Skip to content

Commit 7529596

Browse files
authored
Merge pull request #159 from JuliaOpt/ml/rsoc
enable SOCRotated through conic_to_lpqp
2 parents fba7cac + 3f7b955 commit 7529596

File tree

1 file changed

+82
-12
lines changed

1 file changed

+82
-12
lines changed

src/SolverInterface/conic_to_lpqp.jl

Lines changed: 82 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ type ConicToLPQPBridge <: AbstractLinearQuadraticModel
1414
sense::Symbol
1515
varboundmap::Vector{Int}
1616
SOCconstrs::Vector{Vector{Int}} # x'x <= y^2, y is first index in vector
17+
RSOCconstrs::Vector{Vector{Int}} # x'x <= y*z, y is first index in vector, z is second
18+
vartypes::Vector{Symbol}
1719
end
1820

19-
ConicToLPQPBridge(s::AbstractConicModel) = ConicToLPQPBridge(s, sparse(Int[],Int[],Float64[]), Float64[], Float64[], Float64[], Float64[], Float64[], :Min, Int[], Array{Vector{Int}}(0))
21+
ConicToLPQPBridge(s::AbstractConicModel) = ConicToLPQPBridge(s, sparse(Int[],Int[],Float64[]), Float64[], Float64[], Float64[], Float64[], Float64[], :Min, Int[], Array{Vector{Int}}(0),Array{Vector{Int}}(0), Symbol[])
2022

2123
export ConicToLPQPBridge
2224

@@ -35,25 +37,66 @@ function loadproblem!(wrap::ConicToLPQPBridge, A, collb, colub, obj, rowlb, rowu
3537
wrap.sense = sense
3638
end
3739

38-
const notsoc_error = "For conic solvers, only quadratic constraints in second-order conic format (x'x <= y^2) are supported"
40+
const notsoc_error = "For conic solvers, only quadratic constraints in second-order cone format (x'x <= y^2) or rotated second-order cone format (x'x <= yz) are supported"
3941

4042
function addquadconstr!(wrap::ConicToLPQPBridge, linearidx, linearval, quadrowidx, quadcolidx, quadval, sense, rhs)
4143
if length(linearidx) > 0 || length(linearval) > 0 || sense != '<' || rhs != 0 || mapreduce(v-> (v == 0.0 || v == 1.0), +, 0, quadval) != length(quadval) - 1 || mapreduce(v->v == -1.0, +, 0, quadval) != 1
4244
error(notsoc_error)
4345
end
4446
length(quadrowidx) == length(quadcolidx) == length(quadval) || error("Inconsistent dimensions")
45-
SOCconstr = Int[]
46-
for i in 1:length(quadval)
47-
quadrowidx[i] == quadcolidx[i] || quadval[i] == 0 || error(notsoc_error)
48-
if quadval[i] == 1.0
49-
push!(SOCconstr, quadcolidx[i])
50-
elseif quadval[i] == -1.0
51-
unshift!(SOCconstr, quadcolidx[i])
47+
# check if SOC or RSOC or neither
48+
n_pos_on_diag = 0
49+
off_diag_idx = 0
50+
neg_diag_idx = 0
51+
n = length(quadval)
52+
nz = 0
53+
for i in 1:n
54+
quadval[i] == 0 && continue
55+
nz += 1
56+
if quadrowidx[i] == quadcolidx[i]
57+
if quadval[i] == 1
58+
n_pos_on_diag += 1
59+
elseif quadval[i] == -1
60+
neg_diag_idx = i
61+
else
62+
error(notsoc_error)
63+
end
5264
else
53-
@assert quadval[i] == 0.0
65+
if quadval[i] == -1
66+
if !(neg_diag_idx == off_diag_idx == 0)
67+
error(notsoc_error)
68+
end
69+
off_diag_idx = i
70+
else
71+
error(notsoc_error)
72+
end
5473
end
5574
end
56-
push!(wrap.SOCconstrs, SOCconstr)
75+
if n_pos_on_diag == nz-1 && neg_diag_idx > 0
76+
# SOC
77+
SOCconstr = Int[]
78+
push!(SOCconstr, quadcolidx[neg_diag_idx])
79+
for i in 1:n
80+
if quadval[i] == 1
81+
push!(SOCconstr,quadcolidx[i])
82+
end
83+
end
84+
push!(wrap.SOCconstrs, SOCconstr)
85+
elseif n_pos_on_diag == nz-1 && off_diag_idx > 0
86+
# Rotated SOC
87+
RSOCconstr = Int[]
88+
push!(RSOCconstr, quadcolidx[off_diag_idx])
89+
push!(RSOCconstr, quadrowidx[off_diag_idx])
90+
for i in 1:n
91+
if quadval[i] == 1
92+
push!(RSOCconstr,quadcolidx[i])
93+
end
94+
end
95+
push!(wrap.RSOCconstrs, RSOCconstr)
96+
97+
else
98+
error(notsoc_error)
99+
end
57100
end
58101

59102

@@ -138,6 +181,7 @@ function optimize!(wrap::ConicToLPQPBridge)
138181
# Instead, append to A.
139182
ISOC = Int[]
140183
JSOC = Int[]
184+
VSOC = Float64[]
141185
SOCconstrs = wrap.SOCconstrs
142186
soc_row = 0
143187
for it in 1:length(SOCconstrs)
@@ -148,23 +192,46 @@ function optimize!(wrap::ConicToLPQPBridge)
148192
for k in 1:n
149193
push!(ISOC, soc_row+k)
150194
push!(JSOC, SOCconstrs[it][k])
195+
push!(VSOC, -1.0)
151196
push!(b, 0.0)
152197
end
153198
push!(constr_cones, (:SOC, (nrow+extrarows+soc_row+1):(nrow+extrarows+soc_row+n)))
154199
soc_row += n
155200
end
201+
RSOCconstrs = wrap.RSOCconstrs
202+
for it in 1:length(RSOCconstrs)
203+
n = length(RSOCconstrs[it])
204+
if collb[RSOCconstrs[it][1]] < 0 || collb[RSOCconstrs[it][2]] < 0
205+
error("Invalid rotated second-order conic constraint: x'x <= yz requires y >= 0 and z >= 0")
206+
end
207+
for k in 1:n
208+
push!(ISOC, soc_row+k)
209+
push!(JSOC, RSOCconstrs[it][k])
210+
if k <= 2
211+
push!(VSOC, -1.0/sqrt(2))
212+
else
213+
push!(VSOC, -1.0)
214+
end
215+
push!(b, 0.0)
216+
end
217+
push!(constr_cones, (:SOCRotated, (nrow+extrarows+soc_row+1):(nrow+extrarows+soc_row+n)))
218+
soc_row += n
219+
end
156220

157221

158222
A = vcat(sparse(I,J,ones(extrarows),extrarows, nvar),
159223
A,
160-
sparse(ISOC,JSOC,fill(-1.0, length(ISOC)),soc_row,nvar))
224+
sparse(ISOC,JSOC,VSOC,soc_row,nvar))
161225

162226
if wrap.sense == :Max
163227
obj = -obj
164228
end
165229

166230
#@show obj, full(A), b, constr_cones, var_cones
167231
loadproblem!(wrap.m, obj, A, b, constr_cones, var_cones)
232+
if !isempty(wrap.vartypes)
233+
setvartype!(wrap.m, wrap.vartypes)
234+
end
168235
optimize!(wrap.m)
169236

170237
end
@@ -245,3 +312,6 @@ function addconstr!{T<:Integer}(wrap::ConicToLPQPBridge, varidx::AbstractArray{T
245312
push!(wrap.rowlb, lb)
246313
push!(wrap.rowub, ub)
247314
end
315+
function setvartype!(wrap::ConicToLPQPBridge, v)
316+
wrap.vartypes = copy(v)
317+
end

0 commit comments

Comments
 (0)