Skip to content

Commit 8241d2d

Browse files
blegatjoehuchette
authored andcommitted
Use JuMP's functions to simplify conicconstraintdata and add SDP support (#50)
1 parent 2abc9b3 commit 8241d2d

File tree

3 files changed

+46
-171
lines changed

3 files changed

+46
-171
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ script:
1919
- julia -e 'Pkg.clone(pwd())'
2020
- julia --check-bounds=yes -e 'Pkg.test("StructJuMP", coverage=true)'
2121
after_success:
22-
- julia -e 'cd(Pkg.dir("StructJuMP")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
22+
- julia -e 'cd(Pkg.dir("StructJuMP")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'

REQUIRE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
julia 0.3-
2-
JuMP
2+
JuMP 0.17

src/BendersBridge.jl

Lines changed: 44 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -12,81 +12,34 @@ function conicconstraintdata(m::Model)
1212
stoch = getStructure(m)
1313
parent = stoch.parent
1414
numMasterCols = 0
15-
if parent != nothing
15+
if parent !== nothing
1616
numMasterCols = parent.numCols
1717
end
1818
v = Symbol[]
19-
obj_coeff = zeros(m.numCols)
20-
for i in eachindex(m.obj.aff.vars)
21-
var = m.obj.aff.vars[i]
22-
coeff = m.obj.aff.coeffs[i]
23-
obj_coeff[var.col] = coeff
24-
end
2519

2620
var_cones = Any[cone for cone in m.varCones]
2721
con_cones = Any[]
2822
nnz = 0
2923

24+
numSDPRows, numSymRows, nnz = JuMP.getSDrowsinfo(m)
25+
3026
linconstr::Vector{LinearConstraint} = m.linconstr
3127
numLinRows = length(linconstr)
32-
numBounds = 0
33-
nonNeg = Int[]
34-
nonPos = Int[]
35-
free = Int[]
36-
zeroVar = Int[]
37-
for i in 1:m.numCols
38-
seen = false
39-
lb, ub = m.colLower[i], m.colUpper[i]
40-
for (_,cone) in m.varCones
41-
if i in cone
42-
seen = true
43-
@assert lb == -Inf && ub == Inf
44-
break
45-
end
46-
end
47-
48-
if !seen
49-
if lb != -Inf && lb != 0
50-
numBounds += 1
51-
end
52-
if ub != Inf && ub != 0
53-
numBounds += 1
54-
end
55-
if lb == 0 && ub == 0
56-
push!(zeroVar, i)
57-
elseif lb == 0
58-
push!(nonNeg, i)
59-
elseif ub == 0
60-
push!(nonPos, i)
61-
else
62-
push!(free, i)
63-
end
64-
end
65-
end
6628

67-
if !isempty(zeroVar)
68-
push!(var_cones, (:Zero,zeroVar))
69-
end
70-
if !isempty(nonNeg)
71-
push!(var_cones, (:NonNeg,nonNeg))
72-
end
73-
if !isempty(nonPos)
74-
push!(var_cones, (:NonPos,nonPos))
75-
end
76-
if !isempty(free)
77-
push!(var_cones, (:Free,free))
78-
end
29+
numBounds = JuMP.variable_range_to_cone!(var_cones, m)
7930

8031
nnz += numBounds
8132
for c in 1:numLinRows
8233
nnz += length(linconstr[c].terms.coeffs)
8334
end
8435

85-
numSOCRows = 0
86-
for con in m.socconstr
87-
numSOCRows += length(con.normexpr.norm.terms) + 1
88-
end
89-
numRows = numLinRows + numBounds + numSOCRows
36+
numSOCRows = JuMP.getNumSOCRows(m)
37+
numNormRows = length(m.socconstr)
38+
39+
numRows = numLinRows + numBounds + numSOCRows + numSDPRows + numSymRows
40+
41+
# constr_to_row is not used but fill_bounds_constr! and fillconstr! for SDP needs them
42+
constr_to_row = Array{Vector{Int}}(numBounds + 2*length(m.sdpconstr))
9043

9144
b = Array(Float64, numRows)
9245

@@ -98,134 +51,56 @@ function conicconstraintdata(m::Model)
9851
V_s = Float64[]
9952

10053
# Fill it up
101-
nnz = 0
10254
tmprow = JuMP.IndexedVector(Float64,m.numCols)
103-
tmpelts = tmprow.elts
104-
tmpnzidx = tmprow.nzidx
105-
nonneg_rows = Int[]
106-
nonpos_rows = Int[]
107-
eq_rows = Int[]
108-
for c in 1:numLinRows
109-
if linconstr[c].lb == -Inf
110-
b[c] = linconstr[c].ub
111-
push!(nonneg_rows, c)
112-
elseif linconstr[c].ub == Inf
113-
b[c] = linconstr[c].lb
114-
push!(nonpos_rows, c)
115-
elseif linconstr[c].lb == linconstr[c].ub
116-
b[c] = linconstr[c].lb
117-
push!(eq_rows, c)
118-
else
119-
error("We currently do not support ranged constraints with conic solvers")
120-
end
12155

122-
JuMP.assert_isfinite(linconstr[c].terms)
123-
coeffs = linconstr[c].terms.coeffs
124-
vars = linconstr[c].terms.vars
125-
# eliminated collect duplicates
126-
for ind in eachindex(coeffs)
127-
if vars[ind].m === parent
128-
push!(I_m, c)
129-
push!(J_m, vars[ind].col)
130-
push!(V_m, coeffs[ind])
131-
else
132-
push!(I_s, c)
133-
push!(J_s, vars[ind].col)
134-
push!(V_s, coeffs[ind])
135-
end
136-
end
56+
JuMP.fillconstrRHS!(b, con_cones, 0, m.linconstr)
57+
if numMasterCols > 0
58+
JuMP.fillconstrLHS!(I_m, J_m, V_m, tmprow, 0, m.linconstr, parent, true)
13759
end
60+
c = JuMP.fillconstrLHS!(I_s, J_s, V_s, tmprow, 0, m.linconstr, m, true)
13861

139-
c = numLinRows
140-
bndidx = 0
14162
for idx in 1:m.numCols
142-
lb = m.colLower[idx]
14363
# identify integrality information
14464
push!(v, m.colCat[idx])
145-
if lb != -Inf && lb != 0
146-
bndidx += 1
147-
nnz += 1
148-
c += 1
149-
push!(I_s, c)
150-
push!(J_s, idx)
151-
push!(V_s, 1.0)
152-
b[c] = lb
153-
push!(nonpos_rows, c)
154-
end
155-
ub = m.colUpper[idx]
156-
if ub != Inf && ub != 0
157-
bndidx += 1
158-
c += 1
159-
push!(I_s, c)
160-
push!(J_s, idx)
161-
push!(V_s, 1.0)
162-
b[c] = ub
163-
push!(nonneg_rows, c)
164-
end
16565
end
66+
c, d = JuMP.fill_bounds_constr!(I_s, J_s, V_s, b, con_cones, constr_to_row, c, 0, m)
67+
68+
@assert c == numLinRows + numBounds
69+
@assert d == numBounds
16670

167-
if !isempty(nonneg_rows)
168-
push!(con_cones, (:NonNeg,nonneg_rows))
71+
JuMP.fillconstrRHS!(b, con_cones, c, m.socconstr)
72+
if numMasterCols > 0
73+
JuMP.fillconstrLHS!(I_m, J_m, V_m, tmprow, c, m.socconstr, parent, true)
16974
end
170-
if !isempty(nonpos_rows)
171-
push!(con_cones, (:NonPos,nonpos_rows))
75+
c = JuMP.fillconstrLHS!(I_s, J_s, V_s, tmprow, c, m.socconstr, m, true)
76+
77+
@assert c == numLinRows + numBounds + numSOCRows
78+
79+
if numMasterCols > 0
80+
c, d = JuMP.fillconstr!(I_m, J_m, V_m, b, con_cones, tmprow, constr_to_row, c, d, m.sdpconstr, m, true)
17281
end
173-
if !isempty(eq_rows)
174-
push!(con_cones, (:Zero,eq_rows))
82+
c, d = JuMP.fillconstr!(I_s, J_s, V_s, b, con_cones, tmprow, constr_to_row, c, d, m.sdpconstr, m, true)
83+
84+
if c < length(b)
85+
# This happens for example when symmetry constraints are dropped with SDP
86+
resize!(b, c)
17587
end
176-
@assert c == numLinRows + numBounds
17788

178-
tmpelts = tmprow.elts
179-
tmpnzidx = tmprow.nzidx
180-
socidx = 0
181-
for con in m.socconstr
182-
socidx += 1
183-
expr = con.normexpr
184-
c += 1
185-
soc_start = c
186-
JuMP.collect_expr!(m, tmprow, expr.aff)
187-
nnz = tmprow.nnz
188-
indices = tmpnzidx[1:nnz]
189-
vars = expr.aff.vars
190-
for i in eachindex(vars)
191-
if vars[i].m === parent
192-
push!(I_m, c)
193-
push!(J_m, indices[i])
194-
push!(V_m, tmpelts[indices[i]])
195-
else
196-
push!(I_s, c)
197-
push!(J_s, indices[i])
198-
push!(V_s, tmpelts[indices[i]])
199-
end
200-
end
201-
b[c] = -expr.aff.constant
202-
for term in expr.norm.terms
203-
c += 1
204-
JuMP.collect_expr!(m, tmprow, term)
205-
nnz = tmprow.nnz
206-
indices = tmpnzidx[1:nnz]
207-
vars = term.vars
208-
for i = 1:length(vars)
209-
if vars[i].m == parent
210-
push!(I_m, c)
211-
push!(J_m, indices[i])
212-
push!(V_m, -expr.coeff*tmpelts[indices[i]])
213-
else
214-
push!(I_s, c)
215-
push!(J_s, indices[i])
216-
push!(V_s, -expr.coeff*tmpelts[indices[i]])
217-
end
218-
end
219-
b[c] = expr.coeff*term.constant
220-
end
221-
push!(con_cones, (:SOC, soc_start:c))
89+
f_s = JuMP.prepAffObjective(m)
90+
91+
# The conic MPB interface defines conic problems as
92+
# always being minimization problems, so flip if needed
93+
m.objSense == :Max && scale!(f_s, -1.0)
94+
95+
if numMasterCols > 0
96+
JuMP.rescaleSDcols!(spzeros(numMasterCols), J_m, V_m, parent)
22297
end
223-
@assert c == numLinRows + numBounds + numSOCRows
98+
JuMP.rescaleSDcols!(f_s, J_s, V_s, m)
22499

225100
A = sparse(I_m, J_m, V_m, numRows, numMasterCols)
226101
B = sparse(I_s, J_s, V_s, numRows, m.numCols)
227-
228-
return obj_coeff, A, B, b, var_cones, con_cones, v
102+
103+
return f_s, A, B, b, var_cones, con_cones, v
229104
end
230105

231106
function BendersBridge(m::Model, master_solver, sub_solver)

0 commit comments

Comments
 (0)