Capacity constraints in ampl - constraints

I am building a model that requires me to factor in the capacity of various vessels and I am not sure how to declare this in ampl.
Currently, I have:
Cap1: forall {i in I, t in T} x[1,i] * people[1,t] <= 500;
where I is the set of routes and T is the set of trips taken by the vessel. x[a,i] is an indicator variable which =1 when vessel a travels route i and people[a,t] is the amount of people taken on vessel a on trip t.
ampl always throws up the following error with respect to this constraint:
logical constraint _slogcon[1] is not an indicator constraint.
How can I fix this?

The syntax in AMPL is different than CPLEX. When you want to declare a "forall" you do this:
subject to constraint{index in set}: content of constraint
So, in your case that would be:
subject to Cap1{i in I, t in T}: x[1,i] * people[1,t] <= 500;
Regards!

Related

How to make Pre and Post conditions for recursive functions in SPARK?

I'm translating an exercise I made in Dafny into SPARK, where one verifies a tail recursive function against a recursive one. The Dafny source (censored, because it might still be used for classes):
function Sum(n:nat):nat
decreases n
{
if n==0 then n else n+Sum(n-1)
}
method ComputeSum(n:nat) returns (s:nat)
ensures s == Sum(n)
{
s := 0;
// ...censored...
}
What I got in SPARK so far:
function Sum (n : in Natural) return Natural
is
begin
if n = 0 then
return n;
else
return n + Sum(n - 1);
end if;
end Sum;
function ComputeSum(n : in Natural) return Natural
with
Post => ComputeSum'Result = Sum(n)
is
s : Natural := 0;
begin
-- ...censored...
return s;
end ComputeSum;
I cannot seem to figure out how to express the decreases n condition (which now that I think about it might be a little odd... but I got graded for it a few years back so who am I to judge, and the question remains how to get it done). As a result I get warnings of possible overflow and/or infinite recursion.
I'm guessing there is a pre or post condition to be added. Tried Pre => n <= 1 which obviously does not overflow, but I still get the warning. Adding Post => Sum'Result <= n**n on top of that makes the warning go away, but that condition gets a "postcondition might fail" warning, which isn't right, but guess the prover can't tell. Also not really the expression I should check against, but I cannot seem to figure what other Post I'm looking for. Possibly something very close to the recursive expression, but none of my attempts work. Must be missing out on some language construct...
So, how could I express the recursive constraints?
Edit 1:
Following links to this SO answer and this SPARK doc section, I tried this:
function Sum (n : in Natural) return Natural
is
(if n = 0 then 0 else n + Sum(n - 1))
with
Pre => (n in 0 .. 2),
Contract_Cases => (n = 0 => Sum'Result = 0,
n >= 1 => Sum'Result = n + Sum(n - 1)),
Subprogram_Variant => (Decreases => n);
However getting these warnings from SPARK:
spark.adb:32:30: medium: overflow check might fail [reason for check: result of addition must fit in a 32-bits machine integer][#0]
spark.adb:36:56: warning: call to "Sum" within its postcondition will lead to infinite recursion
If you want to prove that the result of some tail-recursive summation function equals the result of a given recursive summation function for some value N, then it should, in principle, suffice to only define the recursive function (as an expression function) without any post-condition. You then only need to mention the recursive (expression) function in the post-condition of the tail-recursive function (note that there was no post-condition (ensures) on the recursive function in Dafny either).
However, as one of SPARK's primary goal is to proof the absence of runtime errors, you must have to prove that overflow cannot occur and for this reason, you do need a post-condition on the recursive function. A reasonable choice for such a post-condition is, as #Jeffrey Carter already suggested in the comments, the explicit summation formula for arithmetic progression:
Sum (N) = N * (1 + N) / 2
The choice is actually very attractive as with this formula we can now also functionally validate the recursive function itself against a well-known mathematically explicit expression for computing the sum of a series of natural numbers.
Unfortunately, using this formula as-is will only bring you somewhere half-way. In SPARK (and Ada as well), pre- and post-conditions are optionally executable (see also RM 11.4.2 and section 5.11.1 in the SPARK Reference Guide) and must therefore themselves be free of any runtime errors. Therefore, using the formula as-is will only allow you to prove that no overflow occurs for any positive number up until
max N s.t. N * (1 + N) <= Integer'Last <-> N = 46340
as in the post-condition, the multiplication is not allowed to overflow either (note that Natural'Last = Integer'Last = 2**31 - 1).
To work around this, you'll need to make use of the big integers package that has been introduced in the Ada 202x standard library (see also RM A.5.6; this package is already included in GNAT CE 2021 and GNAT FSF 11.2). Big integers are unbounded and computations with these integers never overflow. Using these integers, one can proof that overflow will not occur for any positive number up until
max N s.t. N * (1 + N) / 2 <= Natural'Last <-> N = 65535 = 2**16 - 1
The usage of these integers in a post-condition is illustrated in the example below.
Some final notes:
The Subprogram_Variant aspect is only needed to prove that a recursive subprogram will eventually terminate. Such a proof of termination must be requested explicitly by adding an annotation to the function (also shown in the example below and as discussed in the SPARK documentation pointed out by #egilhh in the comments). The Subprogram_Variant aspect is, however, not needed for your initial purpose: proving that the result of some tail-recursive summation function equals the result of a given recursive summation function for some value N.
To compile a program that uses functions from the new Ada 202x standard library, use compiler option -gnat2020.
While I use a subtype to constrain the range of permissible values for N, you could also use a precondition. This should not make any difference. However, in SPARK (and Ada as well), it is in general considered to be a best practise to express contraints using (sub)types as much as possible.
Consider counterexamples as possible clues rather than facts. They may or may not make sense. Counterexamples are optionally generated by some solvers and may not make sense. See also the section 7.2.6 in the SPARK user’s guide.
main.adb
with Ada.Numerics.Big_Numbers.Big_Integers;
procedure Main with SPARK_Mode is
package BI renames Ada.Numerics.Big_Numbers.Big_Integers;
use type BI.Valid_Big_Integer;
-- Conversion functions.
function To_Big (Arg : Integer) return BI.Valid_Big_Integer renames BI.To_Big_Integer;
function To_Int (Arg : BI.Valid_Big_Integer) return Integer renames BI.To_Integer;
subtype Domain is Natural range 0 .. 2**16 - 1;
function Sum (N : Domain) return Natural is
(if N = 0 then 0 else N + Sum (N - 1))
with
Post => Sum'Result = To_Int (To_Big (N) * (1 + To_Big (N)) / 2),
Subprogram_Variant => (Decreases => N);
-- Request a proof that Sum will terminate for all possible values of N.
pragma Annotate (GNATprove, Terminating, Sum);
begin
null;
end Main;
output (gnatprove)
$ gnatprove -Pdefault.gpr --output=oneline --report=all --level=1 --prover=z3
Phase 1 of 2: generation of Global contracts ...
Phase 2 of 2: flow analysis and proof ...
main.adb:13:13: info: subprogram "Sum" will terminate, terminating annotation has been proved
main.adb:14:30: info: overflow check proved
main.adb:14:32: info: subprogram variant proved
main.adb:14:39: info: range check proved
main.adb:16:18: info: postcondition proved
main.adb:16:31: info: range check proved
main.adb:16:53: info: predicate check proved
main.adb:16:69: info: division check proved
main.adb:16:71: info: predicate check proved
Summary logged in [...]/gnatprove.out
ADDENDUM (in response to comment)
So you can add the post condition as a recursive function, but that does not help in proving the absence of overflow; you will still have to provide some upper bound on the function result in order to convince the prover that the expression N + Sum (N - 1) will not cause an overflow.
To check the absence of overflow during the addition, the prover will consider all possible values that Sum might return according to it's specification and see if at least one of those value might cause the addition to overflow. In the absence of an explicit bound in the post condition, Sum might, according to its return type, return any value in the range Natural'Range. That range includes Natural'Last and that value will definitely cause an overflow. Therefore, the prover will report that the addition might overflow. The fact that Sum never returns that value given its allowable input values is irrelevant here (that's why it reports might). Hence, a more precise upper bound on the return value is required.
If an exact upper bound is not available, then you'll typically fallback onto a more conservative bound like, in this case, N * N (or use saturation math as shown in the Fibonacci example from the SPARK user manual, section 5.2.7, but that approach does change your function which might not be desirable).
Here's an alternative example:
example.ads
package Example with SPARK_Mode is
subtype Domain is Natural range 0 .. 2**15;
function Sum (N : Domain) return Natural
with Post =>
Sum'Result = (if N = 0 then 0 else N + Sum (N - 1)) and
Sum'Result <= N * N; -- conservative upper bound if the closed form
-- solution to the recursive function would
-- not exist.
end Example;
example.adb
package body Example with SPARK_Mode is
function Sum (N : Domain) return Natural is
begin
if N = 0 then
return N;
else
return N + Sum (N - 1);
end if;
end Sum;
end Example;
output (gnatprove)
$ gnatprove -Pdefault.gpr --output=oneline --report=all
Phase 1 of 2: generation of Global contracts ...
Phase 2 of 2: flow analysis and proof ...
example.adb:8:19: info: overflow check proved
example.adb:8:28: info: range check proved
example.ads:7:08: info: postcondition proved
example.ads:7:45: info: overflow check proved
example.ads:7:54: info: range check proved
Summary logged in [...]/gnatprove.out
I landed in something that sometimes works, which I think is enough for closing the title question:
function Sum (n : in Natural) return Natural
is
(if n = 0 then 0 else n + Sum(n - 1))
with
Pre => (n in 0 .. 10), -- works with --prover=z3, not Default (CVC4)
-- Pre => (n in 0 .. 100), -- not working - "overflow check might fail, e.g. when n = 2"
Subprogram_Variant => (Decreases => n),
Post => ((n = 0 and then Sum'Result = 0)
or (n > 0 and then Sum'Result = n + Sum(n - 1)));
-- Contract_Cases => (n = 0 => Sum'Result = 0,
-- n > 0 => Sum'Result = n + Sum(n - 1)); -- warning: call to "Sum" within its postcondition will lead to infinite recursion
-- Contract_Cases => (n = 0 => Sum'Result = 0,
-- n > 0 => n + Sum(n - 1) = Sum'Result); -- works
-- Contract_Cases => (n = 0 => Sum'Result = 0,
-- n > 0 => Sum'Result = n * (n + 1) / 2); -- works and gives good overflow counterexamples for high n, but isn't really recursive
Command line invocation in GNAT Studio (Ctrl+Alt+F), --counterproof=on and --prover=z3 my additions to it:
gnatprove -P%PP -j0 %X --output=oneline --ide-progress-bar --level=0 -u %fp --counterexamples=on --prover=z3
Takeaways:
Subprogram_Variant => (Decreases => n) is required to tell the prover n decreases for each recursive invocation, just like the Dafny version.
Works inconsistently for similar contracts, see commented Contract_Cases.
Default prover (CVC4) fails, using Z3 succeeds.
Counterproof on fail makes no sense.
n = 2 presented as counterproof for range 0 .. 100, but not for 0 .. 10.
Possibly related to this mention in the SPARK user guide: However, note that since the counterexample is always generated only using CVC4 prover, it can just explain why this prover cannot prove the property.
Cleaning between changing options required, e.g. --prover.

Why is Ada not trapping this specified range check?

I am going through the learn.adacore.com tutorial and have hit upon a problem that I am unsure of.
Specifically I understand that Ada is designed to trap attempts to overflow a variable with a specified range definition.
In the case below, the first attempt to do this causes a compiler 'range check failure' which is expected. However the following line doesn't trap it and I am not sure why:
with Ada.Text_IO; use Ada.Text_IO;
procedure Custom_Floating_Types is
type T_Norm is new float range -1.0 .. 1.0;
D : T_Norm := 1.0;
begin
Put_Line("The value of D =" & T_Norm'Image(D));
-- D := D + 1.0; -- This causes a range check failure at run time = completely expected.
Put_Line("The value of D =" & T_Norm'Image(D + 1.0)); -- This doesn't?
end Custom_Floating_Types;
You have a couple of pretty good answers, but I'm going to add another because it's clear that you expect the expression D + 1.0 to raise an exception, and the answers you have don't explain why it doesn't.
A type declaration like
type T_Norm is new float range -1.0 .. 1.0;
is roughly equivalent to
type T_Norm'Base is new Float;
subtype T_Norm is T_Norm'Base range -1.0 .. 1.0;
The type (called the "base type") isn't given a name, though it can often be referenced with the 'Base attribute. The name that is given is to a subtype, called the "first-named subtype".
This distinction is important and is often not given enough attention. As explained by egilhh, T_Norm'Image is defined in terms of T_Norm'Base. This is also true of the arithmetic operators. For example, "+" is defined as
function "+" (Left : in T_Norm'Base; Right : in T_Norm'Base) return T_Norm'Base;
2.0 is clearly in the range of T_Norm'Base, so evaluating D + 1.0 doesn't violate any constraints, nor does passing it to T_Norm'Image. However, when you try to assign the resulting value to D, which has subtype T_Norm, a check is performed that the value is in the range of the subtype, and an exception is raised because the check fails.
This distinction is used in other places to make the language work reasonably. For example, a constrained array type
type A is array (1 .. 10) of C;
is roughly equivalent to
type A'Base is array (Integer range <>) of C;
subtype A is A'Base (1 .. 10);
If you do
V : A;
... V (2 .. 4)
you might expect problems because the slice doesn't have the bounds of A. But it works because the slice doesn't have subtype A but rather the anonymous subtype A'Base (2 ..4).
The definition of 'Image says:
For every scalar subtype S:
S'Image denotes a function with the following specification:
function S'Image(Arg : S'Base)
return String
As you can see, it takes a parameter of the base (unconstrained) type
T_Norm'Image(D + 1.0) neither assigns nor reads an out-of-range value. It asks for the 'Image attribute (string representation) of (D + 1.0), which is the same as asking for (1.0 + 1.0).
I can see two ways the confusion might arise. First, the name "attribute" could be misinterpreted to suggest that 'Image involves something intrinsic to D. It doesn't. The 'Image attribute is just a function, so D is just part of the expression that defines the value of the parameter (in your example = 2.0).
Second, the 'Image attribute comes from Float. Thus, any Float can be its parameter.
You can create a function that accepts only parameters of T_Norm'Range and make that function an attribute of T_Norm. See Ada Reference Manual 4.10.
Because you don't store a value greater than range in D.

OPL constraint index

I am programming an OPL model and do not know how to express the following constraint:
q_t-D_t_T*v_t <=0
Where D_t_T is the sum of all q_t in the set of t to T.
-- Update --
Yes, just q[t] and v[t] are variables. Is the suggestion also working if I defined the range of t as follows:
//parameters
int T=...;
range Perioden=1..T;
My constraint looks then:
forall(t in Perioden)
constraint1:
q[t]- (sum(i in t..T) q[i])*v[t]<=0;
Maybe one more basic question: How do I express the [t-1] in the following expression:
forall(t in Perioden)
constraint2:
y[t-1]+q[t]-y[t]==q[t];
Yes, just q[t] and v[t] are variables.
Is your suggestion also working if I defined the range of t as follows:
//parameters
int T=...;
range Perioden=1..T;
My constraint looks then:
forall(t in Perioden)
constraint1:
q[t]- (sum(i in t..T) q[i])*v[t]<=0;
Maybe one more basic question:
How do I express the [t-1] in the following expression:
forall(t in Perioden)
constraint2:
y[t-1]+q[t]-y[t]==q[t];

Sum of ranks in a binary tree - is there a better way

Maybe this question does not belong as this is not a programming question per se, and i do apologize if this is the case.
I just had an exam in abstract data structures, and there was this question:
the rank of a tree node is defined like this: if you are the root of the tree, your rank is 0. Otherwise, your rank is the rank of your parents + 1.
Design an algorithm that calculates the sum of the ranks of all nodes in a binary tree. What is the runtime of your algorithm?
My answer I believe solves this question, my psuedo-code is as such:
int sum_of_tree_ranks(tree node x)
{
if x is a leaf return rank(x)
else, return sum_of_tree_ranks(x->left_child)+sum_of_tree_ranks(x->right_child)+rank(x)
}
where the function rank is
int rank(tree node x)
{
if x->parent=null return 0
else return 1+rank(x->parent)
}
it's very simple, the sum of ranks of a tree is the sum of the left subtree+sum of the right subtree + rank of the root.
The runtime of this algorithm I believe is n^2. i believe this is the case because we were not given the binary tree is balanced. it could be that there are n numbers in the tree but also n different "levels", as in, the tree looks like a linked list rather than a tree. so to calculate the rank of a leaf, potentially we go n steps up. the father of the leaf will be n-1 steps up etc...so thats n+(n-1)+(n-2)+...+1+0=O(n^2)
My question is, is this correct? does my algorithm solve the problem? is my analysis of the runtime correct? and most importantly, is there a better solution to solve this, that does not run in n^2?
Your algorithm works. your analysis is correct. The problem can be solved in O(n) time: (take care of leaves by yourself)
int rank(tree node x, int r)
{
if x is a leaf return r
else
return rank(x->left_child, r + 1)+ ranks(x->right_child, r + 1) + r
}
rank(tree->root, 0)
You're right but there is an O(n) solution providing you can use a more "complex" data structure.
Let each node hold its rank and update the ranks whenever you add/remove, that way you can use the O(1) statement:
return 1 + node->left.rank + node->right.rank;
and do this for each node on the tree to achieve O(n).
A thumb rule for reducing Complexity time is: if you can complex the data structure and add features to adapt it to your problem, you can reduce Complexity time to O(n) most of the times.
It can be solved in O(n) time where n is number of Nodes in Binary tree .
It's nothing but sum of height of all nodes where height of root node is zero .
As
Algorithm:
Input binary tree with left and right child
sum=0;
output sum
PrintSumOfrank(root,sum):
if(root==NULL) return 0;
return PrintSumOfrank(root->lchild,sum+1)+PrintSumOfRank(root->Rchild,sum+1)+sum;
Edit:
This can be also solved using queue or level order of traversal tree.
Algorithm using Queue:
int sum=0;
int currentHeight=0;
Node *T;
Node *t1;
if(T!=NULL)
enque(T);
while(Q is not empty) begin
currentHeight:currentHeight+1 ;
for each nodes in Q do
t1 = deque();
if(t1->lchild!=NULL)begin
enque(t1->lchild);sum = sum+currentHeight;
end if
if(t1->rchild!=NULL)begin
enque(t1->rchild);sum = sum+currentHeight;
end if
end for
end while
print sum ;

AMN and math logic notation

I'm not sure this is appropriate for stackoverflow, but I don't know where else to ask. I'm studying the B-Method for proving consistence in requirement specifications, and I have an issue with the logic math notation when specifying the pre conditions of the operations.
Simplifying the original problem, I have a variable which is a subset flights of the cartesian product between FLIGHT_NO x TIME x TIME, where for each member (no,td,ta), no means the number of the flight, td the time of departure and ta the tme of arrival. How can I get, using math logic notation, the element of flights that has the biggest value of td?
Do you want to get such an element, or to test that an element you have satisfies this property? I am asking because the second seems a sensible precondition to an operation. I don't know the B-Method specifically; I've looked at some documents, but can't find a quick reference, so this may be wrong in some details.
The second should look like this (prj2 is used for the second projection):
HasGreatestTd(flight) = flight \in flights \and \forall flight' (flight' \in flights => prj2(flight) >= prj2(flight'))
Then the first is:
flightWithGreatestTd = choice({flight | HasGreatestTd(flight)})
Forgive my ignorance, I'm not familiar with the B-Method. But couldn't you use the uniqueness quantifier? It'd look something like:
there exists a time td such that for all times td', td > td'
and
for all td, td', td'', if td > td'' and td' > td'' then td == td'
This, of course, assumes that there is exactly one element in the set. I can't really tell if the B-Method allows for the full power of first order logic but I assume you could come close to this.
It is possible to define functions in B. Functions have constant values and are to be listed in the ABSTRACT_CONSTANTS clause, and defined in the PROPERTIES clause. I try to explain how you can use this construct to solve your problem.
Follows a small excerpt where
a shortcut for the cartesian product giving flight information is introduced;
DEFINITIONS
FLIGHT_INFO == FLIGHT_NO * TIME * TIME
four constants are declared, the first three are "accessors", and the last maps a non-empty set of flight informations to the flight information with the largest departure time.
CONSTANTS
flight_no, flight_departure, flight_arrival, last_flight
Then these constants are typed and defined as total functions. Note that the last function must take as input a non-empty set. Here I used to different approaches to specify these functions. One is definitional (with an equality), and the other is axiomatic.
PROPERTIES
// typing
flight_no: FLIGHT_INFO --> FLIGHT_NO &
flight_departure: FLIGHT_INFO --> TIME &
flight_arrival: FLIGHT_INFO --> TIME &
last_flight : POW1(FLIGHT_INFO) --> FLIGHT_INFO &
// value
flight_no = %(no, dt, at).(no |-> dt |-> at : FLIGHT_INFO | no) &
flight_departure = %(no, dt, at).(no |-> dt |-> at : FLIGHT_INFO | dt) &
flight_arrival = %(no, dt, at).(no |-> dt |-> at : FLIGHT_INFO | at) &
!fs.(fs : POW1(FLIGHT_INFO) =>
last_flight(fs) : fs &
!(fi).(fi : FLIGHT_INFO & fi : fs =>
flight_departure(fi) <= flight_departure(last_flight(fs)))

Resources