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

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.

Related

How to define a JuMP expression conditional on index value

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

Modify object whose name is based on contents of an array

I have a two-element vector whose elements can only be 0 or 1. For the sake of this example, suppose x = [0, 1]. Suppose also there are four objects y00, y01, y10, y11. My goal is to update the corresponding y (y01 in this example) according to the current value of x.
I am aware I can do this using a series of if statements:
if x == [0, 0]
y00 += 1
elseif x == [0, 1]
y01 += 1
elseif x == [1, 0]
y10 += 1
elseif x == [1, 1]
y11 += 1
end
However, I understand this can be done more succinctly using Julia's metaprogramming, although I'm unfamiliar with its usage and can't figure out how.
I want to be able to express something like y{x[1]}{x[2]} += 1 (which is obviously wrong); basically, be able to refer and modify the correct y according to the current value of x.
So far, I've been able to call the actual value of the correct y (but I can't summon the y object itself) with something like
eval(Symbol(string("y", x[1], x[2])))
I'm sorry if I did not use the appropriate lingo, but I hope I made myself clear.
There's a much more elegant way using StaticArrays. You can define a common type for your y values, which will behave like a matrix (which I assume the ys represent?), and defines a lot of things for you:
julia> mutable struct Thing2 <: FieldMatrix{2, 2, Float64}
y00::Float64
y01::Float64
y10::Float64
y11::Float64
end
julia> M = rand(Thing2)
2×2 Thing2 with indices SOneTo(2)×SOneTo(2):
0.695919 0.624941
0.404213 0.0317816
julia> M.y00 += 1
1.6959194941562996
julia> M[1, 2] += 1
1.6249412302897646
julia> M * [2, 3]
2-element SArray{Tuple{2},Float64,1,2} with indices SOneTo(2):
10.266662679181893
0.9037708026795666
(Side note: Julia indices begin at 1, so it might be more idiomatic to use one-based indices for y as well. Alternatively, can create array types with custom indexing, but that's more work, again.)
How about using x as linear indices into an array Y?
x = reshape(1:4, 2, 2)
Y = zeros(4);
Y[ x[1,2] ] += 1
Any time you find yourself naming variables with sequential numbers it's a HUGE RED FLAG that you should just use an array instead. No need to make it so complicated with a custom static array or linear indexing — you can just make y a plain old 2x2 array. The straight-forward transformation is:
y = zeros(2,2)
if x == [0, 0]
y[1,1] += 1
elseif x == [0, 1]
y[1,2] += 1
elseif x == [1, 0]
y[2,1] += 1
elseif x == [1, 1]
y[2,2] += 1
end
Now you can start seeing a pattern here and simplify this by using x as an index directly into y:
y[(x .+ 1)...] += 1
I'm doing two things there: I'm adding one to all the elements of x and then I'm splatting those elements into the indexing expression so they're treated as a two-dimensional lookup. From here, you could make this more Julian by just using one-based indices from the get-go and potentially making x a Tuple or CartesianIndex for improved performance.

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