@@ -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}
1719end
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
2123export ConicToLPQPBridge
2224
@@ -35,25 +37,66 @@ function loadproblem!(wrap::ConicToLPQPBridge, A, collb, colub, obj, rowlb, rowu
3537 wrap. sense = sense
3638end
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
4042function 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
57100end
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
170237end
@@ -245,3 +312,6 @@ function addconstr!{T<:Integer}(wrap::ConicToLPQPBridge, varidx::AbstractArray{T
245312 push! (wrap. rowlb, lb)
246313 push! (wrap. rowub, ub)
247314end
315+ function setvartype! (wrap:: ConicToLPQPBridge , v)
316+ wrap. vartypes = copy (v)
317+ end
0 commit comments