quadratic equality constraint: Julia+Jump+Gurobi - julia
i'm a newbie to julia and struggling how to handle quadratic equality constraints when using gurobi as the main solver. Can u may take a quick look at the following listing? I alread know that such structures are impossible to solve by using gurobi, but how do I can bypass this difficulty and thus enforce the condition to my model?
[listing][1]
Relevant and defined Variables causing problems:
x: binary decision variable
s: s>=0
I would be glad about any help!
Andre
eukl_distance = [0 6 5 7 9 8; 6 0 6 3 14 9; 5 6 0 5 9 4; 7 3 5 0 13 8;
9 14 9 13 0 7; 8 9 4 8 7 0]
# Nachfrage an Knoten i
d = [0,2,1,1,3,1]
no_nodes = 6
# Zeitfenster
time_windows = [Vector{Float64}(2) for i=1:no_nodes]
time_windows[1] = [0,10]
time_windows[2] = [1,4]
time_windows[3] = [2,5]
time_windows[4] = [4,7]
time_windows[5] = [3,6]
time_windows[6] = [5,8]
# Fahrtzeit von i nach j und Servicezeit an Knoten i
t = [Array{Float64}(no_nodes) for i=1:no_nodes]
t[1] = [0,2,1.5,2.5,4,3.5]
t[2] = [2,0,2,1,6,4]
t[3] = [1.5,2,0,1.5,4,1.25]
t[4] = [2.5,1,1.5,0,5.75,3.5]
t[5] = [4,6,4,5.75,0,2.5]
t[6] = [3.5,4,1.25,3.5,2.5,0]
# Anzahl Fahrzeuge
k = 2
# Kapazität Fahrzeuge
C = 5
# Strafkostenfaktor
z = 2
M = 100000000000000000
using JuMP, Gurobi, LightGraphs, Distances
m = Model(solver = GurobiSolver())
#variable(m, x[i=1:no_nodes,j=1:no_nodes,kk=1:k], Bin)
#variable(m, y[i=1:no_nodes, kk=1:k], Bin)
#variable(m, 0<=s[i=1:no_nodes,kk=1:k]<=M)
#variable(m, w1[i=1:no_nodes, kk=1:k]>=0)
#variable(m, w2[i=1:no_nodes, kk=1:k]>=0)
# Hilfsvariablen
#variable(m, h1[i=1:no_nodes, j=1:no_nodes, kk=1:k]>=0)
#variable(m, h2[i=1:no_nodes, j=1:no_nodes, kk=1:k]>=0)
# Beachte: Division von z durch no_nodes notwendig,
# da ansonsten w1 und w2 für jedes i über jedes j
# addiert werden. Beispiel: Sei i = 2 und j=1:6
# x[2,1,1]*dist+w1[2,1]*2+w2[2,1]*2+x[2,1,2]*dist+w1[2,2]*2+w2[2,2]*2 +
# x[2,2,1]*dist+w1[2,1]*2+w2[2,1]*2+x[2,2,2]*dist+w1[2,2]*2+w2[2,2]*2 +
# ... x[2,6,1]*dist+w1[2,1]*2+w2[2,1]*2+x[2,6,2]*dist+w1[2,2]*2+w2[2,2]*2
#objective(m, Min, sum(x[i=ii,j=jj,n=kk]*eukl_distance[ii,jj]+w1[i=ii,n=kk]*z/no_nodes+w2[i=ii,n=kk]*z/no_nodes for ii=1:no_nodes, jj=1:no_nodes, kk=1:k))
# erlaube verfrühte sowie verspätete Ankunft
# Abfahrt am Depot zum Zeitpunkt 0
#constraint(m, earlyArrival[ii=1:no_nodes,kk=1:k], time_windows[i=ii][1]-s[i=ii,n=kk]-w1[i=ii,n=kk]<=0)
#constraint(m, lateArrival[ii=1:no_nodes,kk=1:k], time_windows[i=ii][2]-s[i=ii,n=kk]+w2[i=ii,n=kk]>=0)
# Eliminiere Kanten von i zu i
# [i,i]=0
#constraint(m, noSelfConnection[ii=1:no_nodes,kk=1:k], x[i=ii,j=ii,n=kk]==0)
# Jeder Kunde wird von einem Fahrzeug besucht
#constraint(m, oneCustomerVisitation[ii=2:no_nodes], sum(y[i=ii,kk=1:k])==1)
# Genau K Fahrzeuge erreichen das Depot
#constraint(m, sum(y[i=1,kk=1:k])==k)
# Wenn ein Fahrzeug einen Kunden i anfährt,
# muss die Summe aller genutzten ausgehenden und eingehenden Kanten,
# basienrend auf Knoten i, genau 1 entsprechen
#constraint(m, completeRoute1[ii=1:no_nodes, kk=1:k], sum(x[i=ii,j=1:no_nodes,n=kk])-y[i=ii,n=kk]==0)
#constraint(m, completeRoute2[ii=1:no_nodes, kk=1:k], sum(x[j=1:no_nodes,i=ii,n=kk])-y[i=ii,n=kk]==0)
# Kapazitätsbeschränkung
#constraint(m, capacityConstr[kk=1:k], sum(d[i]*y[i,kk] for i in 1:no_nodes)<=C)
# Ankunft am Knoten i entspricht der
# Summe aus Ankunftszeit am Knoten j und Lieferzeit
# von Knoten i zu j
for i=1:no_nodes, j=1:no_nodes, kk=1:k
#constraint(m, h1[i,j,kk]<=M*x[i,j,kk])
#constraint(m, h1[i,j,kk]<=x[i,j,kk]*s[i,kk])
#constraint(m, h1[i,j,kk]>=s[i,kk]-M*(1-x[i,j,kk]))
#constraint(m, h2[i,j,kk]<=M*x[i,j,kk])
#constraint(m, h2[i,j,kk]<=x[i,j,kk]*s[j,kk])
#constraint(m, h2[i,j,kk]>=s[j,kk]-M*(1-x[i,j,kk]))
if i==1
#constraint(m, x[i,j,kk]*t[i][j]-h2[i,j,kk]==0)
else
#constraint(m, h1[i,j,kk]+x[i,j,kk]*t[i][j]-h2[i,j,kk]==0)
end
end
# ------------ Lazy Constraint -------------
function buildGraph(n)
g = DiGraph(n)
for i in 1:n, j in 1:n, kk in 1:k
if round.(Int,getvalue(x)[i,j,kk])==1
add_edge!(g,(i,j))
end
end
return simplecycles_hadwick_james(g)
end
function subtour(cb)
subtours = buildGraph(no_nodes)
for n in 1:length(subtours), kk in 1:k
if subtours[n][1]!=1
#lazyconstraint(cb, sum(x[i=subtours[n],j=subtours[n],kk])<=length(subtours[n])-1)
end
end
end
addlazycallback(m, subtour)
solve(m)
getobjectivevalue(m)
for i in 1:no_nodes, j in 1:no_nodes, kk in 1:k
if round.(Int,getvalue(x)[i,j,kk])==1
println("($i,$j,$kk) = 1")
end
end
Related
Solve a system of N equations with N unknowns using Julia
I have : a set of N locations which can be workplace or residence a vector of observed workers L_i, with i in N a vector of observed residents R_n, with n in N a matrix of distance observed between all pair residence n and workplace i a shape parameter epsilon Setting N=3, epsilon=5, and d = [1 1.5 3 ; 1.5 1 1.5 ; 3 1.5 1] #distance matrix L_i = [13 69 18] #vector of workers in each workplace R_n = [27; 63; 10] I want to find the vector of wages (size N) that solve this system of N equations, with l all the workplaces. Do I need to implement an iterative algorithm on the vectors of workers and wages? Or is it possible to directly solve this system ? I tried this, w_i = [1 ; 1 ; 1] er=1 n =1 while er>1e-3 L_i = ( (w_i ./ d).^ϵ ) ./ sum( ( (w_i ./ d).^ϵ), dims=1) * R er = maximum(abs.(L .- L_i)) w_i = 0.7.*w_i + 0.3.*w_i.*((L .- L_i) ./ L_i) n = n+1 end
If L and R are given (i.e., do not depend on w_i), you should set up a non-linear search to get (a vector of) wages from that gravity equation (subject to normalising one w_i, of course). Here's a minimal example. I hope it helps. # Call Packages using Random, NLsolve, LinearAlgebra # Set seeds Random.seed!(1704) # Variables and parameters N = 10 R = rand(N) L = rand(N) * 0.5 d = ones(N, N) .+ Symmetric(rand(N, N)) / 10.0 d[diagind(d)] .= 1.0 ε = -3.0 # Define objective function function obj_fun(x, d, R, L, ε) # Find shares S_mat = (x ./ d).^ε den = sum(S_mat, dims = 1) s = S_mat ./ den # Normalize last wage x[end] = 1.0 # Define loss function loss = L .- s * R # Return return loss end # Run optimization x₀ = ones(N) res = nlsolve(x -> obj_fun(x, d, R, L, ε), x₀, show_trace = true) # Equilibrium vector of wages w = res.zero
"How to make the summation to a specific period in Julia?"
I am formulating mathematical programming and now I have an issue with the summation sign in a constraint. I want to sum over the specific period in a planning horizon, I have tried some but Julia report an error message. the mathematical formula looks somewhat like this: constraint1 and this:constraint2 here is some code I have tried: Horizon = 12 Section = 5 TBetPM = [4 6 9 8 5] LPM = [1 4 5 4 4] MaxPM = [9 8 7 10 6] PrevPM = [3 3 2 5 2] tam=zeros(Float64,1,5) for i=1:Section tam[i] = TBetPM[i]-LPM[i] end tar = zeros(Float64,1,5) for i=1:Section tar[i] = Pi[i]*(MaxPM[i]-PrevPM[i])-LPM[i] end #constraint(mod, [i=1:Section], sum(m[i,t] for t=1:Horizon if t<=tam[i]) >= 1 ) #constraint(mod, [i=1:Section], sum(r[i,t] for t=1:Horizon if t<=tar[i]) >= 1 ) I also tried these but both does not work #constraint(mod, [i=1:Section], sum(m[i,t] for t=1:tam[i]) >= 1 ) #constraint(mod, [i=1:Section], sum(r[i,t] for t=1:tar[i]) >= 1 ) Thank you in advance for all the answers :)
You used a model mod in your #constraint macro. It wasn't defined. You must create it if you use JuMP. using JuMP mod = Model() You previsouly initialized tam and tar as two dimensionnal arrays of size 1x5 (matrices). I think you needed a one dimensional array as you accessed them as vectors : tam = zeros(Float64,5) tar = zeros(Float64,5) You didn't defined the variables m and r in your model : #variable(mod, m[i=1:Section, t=1:Horizon]) #variable(mod, r[i=1:Section, t=1:Horizon]) Finally, you might want JuMP to solve your model, this can be done with : using GLPK # feel free here to use the solver you prefer optimize!(mod, with_optimizer(GLPK.Optimizer)) And printing the solutions : if termination_status(mod) == MOI.OPTIMAL optimal_solution = value.(m), value.(r) optimal_objective = objective_value(mod) #show optimal_solution #show optimal_objective else error("The model was not solved correctly.") end Whole working code (Julia v1.1.0, JuMP v0.19.0, GPLK v0.9.1): Horizon = 12 Section = 5 TBetPM = [4 6 9 8 5] LPM = [1 4 5 4 4] MaxPM = [9 8 7 10 6] PrevPM = [3 3 2 5 2] using JuMP using GLPK # feel free here to use the solver you prefer mod = Model() tam = zeros(Float64,5) for i in 1:Section tam[i] = TBetPM[i]-LPM[i] end tar = zeros(Float64,5) for i=1:Section tar[i] = pi*(MaxPM[i] - PrevPM[i]) - LPM[i] end #variable(mod, m[i=1:Section, t=1:Horizon]) #variable(mod, r[i=1:Section, t=1:Horizon]) #constraint(mod, [i=1:Section], sum(m[i,t] for t in 1:Horizon if t <= tam[i]) >= 1) #constraint(mod, [i=1:Section], sum(r[i,t] for t in 1:Horizon if t <= tar[i]) >= 1) # Solve model and printing solution optimize!(mod, with_optimizer(GLPK.Optimizer)) if termination_status(mod) == MOI.OPTIMAL optimal_solution = value.(m), value.(r) optimal_objective = objective_value(mod) #show optimal_solution #show optimal_objective else error("The model was not solved correctly.") end I don't know if it's because of a copy/paste or something else, but you should indent your code even if it's not mandatory to compile it :p
Thank you for the reply, J.Khamphousone. Here is the full code I have tried: using JuMP, CPLEX, Gurobi, GLPKMathProgInterface sex = Model(solver = GurobiSolver()) Horizon = 12 Section = 5 TBetPM = [4 6 9 8 5] TlastPM = [0 0 0 0 0] MaxPM = [9 8 7 10 6] PrevPM = [3 3 2 5 2] taf1=zeros(Float64,1,5) for i=1:Section taf1[i] = TBetPM[i]-TlastPM[i] end tafr1 = zeros(Float64,1,5) for i=1:Section tafr1[i] = TBetPM[i]*(MaxPM[i]-PrevPM[i])-TlastPM[i] end tafr = zeros(Float64,1,5) for i=1:Section tafr[i] = TBetPM[i]*MaxPM[i] end mdur = [9 6 8 10 3] rdur = [18 16 23 16 12] Maxdur = 24 mcost = [2 6 5.5 4 4] rcost = [6 15 20 18 25] scost = [0.6 1.17 0.81 0.66 1.4] pcost = 2 ccost = 0.001 Ncus = 100 #variable(sex, m[1:Section,1:Horizon]>=0, Bin) # 1 if section s maintain in week h #variable(sex, r[1:Section,1:Horizon]>=0, Bin) # 1 if section s renew in week h #variable(sex, p[1:Horizon]>=0,Bin) #1 if possession in week h #objective(sex, Min, sum(pcost*p[t] for t=1:Horizon)+ sum(mcost[i]*m[i,t] for t=1:Horizon, i=1:Section)+ sum(rcost[i]*r[i,t] for t=1:Horizon, i=1:Section) ) #select first maintenance time (correct) #constraint(sex, [i=1:Section], sum(m[i,t] for t=1:Horizon if t==taf1[i]) >= 1 ) #select next maintenance time (correct) #constraint(sex, [i=1:Section, k=1:(Horizon-TBetPM[i])], sum(m[i,t] for t=1+k:TBetPM[i]+k) >= 1 ) #select first renewal time #constraint(sex, [i=1:Section], sum(r[i,t] for t in tafr1[i]) >= 1 ) #select next renewal time #constraint(sex, [i=1:Section, k=1:(Horizon-tafr[i])], sum(r[i,t] for t=1+k:tafr[i]+k) >= 1 ) # if there is maintenance, there is possession #constraint(sex, [i=1:Section, h=1:Horizon], m[i,h] <= p[h] ) # if there is renewal, there is possession #constraint(sex, [i=1:Section, h=1:Horizon], r[i,h] <= p[h] ) solve(sex) #print(sex) mVal = getvalue(m) for i=1:Section, t=1:Horizon if (mVal[i,t] ==1) println("section[$i] repair in period [$t]", ) end end rVal = getvalue(r) for i=1:Section, t=1:Horizon if (rVal[i,t] ==1) println("section[$i] renew in period [$t]", ) end end
Element-wise multiplication in JuMP environment
I'm trying to implement the following constraint in a JuMP environment: #constraint(m, ((c*x) + (p*o)) + (r.*z) - d .== g') Unfortunately, I get the following error ERROR: MethodError: no method matching append But trying the element-wise multiplication alone does not return any error and implements it correctly into the model. Here you have the minimal example I'm working with. m = Model(solver = GLPKSolverLP()); np = 3; #number of products c = [3 7 5; 6 5 7; 3 6 5; -28 -40 -32]; g = [200 200 200 -1500]; n = length(g); o = [1 1 1]'; #variable(m, x[1:np] >= 0); #variable(m, d[1:n] >= 0); #variable(m, z[1:n] >= 0); #variable(m, r[1:n] >= 0); #variable(m, p[1:n,1:np] >= 0); #objective(m, Min, sum(d)); #constraint(m, ((c*x) + (p*o)) + (r.*z) - d .== g')
It seems that there is a problem when you add quadratic term to linear term and quadratic term is on right hand side of the addition inside #constraint macro. There are two solutions: A. write the quadratic term as first like this: #constraint(m, (r.*z) + ((c*x) + (p*o)) - d .== g') B. define LHS of the equation outside (and now the order of terms does not matter) constr = ((c*x) + (p*o)) + (r.*z) - d #constraint(m, constr .== g') As a side note: your problem is quadratic so GLPKSolverLP will not solve it as it does not allow such constraints.
How to do "for all" in sum notation in Julia/JuMP
I am trying to add constraints to a linear optimization problem in Julia using JuMP. I am using the sum{} function however, I am having trouble with some of the constraints. Does anyone know how to write "for all" in JuMP (the upside down A)? Here is the code I have so far: using JuMP m = Model() c= [3 5 2 ; 4 3 5 ; 4 5 3 ; 5 4 3 ; 3 5 4] #variable(m, x[i=1:5,j=1:3] >= 0) #objective(m,Min,sum{c[i,j]*x[i,j],i=1:5,j=1:3}) for i=1:5 #constraint(m, sum{x[i,j],i,j=1:3} <= 480) end What I am trying to get is this: I am trying to use the for loop as a substitute of "for all i from 1 to 5" however I keep getting errors. Is there another way to do this?
In mathematical notation, you sum across i, and do so for each j. In Julia/JuMP, you can think of "∀" as being a for loop ("for all"), and a "Σ" as being a sum{ }: using JuMP m = Model() c= [3 5 2; 4 3 5; 4 5 3; 5 4 3; 3 5 4] # x_ij >= 0 ∀ i = 1,...,5, j = 1,...,3 #variable(m, x[i=1:5,j=1:3] >= 0) #objective(m,Min,sum{c[i,j]*x[i,j],i=1:5,j=1:3}) # ∀j = 1,...,3 for j in 1:3 #constraint(m, sum{x[i,j],i=1:5} <= 480) end
Vector as matrix coordinates
See https://stackoverflow.com/questions/41810306/appointment-scheduling....
You example does not work. You are indexing the second element twice (by the way, a nice alternative to your floor (rand (n) * x) is to use randi()): octave> M = randi(10, 3) M = 9 2 5 9 3 1 2 8 7 octave> v = [2;2]; octave> M(v) ans = 9 9 octave> M([2;2]) ans = 9 9 The right way to do what you want is to use sub2ind() which works for any number of dimensions. octave> M(sub2ind (size (M), 2, 2)) ans = 3 octave> M = randi (10, 3, 3, 3) M = ans(:,:,1) = 6 3 10 1 7 9 7 6 8 ans(:,:,2) = 7 9 10 9 4 5 8 5 5 ans(:,:,3) = 3 5 10 8 3 10 4 9 4 octave> M(sub2ind (size (M), 1, 2, 3)) ans = 5
I edited the sub2ind function so it can take a vector. works like this: M(sub2ind2(dims, V)); I will probably send the modified sub2ind2 function on the next days. [EDIT] function ind = sub2ind2 (dims, varargin) if (nargin > 1) if (isvector (dims) && all (round (dims) == dims)) nd = length (dims); v = varargin{1}; vlen = length (v) dims(vlen) = prod (dims(vlen:nd)); dims(vlen+1:nd) = []; scale = cumprod (dims(:)); for i = 1:vlen arg = v(i); if (isnumeric (arg) && isequal (round (arg), arg)) if (i == 1) if (all (arg(:) > 0 & arg(:) <= dims(i))) ind = first_arg = arg; else error ("sub2ind: index out of range"); endif else if (size_equal (first_arg, arg)) if ((i > nd && arg == 1) || all (arg(:) > 0 & arg(:) <= dims(i))) ind += scale(i-1) * (arg - 1); else error ("sub2ind: index out of range"); endif else error ("sub2ind: all index arguments must be the same size"); endif endif else error ("sub2ind: expecting integer-valued index arguments"); endif endfor else error ("sub2ind: expecting dims to be an integer vector"); endif else print_usage (); endif endfunction