How to sum for all in Julia/JuMP v 1.10 - julia

I saw an outdated answer in the following thread (How to do "for all" in sum notation in Julia/JuMP)
which is 3 years old unfortunately, but it's exactly what I want. However the code fails due to a number of syntax errors as the sum() function has changed these past few years.
For my code, I found that the sum() function only works for one indexing variable i, but if I include another variable j, the function stops working. I'm also using jupyter notebook if that makes any difference. Any ideas?
Using JuMP
ZS = Model(with_optimizer(Gurobi.Optimizer))
P = [[10 -20];
[30 -40]]
#variable(ZS, x[1,1:2])
#variable(ZS, y[1:2,1])
#objective(ZS, Max, sum(x[i]*P[i,j]*y[j] for i=1:2 for j=1:2))
#constraint(ZS, con1, x[1] + x[2] <= 1)
#constraint(ZS, con2, y[1] + y[2] <= 1)
optimize!(ZS)
For this example of code, I received a "key not found" error

Seems like you need an update of the for loop syntax and to set your solver to be non-convex.
I also recommend using anonymous labeling for vars, exp etc so that you can change them as required.
using JuMP
using Gurobi
ZS = Model(Gurobi.Optimizer)
set_optimizer_attribute(ZS, "NonConvex", 2)
P = [[10 -20];
[30 -40]]
xs = #variable(ZS, x[1:2])
ys = #variable(ZS, y[1:2])
my_obj = #objective(ZS, Max, sum(x[i]*P[i,j]*y[j] for i in 1:2, j in 1:2))
con1 = #constraint(ZS, x[1] + x[2] <= 1)
con2 = #constraint(ZS, , y[1] + y[2] <= 1)
optimize!(ZS)
Runtime is pretty dang long though...

Change definitions of variables to be one-dimensional like this:
#variable(ZS, x[1:2])
#variable(ZS, y[1:2])
and all should work as expected.
Alternatively leave x and y two dimensional and redefine your objective and constraints like this:
#objective(ZS, Max, sum(x[1,i]*P[i,j]*y[j,1] for i=1:2 for j=1:2))
#constraint(ZS, con1, x[1,1] + x[1,2] <= 1)
#constraint(ZS, con2, y[1,1] + y[2,1] <= 1)
As a side note you can define P more simply like this:
julia> P = [10 -20
30 -40]
2×2 Array{Int64,2}:
10 -20
30 -40

Related

Julia JuMP feasibility slack of constraints

In Julia, by using JuMP am setting up a simple optimization problem (MWE, the real problem is much bigger).
model = Model()
set_optimizer(model, MosekTools.Optimizer)
#variable(model, 0 <= x[1:2])
#constraint(model, sum(x) <= 2)
#constraint(model, 1 <= sum(x))
#objective(model, Min, sum(x))
print(model)
Which gives this model:
Min x[1] + x[2]
Subject to
x[1] + x[2] ≤ 2.0
-x[1] - x[2] ≤ -1.0
x[1] ≥ 0.0
x[2] ≥ 0.0
I optimize this model via optimize!(model).
Now, obviously, the constraint x[1] + x[2] <= 2 is redundant and it has a feasibility slack of "3". My goal is to determine all the constraints that have slacks larger than 0 and display the slacks. Then I will delete those from the model.
To this end, I iterate over the constraints which are not variable bounds and print their values.
for (F, S) in list_of_constraint_types(model)
# Iterate over constraint types
if F!= JuMP.VariableRef #for constraints that
for ci in all_constraints(model, F, S)
println(value(ci))
end
end
end
However, because I print the value of the constraints, I get the left-hand sides:
1.0
-1.0
I want to instead see the slacks as
0
3
How may I do this? Note that I am not necessarily interested in linear programs, so things like shadow_value is not useful for me.
Based on the accepted answer, I am adding a MWE that solves this problem.
model = Model()
set_optimizer(model, MosekTools.Optimizer)
#variable(model, 0 <= x[1:2])
#constraint(model, sum(x) <= 2)
#constraint(model, 1 <= sum(x))
#constraint(model, 0.9 <= sum(x))
#objective(model, Min, sum(x))
print(model)
optimize!(model)
constraints_to_delete = vec([])
for (F, S) in list_of_constraint_types(model)
if F!= JuMP.VariableRef
for ci in all_constraints(model, F, S)
slack = normalized_rhs(ci) - value(ci)
if slack > 10^-5
push!(constraints_to_delete, ci)
println(slack)
#delete(model, ci)
end
end
end
end
for c in constraints_to_delete
delete(model, c)
end
print(model)
Read this (hot off the press) tutorial: https://jump.dev/JuMP.jl/dev/tutorials/linear/lp_sensitivity/.
Although focused on LPs, it shows how to compute slacks etc using normalized_rhs(ci) - value(ci).

How can I change the code so it can solve the model?

It is not possible for Julia to solve it when I use a[i, j] = 1. how can i get julia to solve this problem?
using JuMP
using GLPK
u = [1 2 3 ; 1 2 3 ; 1 2 3]
m = Model(GLPK.Optimizer)
#variable(m, a[1:3,1:3], Bin)
#objective(m, Max, sum(u[i,j]*a[i,j] for i=1:3, j=1:3))
#constraint(m, [a[i,j]=1], sum(a[i:j][i:j]) == 1)
solution = optimize!(m)
opt_value = value.(a)
in the line
#constraint(m, [a[i,j]=1], sum(a[i:j][i:j]) == 1)
1) You're trying to set a variable, not to test equality, instead use
a[i,j] == 1
2) i and j are undefined. Without a minimal example to run, I would say according to the previous line of your code, I would say something like
sum(<what-to-sum-here> for i=1:3, j=1:3)
Or loop on the list of index you want to use if not the proper one.

JuMPDict change of dimension

I am using Julia 0.6.2 and JuMP 0.18.5 (I can't use a more recent version since I need to use an old package).
Creating JuMP variables with conditions on the index lead to a JuMPDict instead of an Array.
For example:
m = Model(solver = CplexSolver())
# type of x: JuMP.JuMPDict{JuMP.Variable,2}
#variable(m, x[i in 1:3, j in 1:3; i < j] >= 0)
# type of y: JuMP.JuMPDict{JuMP.Variable,3}
#variable(m, y[i in 1:3, j in 1:3, k in 1:3; i < j] >= 0)
I would like to apply a function f to x and to y[:, :, k] for all k in 1:3. However, I don't know how to define such a generic function.
I tried to set the argument type of f to JuMP.JuMPDict{JuMP.Variable,2}:
function f(input::JuMP.JuMPDict{JuMP.Variable,2})
...
end
I can use the function on x but not on y:
f(x) # Works
for k in 1:3
f(y[:, :, k]) # does not work as y is not an array
end
My last idea was to convert y into several JuMP.JuMPDict{JuMP.Variable,2}:
function convertTo2D(dict3D::JuMP.JuMPDict{JuMP.Variable,3}, k::Int)
dict2D = JuMP.JuMPDict{JuMP.Variable,2}() # This line returns "ERROR: KeyError: key :model not found"
for (key, value) in keys(dict3D)
if key[3] == k
dict2D[(key[1], key[2])] = value # Not sure if it will work
end
end
return dict2D
end
If this was working I could use:
for k in 1:3
f(convertTd2D(y, k))
end
Do you know how I could fix convertTo2D or do what I want another way?
Anonymous variables solved my problem. Thanks to them I can successively create the variables of y in a for loop. Variable y is now an array of "2D dictionaries" rather than a "3D dictionaries":
y = Array{JuMP.JuMPDict{JuMP.Variable,2}, 1}([])
for k in 1:3
yk = #variable(m, [i in 1:3, j in 1:3; i < j] >= 0)
f(yk)
push!(y, yk)
end

"Syntax error" while writing OCaml function?

I am writing a function in OCaml to raise x to the power of y.
My code is:
#let rec pow x y =
if y == 0 then 1 else
if (y mod 2 = 0) then pow x y/2 * pow x y/2 else
x * pow x y/2 * pow x y/2;;
When I try to execute it, I get an error for syntax in line one, but it doesn't tell me what it is.
When you wrote the code, did you type the #? The # is just a character that the OCaml REPL outputs to prompt for input; it is not part of the code. You should not type it.
Here are some other errors that you should fix:
== is physical equality in OCaml. = is structural equality. Although both work the same for unboxed types (such as int), it's better practice to do y = 0. Note that you use =, the recommended equality, in the expression y mod 2 = 0.
You need parentheses around y/2. pow x y/2 parses as (pow x y) / 2, but you want pow x (y / 2).

Prolog:: f(x) recursion

I'm a beginner to Prolog and have two requirements:
f(1) = 1
f(x) = 5x + x^2 + f(x - 1)
rules:
f(1,1).
f(X,Y) :-
Y is 5 * X + X * X + f(X-1,Y).
query:
f(4,X).
Output:
ERROR: is/2: Arguments are not sufficiently instantiated
How can I add value of f(X-1)?
This can be easily solved by using auxiliary variables.
For example, consider:
f(1, 1).
f(X, Y) :-
Y #= 5*X + X^2 + T1,
T2 #= X - 1,
f(T2, T1).
This is a straight-forward translation of the rules you give, using auxiliary variables T1 and T2 which stand for the partial expressions f(X-1) and X-1, respectively. As #BallpointBen correctly notes, it is not sufficient to use the terms themselves, because these terms are different from their arithmetic evaluation. In particular, -(2,1) is not the integer 1, but 2 - 1 #= 1 does hold!
Depending on your Prolog system, you may ned to currently still import a library to use the predicate (#=)/2, which expresses equality of integer expressesions.
Your example query now already yields a solution:
?- f(4, X).
X = 75 .
Note that the predicate does not terminate universally in this case:
?- f(4, X), false.
nontermination
We can easily make it so with an additional constraint:
f(1, 1).
f(X, Y) :-
X #> 1,
Y #= 5*X + X^2 + T1,
T2 #= X - 1,
f(T2, T1).
Now we have:
?- f(4, X).
X = 75 ;
false.
Note that we can use this as a true relation, also in the most general case:
?- f(X, Y).
X = Y, Y = 1 ;
X = 2,
Y = 15 ;
X = 3,
Y = 39 ;
X = 4,
Y = 75 ;
etc.
Versions based on lower-level arithmetic typically only cover a very limited subset of instances of such queries. I therefore recommend that you use (#=)/2 instead of (is)/2. Especially for beginners, using (is)/2 is too hard to understand. Take the many related questions filed under instantiation-error as evidence, and see clpfd for declarative solutions.
The issue is that you are trying to evaluate f(X-1,Y) as if it were a number, but of course it is a predicate that may be true or false. After some tinkering, I found this solution:
f(1,1).
f(X,Y) :- X > 0, Z is X-1, f(Z,N), Y is 5*X + X*X + N.
The trick is to let it find its way down to f(1,N) first, without evaluating anything; then let the results bubble back up by satisfying Y is 5*X + X*X + N. In Prolog, order matters for its search. It needs to satisfy f(Z,N) in order to have a value of N for the statement Y is 5*X + X*X + N.
Also, note the condition X > 0 to avoid infinite recursion.

Resources