Print something completely different when the LP is infeasible in MathProg - ampl

I’m using MathProg (a language specific to the GLPK library, resembling a subset of AMPL) to find topological ranking of vertices of a graph. It’s an assignment for my linear programming class. It’s an introductory exercise to make sure we can formulate a simple linear program and solve it using GLPK.
I’ve written a Perl script that generates the linear program in MathProg for a given graph. It prints values of the variables (ranks of vertices) via printf. If it’s feasible, that’s exactly what I want; otherwise it prints all zeros, but I want to print just Infeasible, has cycles or loops..
I managed to do it in a hacky way (see below). How to do it more elegantly, without repeating the condition for feasibility? Is there a way to detect infeasibility that does not depend on the problem being solved?
param Vsize := 3;
set V "Vertices" := (0..Vsize-1);
set E "Edges" within V cross V := {(0, 1), (1, 2), (2, 0)};
var v{i in V} >= 0;
minimize rank_total: sum{i in V} v[i];
edge{(i, j) in E}: v[j] - v[i] >= 1;
solve;
printf "#OUTPUT:\n";
printf (if ((exists{i in V} v[i] >= 1) or card(E) = 0) then "" else "Infeasible, has cycles or loops.\n");
printf{i in V} (if ((exists{j in V} v[j] >= 1) or card(E) = 0) then "v_%d: %d\n" else ""), i, v[i];
printf "#OUTPUT END\n";
end;
I tried to declare param Feasible binary := (exists{i in V} v[i] >= 1) or card(E) = 0; but GLPK refused it with Model processing error. When I declared it before solve, it said operand preceding >= has invalid type, when after, it said expression following := has invalid type. I was seeking something like a variable in common programming languages.

In AMPL you can check the built-in parameter solve_result to see if the problem is infeasible:
if solve_result = 'infeasible' then
print 'Infeasible, has cycles or loops.';
However, I'm not sure if GLPK supports this parameter in which case you might need to check for feasibility manually.
As for the error, since exists is a logical expression you can't use it as a numeric one. The fix is to simply put logical expression in if:
param Feasible binary :=
if (exists{i in V} v[i].val >= 1) or card(E) = 0 then 1;

Related

how to write "then" as IP constraint in Julia

Hello fellows, i am learning Julia and integer programing but i am stuck at one point
How to model "then" in julia-jump for integer programing leanring.
Stuck here here
#Define the variables of the model
#variable(mo, x[1:N,1:S], Bin)
#variable(mo, a[1:S]>=0)
#Assignment constraint
#constraint(mo, [i=1:N], sum(x[i,j] for j=1:S) == 1)
##constraint (mo, PLEASE HELP )
In cases like this you usually need to use Big-M constraints
So this will be:
a_ij >= s_i^2 - M*(1-x_ij)
where M is a "big enough" number. This means that if x_ij == 0 the inequality will always be true (and hence kind of turned-off). On the other hand when x_ij == 1 the M-part will be zeroed and the equation will hold.
In JuMP terms the code will look like this:
const M = 10_000
#constraint(mo, [i=1:N, j=1:S], a[i, j] >= s[i]^2 - M*(1 - x[i, j]))
However, if s[i] is an external parameter rather than model variable you could simply use x[i,j] <= a[j]/s[i]^2 proposed by #DanGetz. However when s[i] is #variable you really want to avoid dividing or multiplying variables by each other. So this big M approach is more general across use cases.

Calling a separation algorithm in Julia

I'm trying to solve a model using Julia-JuMP. The following is the outline of the model that I created. Here, z[i,j] is a binary variable and d[i,j] is the cost for which z[i,j]=1.
My constraint creates an infinite number of constraint and hence I need to use a separation algorithm to solve it.
First, I solve the model without any constraint, so the answer to all variables z[i,j] and d[i,j] are zero.
Then, I'm including the separation algorithm (which is given inside the if condition). Even though I'm including if z_value == 0, z_values are not passing to it.
Am I missing something in the format of this model?
m = Model(solver=GurobiSolver())
#variable(m, z[N,N], Bin)
#variable(m, d[N,N]>=0)
#objective(m, Min, sum{ d[i,j]*z[i,j], i in N, j in N} )
z_value = getvalue(z)
d_value = getvalue(d)
if z_value == 0
statement
elseif z_value == 1
statement
end
#constraint(m, sum{z[i,j], i in N, j in N}>=2)
solve(m)
println("Final solution: [ $(getvalue(z)), $(getvalue(d)) ]")
You're multiplying z by d which both are variables, hence your model is non-linear,
Are the costs d[i,j] constant or really a variable of the problem ?
If so you need to use a non-linear solver

Variable indexes outside of defined range in AMPL

Not too familiar with AMPL, but running into some issues with indexes...
Basically, I have some variables defined as such:
var array{i in set};
And I need to do some amount of checking the elements around a given i in some of the constraints:
subject to Constraint{i in set}:
array[i] + array[i-1] + array[i+1] <= 12;
But obviously array[0] or array[card(set) + 1] don't exist. To add a further issue, I'm trying to model a sort of problem in which array[0] or array[card(set) + 1] just shouldn't be factored into our computation at all (e.g. it shouldn't constrain the other variables). Any help appreciated :) Thanks.
In AMPL, you can create or define your own "sets" for valid indices and use them in your constraints.
So, in your case, to avoid invalid indices, you can define a set of permissible indices: param inner_i {2..(N-1)} and loop over those when creating the constraints.
The price we pay is that we have to explicitly take care of the corner cases.
Here's one way to do it: (Note, I don't have AMPL loaded, so the code is untested.)
param N > 0; #number of elements
set ELEM; # Elements
set inner_i {2..(N-1)} > 0; #valid indices
var array {ELEM} >= 0;
subject to LimitSum{i in inner_i}:
array[i-1] + array[i] + array[i+1] <= 12;
#Take care of the boundary conditions explicitly, if needed
subject to LimitSum_start:
array[1] + array[2] <= 12;
#only two elements since array[0] doesn't exist.
subject to LimitSum_last:
array[N-1] + array[N] <= 12;
#only two elements since array[N+1] doesn't exist.
Hope this helps you move forward.
You can use an if-then-else expression to conditionally include some terms:
subject to Constraint{i in set}:
array[i] + (if i != 0 then array[i-1]) + (if i != N then array[i+1]) <= 12;
where N is the last element of the set.

Z3 maximization API: possible bug?

I'm currently playing with the maximization API for Z3 (opt branch), and I've stumbled upon a following bug:
Whenever I give it any unbounded problem, it simply returns me OPT and gives zero in the resulting model (e.g. maximize Real('x') with no constraints on the model).
Python example:
from z3 import *
context = main_ctx()
x = Real('x')
optimize_context = Z3_mk_optimize(context.ctx)
Z3_optimize_assert(context.ctx, optimize_context, (x >= 0).ast)
Z3_optimize_maximize(context.ctx, optimize_context, x.ast)
out = Z3_optimize_check(context.ctx, optimize_context)
print out
And I get the value of out to be 1 (OPT), while it seems like it should be -1.
Thanks for trying out this experimental branch.
Development is still churning quite a bit these days, but most of the features are reasonably stable and you are invited to try them out.
To answer your question. There is a native way to use the optimization features from Z3.
To paraphrase your example, here is what is relevant:
from z3 import *
x = Real('x')
opt = Optimize()
opt.add(x >= 0)
h = opt.maximize(x)
print opt.check()
print opt.upper(h)
print opt.model()
When running it, you will see the following output:
sat
oo
[x = 0]
The first line says that the assertions are satisfiable.
The second line prints the value of the handle "h" under the satisfiabilty call.
The value of the handle holds an expression that meets the maximization/minimization criteria declared by the call to opt.maximize/opt.minimize.
In this case the expression is "oo". It is somewhat of a "hack" because it is going to be up to you to guess that "oo" means infinity. If you interpret this value back to Z3, you will not get infinity.
(I am here restricting the use of Z3 where we don't expose non-standard numbers, there is another part of Z3 that includes non-standard numbers, but that is another story).
Note that the opt.maximize call returns the handle "h",
which is later used to query what was the optimal value.
The last line is some model satisfying the constraints.
When the objective is bounded, the model will be what
you expect, but in this case the objective is unbounded.
There is no finite best value.
Try for example instead:
x = Real('x')
opt = Optimize()
opt.add(x >= 0)
opt.add(x <= 10)
h = opt.maximize(x)
print opt.check()
print opt.upper(h)
print opt.model()
This time you get a model that sets x = 10, and this is also the maximal value.
You could also try:
x = Real('x')
opt = Optimize()
opt.add(x >= 0)
opt.add(x < 10)
h = opt.maximize(x)
print opt.check()
print opt.upper(h)
print opt.model()
The output is now:
sat
10 + -1*epsilon
[x = 9]
epsilon refers to a non-standard number (infinitesimal). You can set it arbitrarily small.
Again the model uses only standard numbers, so it picks some number, in this case 9.

"Out of domain" error in MathProg (GLPK)

I am struggling with a seemingly simple model in MathProg. The model is as follows:
set W;
set V;
param b {W, V} binary;
param p;
var w {j in W} <= 0, >= 1;
minimize obj: 0;
subject to within_radius_of {i in V}:
sum {j in W} b[i,j] * w[j] >= 1;
subject to p_limit:
sum {j in W} w[j] <= p;
end;
When I run it, it gives me the error feasibility.glp:11: b[v1,w1] out of domain. I have no idea what is going wrong. Even more strange to me, if I change the relevant line to b[j,i] it keeps giving the exact same error (not b[w1,v1] as I expected).
I inspected the AMPL Diet Example carefully, and despite me seeing no difference in the relevant part of my model it still doesn't work. What is wrong?
Parameter b is declared as binary so it can only take values 0 or 1. You haven't provided a data file, but the error message suggests that the data for b is out of domain (not 0 or 1), for example:
data;
set W := w1;
set V := v1;
param b := w1 v1 0.5;
AMPL gives a more detailed error message in this case:
error processing param b['w1','v1']:
failed check: param b['w1','v1'] = 0.5
is not binary (0 or 1);
The reason why the order of indices doesn't matter in this case is that the data for b is checked completely before the model is actually instantiated. So it seems that w1 and v1 may be swapped in the data file.