How to define a JuMP expression conditional on index value - julia

I am trying to define a #NLexpression in JuMP that has different specifications at different indices. In the below example, I want the expression y[j,k] to be defined as 1/(x[j] - x[k]) when j != k and take some other value when j == k. I can simulate this behavior by defining an auxiliary variable z and adding constraints conditional on index values. Is there a similar way to define expression conditional on index values?
using JuMP, Ipopt
model = JuMP.Model(with_optimizer(Ipopt.Optimizer))
#variable(model, 0 <= x[1:2])
#NLexpression(model, y[j=1:2,k=1:2], 1/(x[j] - x[k])) # <- problematic line
#variable(model, z[1:2,1:2])
for j=1:2, k=1:2
if j == k
#constraint(model, z[j,k] == 1)
else
#NLconstraint(model, z[j,k] == 1/(p[j] - p[k]))
end
end
display(model)

You're not obligated to use JuMP's macros to create containers for expressions. You should be able to conditionally create the expressions as follows:
model = JuMP.Model()
#variable(model, 0 <= x[1:2])
y = Dict() # Or Array, if you prefer.
for j=1:2, k=1:2
if j == k
y[j,k] = 1
else
y[j,k] = #NLexpression(model, 1/(p[j] - p[k]))
end
end

Related

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

Minimize the maximum variable

I have a Mixed Integer Programming problem. The objective function is a minimization of the maximum variable value in the a vector. The variable is has an upper bound of 5. The problem is like this:
m = Model(solver = GLPKSolverMIP())
#objective(m, Min, max(x[i] for i=1:12))
#variable(m, 0 <= x[i] <= 5, Int)
#constraint(m, sum(x[i] for i=1:12) == 12)
status = solve(m)
The max variable is not part of the julia JuMP syntax. So I modified the problem to
t=1
while t<=5 && (status == :NotSolved || status == :Infeasible)
m = Model(solver = GLPKSolverMIP())
i = 1:12
#objective(m, Min, max(x[i] for i=1:12))
#variable(m, 0 <= x[i] <= t, Int)
#constraint(m, sum(x[i] for i=1:12) == 12)
status = solve(m)
t += 1
end
This solution does the job by solving the problem iterative for starting with a upper bound for the variable at 1 and then increase by one until the solutoin is feasible. Is this really the best way to do this?
The question wants to minimize a maximum, this maximum can be held in an auxiliary variable and then we will minimize it. To do so, add constraints to force the new variable to actually be an upper bound on x. In code it is:
using GLPKMathProgInterface
using JuMP
m = Model(solver = GLPKSolverMIP())
#variable(m, 0 <= x[i=1:3] <= 5, Int) # define variables
#variable(m, 0 <= t <= 12) # define auxiliary variable
#constraint(m, t .>= x) # constrain t to be the max
#constraint(m, sum(x[i] for i=1:3) == 12) # the meat of the constraints
#objective(m, Min, t) # we wish to minimize the max
status = solve(m)
Now we can inspect the solution:
julia> getValue(t)
4.0
julia> getValue(x)
3-element Array{Float64,1}:
4.0
4.0
4.0
The actual problem the poster wanted to solve is probably more complex that this, but it can be solved by a variation on this framework.

How to define JuMP variables using for loop in Julia?

I am new to Julia, and I am trying to define an optimization problem with JuMP. I have a lot of variables (x1,x2,x3....) that I am trying to define using a for loop. I want to have the code:
#variable(m, x1>=0)
#variable(m, x2>=0) ...
However I wanted to use a for loop so I did not have to define every variable manually.
Here is what I have so far:
m = Model()
for i = 1:2
#variable(m,string('x',i)>=0)
end
I know the string('x',i) part is not right but I am not sure how to do this using Julia.
It looks like you want an array of x variables.
From the JuMP docs, you can make an array by using array syntax in your definition.
#variable(m, x[1:2] >= 0)
#variable(m, y[1:M,1:N] >= 0)
You can add indices to your variables using #variable. The following are all valid in JuMP:
m = Model()
#variable(m, x[1:2] >= 0)
#variable(m, boringvariable[1:9,1:9,1:9])
#variable(m, 0 <= pixel_intensity[1:255,1:255] <= 1)
#variable(m, bit_pattern[0:8:63], Bin)
N = 5, M = 10
#variable(m, trucks_dispatched[i=1:N,j=1:M] >= 0, Int)
items = [:sock,:sandal,:boot]
max_stock = [:sock => 10, :sandal => 13, :boot => 5]
#variable(m, 0 <= stock_levels[item=items] <= max_stock[item])
I'll just add that a 'for' loop in your constraints might look like this:
#constraint(m, [i in 1:2], x[i]>=0)
where [i in 1:2] is your for loop.
Adding to Iain's comment above, better to use x as a vector the to be defining individual variables for it - that way you only have the one decision variable.
This is particularly useful when you want to increase the dimensionality of it:
ie x[i,j]

How to find the index of a set in Julia/JuMP?

I am trying to create a linear optimization model. I have a set that looks like this:
si=[1,51,39,400909,1244]
sj=[31,47,5]
The numbers in this set represent codes. I am trying to loop through the set to add a constraint to my model, but I do not want to loop through the sets using their values, I want to loop through the sets based on their indices.
Here is the code I have now:
si=[1,51,39,400909,1244]
sj=[31,47,5]
c= [3 5 2;
4 3 5;
4 5 3;
5 4 3;
3 5 4]
b= [80;
75;
80;
120;
60]
# x_ij >= 0 ∀ i = 1,...,5, j = 1,...,3
#defVar(m, x[i in si,j in sj] >= 0)
#setObjective(m,Min,sum{c[i,j]*x[i,j],i in si, j in sj})
# ∀j = 1,...,3
for j in sj
#addConstraint(m, sum{x[i,j],i in si} <= 480)
end
for i in si
#addConstraint(m, sum{x[i,j],j in sj} >= b[i])
end
I keep getting an error because the numbers in the sets are too big. Does anyone know how to loop through the indices instead? Or does anyone have another way to do this?
I am also having trouble printing my solution. Here is my code:
for i in n
for j in p
println("x",i,",",j,"= ", getValue(x[i,j]))
end
end (incorporating Iain Dunning's answer from below)
However the output only reads
Objective value: 1165.0
x5,3= 0.0
Do you know how to fix the output so I can read the values of my variables?
The code you have posted doesn't work because you are trying to index c by, e.g. 400909,47. Try this:
n = length(si)
p = length(sj)
#variable(m, x[i=1:n,j=1:p] >= 0)
#objective(m,Min,sum{c[i,j]*x[i,j],i=1:n,j=1:p})
for j in 1:p
#constraint(m, sum{x[i,j],i=1:n} <= 480)
end
for i in 1:n
#constraint(m, sum{x[i,j],j=1:p} >= b[i])
end

Resources