Skip to content

Commit a494aa3

Browse files
committed
Update
1 parent d198cea commit a494aa3

2 files changed

Lines changed: 54 additions & 100 deletions

File tree

src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl

Lines changed: 40 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -60,59 +60,6 @@ end
6060
const QuadtoSOC{T,OT<:MOI.ModelLike} =
6161
SingleBridgeOptimizer{QuadtoSOCBridge{T},OT}
6262

63-
function _error_msg(::MOI.Utilities.LDLFactorizationsExt)
64-
return """
65-
Unable to transform a quadratic constraint into a SecondOrderCone
66-
constraint because the quadratic constraint is not strongly convex and
67-
our Cholesky decomposition failed.
68-
69-
If the constraint is convex but not strongly convex, you can work-around
70-
this issue by manually installing and loading `LDLFactorizations.jl`:
71-
```julia
72-
import Pkg; Pkg.add("LDLFactorizations")
73-
using LDLFactorizations
74-
```
75-
76-
LDLFactorizations.jl is not included by default because it is licensed
77-
under the LGPL.
78-
"""
79-
end
80-
81-
function _error_msg(::MOI.Utilities.CliqueTreesExt)
82-
return """
83-
Unable to transform a quadratic constraint into a SecondOrderCone
84-
constraint because the quadratic constraint is not strongly convex and
85-
our Cholesky decomposition failed.
86-
87-
If the constraint is convex but not strongly convex, you can work-around
88-
this issue by manually installing and loading `CliqueTrees.jl`:
89-
```julia
90-
import Pkg; Pkg.add("CliqueTrees")
91-
using CliqueTrees
92-
```
93-
94-
CliqueTrees.jl is not included by default because it contains a number of
95-
heavy dependencies.
96-
"""
97-
end
98-
99-
function compute_sparse_sqrt(Q, ::F, ::S) where {F,S}
100-
if (ret = MOI.Utilities.compute_sparse_sqrt(Q)) !== nothing
101-
return ret
102-
elseif !MOI.Utilities.is_defined(MOI.Utilities.LDLFactorizationsExt())
103-
msg = _error_msg(MOI.Utilities.LDLFactorizationsExt())
104-
return throw(MOI.AddConstraintNotAllowed{F,S}(msg))
105-
elseif !MOI.Utilities.is_defined(MOI.Utilities.CliqueTreesExt())
106-
msg = _error_msg(MOI.Utilities.CliqueTreesExt())
107-
return throw(MOI.AddConstraintNotAllowed{F,S}(msg))
108-
end
109-
msg = """
110-
Unable to transform a quadratic constraint into a SecondOrderCone
111-
constraint because the quadratic constraint is not convex.
112-
"""
113-
return throw(MOI.UnsupportedConstraint{F,S}(msg))
114-
end
115-
11663
function bridge_constraint(
11764
::Type{QuadtoSOCBridge{T}},
11865
model,
@@ -137,8 +84,46 @@ function bridge_constraint(
13784
MOI.ScalarAffineTerm(scale * term.coefficient, term.variable),
13885
) for term in func.affine_terms
13986
]
140-
I, J, V = compute_sparse_sqrt(LinearAlgebra.Symmetric(Q), func, set)
141-
for (i, j, v) in zip(I, J, V)
87+
sqrt_ret = MOI.Utilities.compute_sparse_sqrt(LinearAlgebra.Symmetric(Q))
88+
if sqrt_ret === nothing
89+
msg = """
90+
## SecondOrderCone reformulation
91+
92+
We tried to reformulate the quadratic constraint into a SecondOrderCone,
93+
but this failed because the quadratic constraint is not strongly convex
94+
and our matrix factorization failed.
95+
96+
## Package extensions
97+
98+
If the constraint is convex but not strongly convex, you can work-around
99+
this issue by manually installing and loading one of the following
100+
packages.
101+
102+
### LDLFactorizations.jl
103+
104+
Currently active: $(MOI.Utilities.is_defined(MOI.Utilities.LDLFactorizationsExt()))
105+
106+
```julia
107+
import Pkg; Pkg.add("LDLFactorizations")
108+
using LDLFactorizations
109+
```
110+
LDLFactorizations.jl is not included by default because it is licensed
111+
under the LGPL.
112+
113+
### CliqueTrees.jl
114+
115+
Currently active: $(MOI.Utilities.is_defined(MOI.Utilities.CliqueTreesExt()))
116+
117+
```julia
118+
import Pkg; Pkg.add("CliqueTrees")
119+
using CliqueTrees
120+
```
121+
CliqueTrees.jl is not included by default because it contains a number of
122+
heavy dependencies.
123+
"""
124+
return throw(MOI.UnsupportedConstraint{typeof(func),typeof(set)}(msg))
125+
end
126+
for (i, j, v) in zip(sqrt_ret[1], sqrt_ret[2], sqrt_ret[3])
142127
push!(
143128
vector_terms,
144129
MOI.VectorAffineTerm(

test/Bridges/Constraint/test_QuadtoSOCBridge.jl

Lines changed: 14 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -28,32 +28,17 @@ end
2828
include("../utilities.jl")
2929

3030
function test_error_for_nonconvex_quadratic_constraints()
31-
mock = MOI.Utilities.MockOptimizer(MOI.Utilities.Model{Float64}())
32-
bridged_mock = MOI.Bridges.Constraint.QuadtoSOC{Float64}(mock)
33-
x = MOI.add_variable(bridged_mock)
31+
inner = MOI.Utilities.Model{Float64}()
32+
model = MOI.Bridges.Constraint.QuadtoSOC{Float64}(inner)
33+
x = MOI.add_variable(model)
34+
F = MOI.ScalarQuadraticFunction{Float64}
3435
@test_throws(
35-
MOI.UnsupportedConstraint,
36-
MOI.add_constraint(
37-
bridged_mock,
38-
MOI.ScalarQuadraticFunction(
39-
[MOI.ScalarQuadraticTerm(1.0, x, x)],
40-
MOI.ScalarAffineTerm{Float64}[],
41-
0.0,
42-
),
43-
MOI.GreaterThan(0.0),
44-
)
36+
MOI.UnsupportedConstraint{F,MOI.GreaterThan{Float64}},
37+
MOI.add_constraint(model, 1.0 * x * x, MOI.GreaterThan(0.0))
4538
)
4639
@test_throws(
47-
MOI.UnsupportedConstraint,
48-
MOI.add_constraint(
49-
bridged_mock,
50-
MOI.ScalarQuadraticFunction(
51-
[MOI.ScalarQuadraticTerm(-1.0, x, x)],
52-
MOI.ScalarAffineTerm{Float64}[],
53-
0.0,
54-
),
55-
MOI.LessThan(0.0),
56-
)
40+
MOI.UnsupportedConstraint{F,MOI.LessThan{Float64}},
41+
MOI.add_constraint(model, -1.0 * x * x, MOI.LessThan(0.0))
5742
)
5843
return
5944
end
@@ -356,23 +341,13 @@ function test_semidefinite_cholesky_fail()
356341
return
357342
end
358343

359-
function test_compute_sparse_sqrt_edge_cases()
360-
for A in Any[
361-
# Trivial Cholesky
344+
function test_linear_algebra_compute_sparse_sqrt_edge_cases()
345+
ext = MOI.Utilities.LinearAlgebraExt()
346+
for A in AbstractMatrix[
362347
[1.0 0.0; 0.0 2.0],
363-
# Cholesky works, with pivoting
364348
[1.0 0.0 1.0; 0.0 1.0 1.0; 1.0 1.0 3.0],
365-
# Cholesky fails due to 0 eigen value. LDL works
366-
[1.0 1.0; 1.0 1.0],
367-
# Cholesky succeeds, even though 0 eigen value
368-
[2.0 2.0; 2.0 2.0],
369-
# Cholesky fails because of 0 column/row. LDL works
370-
[2.0 0.0; 0.0 0.0],
371349
]
372-
B = SparseArrays.sparse(A)
373-
f = zero(MOI.ScalarQuadraticFunction{eltype(A)})
374-
s = MOI.GreaterThan(zero(eltype(A)))
375-
I, J, V = MOI.Bridges.Constraint.compute_sparse_sqrt(B, f, s)
350+
I, J, V = MOI.Utilities.compute_sparse_sqrt(ext, SparseArrays.sparse(A))
376351
U = zeros(eltype(A), size(A))
377352
for (i, j, v) in zip(I, J, V)
378353
U[i, j] += v
@@ -382,17 +357,11 @@ function test_compute_sparse_sqrt_edge_cases()
382357
# Test failures
383358
for A in Any[
384359
[-1.0 0.0; 0.0 1.0],
385-
# Found from test_quadratic_nonconvex_constraint_basic
386360
[0.0 -1.0; -1.0 0.0],
387361
BigFloat[-1.0 0.0; 0.0 1.0],
362+
[1.0 1.0 0.0; 1.0 1.0 0.0; 0.0 0.0 1.0],
388363
]
389-
B = SparseArrays.sparse(A)
390-
f = zero(MOI.ScalarQuadraticFunction{eltype(A)})
391-
s = MOI.GreaterThan(zero(eltype(A)))
392-
@test_throws(
393-
MOI.UnsupportedConstraint{typeof(f),typeof(s)},
394-
MOI.Bridges.Constraint.compute_sparse_sqrt(B, f, s),
395-
)
364+
@test MOI.Utilities.compute_sparse_sqrt(ext, A) === nothing
396365
end
397366
return
398367
end

0 commit comments

Comments
 (0)