Skip to content

Commit 484f853

Browse files
authored
Use MOI.RotatedSecondOrderCone in QuadOverLinAtom (#601)
1 parent 630c982 commit 484f853

File tree

5 files changed

+56
-28
lines changed

5 files changed

+56
-28
lines changed

src/atoms/second_order_cone/QolElemAtom.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ function new_conic_form!(context::Context{T}, q::QolElemAtom) where {T}
3030
x, y = q.children
3131
t = Variable(x.size)
3232
for i in 1:length(x)
33-
f = vcat(y[i] + t[i], y[i] - t[i], 2 * x[i])
34-
add_constraint!(context, GenericConstraint{MOI.SecondOrderCone}(f))
33+
f = vcat(t[i], (1 / T(2)) * y[i], x[i])
34+
add_constraint!(
35+
context,
36+
GenericConstraint{MOI.RotatedSecondOrderCone}(f),
37+
)
3538
end
36-
add_constraint!(context, y >= 0)
3739
return conic_form!(context, t)
3840
end
3941

src/atoms/second_order_cone/QuadOverLinAtom.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,11 @@ function evaluate(q::QuadOverLinAtom)
2727
return x' * x / evaluate(q.children[2])
2828
end
2929

30-
function new_conic_form!(context::Context, q::QuadOverLinAtom)
30+
function new_conic_form!(context::Context{T}, q::QuadOverLinAtom) where {T}
3131
t = Variable()
3232
x, y = q.children
33-
f = vcat(y + t, y - t, 2 * x)
34-
add_constraint!(context, GenericConstraint{MOI.SecondOrderCone}(f))
35-
add_constraint!(context, y >= 0)
33+
f = vcat(t, (1 / T(2)) * y, x)
34+
add_constraint!(context, GenericConstraint{MOI.RotatedSecondOrderCone}(f))
3635
return conic_form!(context, t)
3736
end
3837

src/constraints/GenericConstraint.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,16 @@ function vexity(vex, ::MOI.SecondOrderCone)
265265
end
266266
return ConvexVexity()
267267
end
268+
269+
# ==============================================================================
270+
# RotatedSecondOrderCone
271+
# ==============================================================================
272+
273+
head(io::IO, ::MOI.RotatedSecondOrderCone) = print(io, "rsoc")
274+
275+
function vexity(vex, ::MOI.RotatedSecondOrderCone)
276+
if !(vex == ConstVexity() || vex == AffineVexity())
277+
return NotDcp()
278+
end
279+
return ConvexVexity()
280+
end

test/test_atoms.jl

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ function test_MultiplyAtom()
536536
target = """
537537
variables: t, x
538538
minobjective: 1.0 * t
539-
[1.0 + 1.0 * t, 1.0 + -1.0 * t, 2.0 * x] in SecondOrderCone(3)
539+
[t, 0.5, x] in RotatedSecondOrderCone(3)
540540
"""
541541
_test_atom(target) do context
542542
x = Variable()
@@ -965,7 +965,7 @@ function test_AbsAtom()
965965
minobjective: 1.0 * w
966966
[1.0 * t + -1.0 * x] in Nonnegatives(1)
967967
[1.0 * t + 1.0 * x] in Nonnegatives(1)
968-
[1.0 + 1.0*w, 1.0 + -1.0*w, 2.0*t] in SecondOrderCone(3)
968+
[w, 0.5, t] in RotatedSecondOrderCone(3)
969969
"""
970970
_test_atom(target) do context
971971
return abs2(Variable())
@@ -1505,7 +1505,7 @@ function test_HuberAtom()
15051505
[1.0 * c + -1.0 * s + -1.0 * n] in Zeros(1)
15061506
[-1.0 * n + 1.0 * n_abs] in Nonnegatives(1)
15071507
[1.0 * n + 1.0 * n_abs] in Nonnegatives(1)
1508-
[1.0 + 1.0 * t, 1.0 + -1.0 * t, 2.0 * s] in SecondOrderCone(3)
1508+
[t, 0.5, s] in RotatedSecondOrderCone(3)
15091509
"""
15101510
_test_atom(target) do context
15111511
return huber(Variable(), 2.0)
@@ -1533,20 +1533,19 @@ end
15331533

15341534
function test_QolElemAtom()
15351535
target = """
1536-
variables: y1, y2, t1, t2, x1, x2
1536+
variables: t1, t2, y1, y2, x1, x2
15371537
minobjective: [1.0 * t1, 1.0 * t2]
1538-
[1.0 * y1, 1.0 * y2] in Nonnegatives(2)
1539-
[1.0 * y1 + 1.0 * t1, 1.0 * y1 + -1.0 * t1, 2.0 * x1] in SecondOrderCone(3)
1540-
[1.0 * y2 + 1.0 * t2, 1.0 * y2 + -1.0 * t2, 2.0 * x2] in SecondOrderCone(3)
1538+
[t1, 0.5 * y1, x1] in RotatedSecondOrderCone(3)
1539+
[t2, 0.5 * y2, x2] in RotatedSecondOrderCone(3)
15411540
"""
15421541
_test_atom(target) do context
15431542
return qol_elementwise(Variable(2), Variable(2))
15441543
end
15451544
target = """
15461545
variables: t1, t2, x1, x2
15471546
minobjective: [1.0 * t1, 1.0 * t2]
1548-
[1.0 + 1.0 * t1, 1.0 + -1.0 * t1, 2.0 * x1] in SecondOrderCone(3)
1549-
[1.0 + 1.0 * t2, 1.0 + -1.0 * t2, 2.0 * x2] in SecondOrderCone(3)
1547+
[t1, 0.5, x1] in RotatedSecondOrderCone(3)
1548+
[t2, 0.5, x2] in RotatedSecondOrderCone(3)
15501549
"""
15511550
_test_atom(target) do context
15521551
return qol_elementwise(Variable(2), constant([1, 1]))
@@ -1562,11 +1561,10 @@ function test_QolElemAtom()
15621561
return Variable(2) .^ a
15631562
end
15641563
target = """
1565-
variables: y1, y2, t1, t2
1564+
variables: t1, t2, y1, y2
15661565
minobjective: [1.0 * t1, 1.0 * t2]
1567-
[1.0 * y1, 1.0 * y2] in Nonnegatives(2)
1568-
[1.0 * y1 + 1.0 * t1, 1.0 * y1 + -1.0 * t1, 2.0] in SecondOrderCone(3)
1569-
[1.0 * y2 + 1.0 * t2, 1.0 * y2 + -1.0 * t2, 2.0] in SecondOrderCone(3)
1566+
[t1, 0.5 * y1, 1.0] in RotatedSecondOrderCone(3)
1567+
[t2, 0.5 * y2, 1.0] in RotatedSecondOrderCone(3)
15701568
"""
15711569
_test_atom(target) do context
15721570
return invpos(Variable(2))
@@ -1575,10 +1573,9 @@ function test_QolElemAtom()
15751573
return 1 ./ Variable(2)
15761574
end
15771575
target = """
1578-
variables: y, t
1576+
variables: t, y
15791577
minobjective: 3.0 * t
1580-
[1.0 * y] in Nonnegatives(1)
1581-
[1.0 * y + 1.0 * t, 1.0 * y + -1.0 * t, 2.0] in SecondOrderCone(3)
1578+
[t, 0.5 * y, 1.0] in RotatedSecondOrderCone(3)
15821579
"""
15831580
_test_atom(target) do context
15841581
return 3 / Variable()
@@ -1620,10 +1617,9 @@ end
16201617

16211618
function test_QuadOverLinAtom()
16221619
target = """
1623-
variables: y, t, x1, x2
1620+
variables: t, y, x1, x2
16241621
minobjective: 1.0 * t
1625-
[1.0 * y] in Nonnegatives(1)
1626-
[1.0 * y + 1.0 * t, 1.0 * y + -1.0 * t, 2.0 * x1, 2.0 * x2] in SecondOrderCone(4)
1622+
[t, 0.5 * y, x1, x2] in RotatedSecondOrderCone(4)
16271623
"""
16281624
_test_atom(target) do context
16291625
return quadoverlin(Variable(2), Variable())
@@ -1931,7 +1927,7 @@ function test_quadform()
19311927
variables: u, t, x1, x2
19321928
minobjective: 1.0 * u
19331929
[t, 3.999999999999999*x1+1.9999999999999998*x2, 1.9999999999999998*x1+3.999999999999999*x2] in SecondOrderCone(3)
1934-
[1.0+1.0*u, 1.0+-1.0*u, 2.0*t] in SecondOrderCone(3)
1930+
[u, 0.5, t] in RotatedSecondOrderCone(3)
19351931
"""
19361932
_test_reformulation(target) do context
19371933
return quadform(Variable(2), [20.0 16.0; 16.0 20.0])
@@ -1946,7 +1942,7 @@ function test_quadform()
19461942
variables: u, t, x1, x2
19471943
minobjective: 1.0 + -1.0 * u
19481944
[t, 3.999999999999999*x1+1.9999999999999998*x2, 1.9999999999999998*x1+3.999999999999999*x2] in SecondOrderCone(3)
1949-
[1.0+1.0*u, 1.0+-1.0*u, 2.0*t] in SecondOrderCone(3)
1945+
[u, 0.5, t] in RotatedSecondOrderCone(3)
19501946
"""
19511947
_test_reformulation(target) do context
19521948
return 1 + quadform(Variable(2), -[20 16; 16 20])

test/test_constraints.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ function test_GenericConstraint_SecondOrderCone()
215215
@test isapprox(c.dual, [1, -2 / t_, -3 / t_, -4 / t_]; atol = 1e-3)
216216
c = Convex.GenericConstraint{MOI.SecondOrderCone}(vcat(square(t), x))
217217
@test vexity(c) === Convex.NotDcp()
218+
@test Convex.sprint(Convex.head, c) == "soc"
218219
return
219220
end
220221

@@ -232,6 +233,23 @@ function test_GenericConstraint_SecondOrderCone_set_with_size()
232233
return
233234
end
234235

236+
### constraints/GenericConstraint_RotatedSecondOrderCone
237+
238+
function test_GenericConstraint_RotatedSecondOrderCone()
239+
x = Variable(3)
240+
t = Variable()
241+
c = Convex.GenericConstraint{MOI.RotatedSecondOrderCone}(vcat(t, 1, x))
242+
p = minimize(t, [c, x >= [2, 3, 4]])
243+
solve!(p, SCS.Optimizer; silent_solver = true)
244+
@test isapprox(x.value, [2, 3, 4]; atol = 1e-3)
245+
@test isapprox(t.value, 29 / 2; atol = 1e-3)
246+
@test isapprox(c.dual, [1, 29 / 2, -2, -3, -4]; atol = 1e-3)
247+
c = Convex.GenericConstraint{MOI.RotatedSecondOrderCone}(vcat(square(t), x))
248+
@test vexity(c) === Convex.NotDcp()
249+
@test Convex.sprint(Convex.head, c) == "rsoc"
250+
return
251+
end
252+
235253
### constraints/GenericConstraint_ExponentialCone
236254

237255
function test_GenericConstraint_ExponentialConeConstraint()

0 commit comments

Comments
 (0)