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

Resources