Skip to content

Commit 466d07a

Browse files
committed
Remove LDLFactorizations
1 parent cee6f12 commit 466d07a

7 files changed

Lines changed: 130 additions & 187 deletions

File tree

Project.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,9 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
2020

2121
[weakdeps]
2222
CliqueTrees = "60701a23-6482-424a-84db-faee86b9b1f8"
23-
LDLFactorizations = "40e66cde-538c-5869-a4ad-c39174c6795b"
2423

2524
[extensions]
2625
MathOptInterfaceCliqueTreesExt = "CliqueTrees"
27-
MathOptInterfaceLDLFactorizationsExt = "LDLFactorizations"
2826

2927
[compat]
3028
BenchmarkTools = "1"
@@ -34,7 +32,6 @@ CodecZlib = "0.6, 0.7"
3432
ForwardDiff = "1"
3533
JSON = "0.21, 1"
3634
JSONSchema = "1"
37-
LDLFactorizations = "0.10"
3835
LinearAlgebra = "1"
3936
MutableArithmetics = "1"
4037
NaNMath = "0.3, 1"
@@ -50,8 +47,7 @@ julia = "1.10"
5047
[extras]
5148
CliqueTrees = "60701a23-6482-424a-84db-faee86b9b1f8"
5249
JSONSchema = "7d188eb4-7ad8-530c-ae41-71a32a6d4692"
53-
LDLFactorizations = "40e66cde-538c-5869-a4ad-c39174c6795b"
5450
ParallelTestRunner = "d3525ed8-44d0-4b2c-a655-542cee43accc"
5551

5652
[targets]
57-
test = ["CliqueTrees", "LDLFactorizations", "JSONSchema", "ParallelTestRunner"]
53+
test = ["CliqueTrees", "JSONSchema", "ParallelTestRunner"]

ext/MathOptInterfaceCliqueTreesExt.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import LinearAlgebra
1111
import MathOptInterface as MOI
1212
import SparseArrays
1313

14-
MOI.Utilities.is_defined(::MOI.Utilities.CliqueTreesExt) = true
14+
MOI.Bridges.Constraint.is_defined(::MOI.Bridges.Constraint.CliqueTrees) = true
1515

16-
function MOI.Utilities.compute_sparse_sqrt(
17-
::MOI.Utilities.CliqueTreesExt,
16+
function MOI.Bridges.Constraint.compute_sparse_sqrt(
17+
::MOI.Bridges.Constraint.CliqueTrees,
1818
Q::AbstractMatrix,
1919
)
2020
G = LinearAlgebra.cholesky!(

ext/MathOptInterfaceLDLFactorizationsExt.jl

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl

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

63+
abstract type AbstractExt end
64+
65+
is_defined(::AbstractExt) = false
66+
67+
struct CliqueTrees <: AbstractExt end
68+
69+
struct LinearAlgebraExt <: AbstractExt end
70+
71+
is_defined(::LinearAlgebraExt) = true
72+
73+
function compute_sparse_sqrt(::LinearAlgebraExt, Q::AbstractMatrix)
74+
factor = LinearAlgebra.cholesky(Q; check = false)
75+
if !LinearAlgebra.issuccess(factor)
76+
return nothing
77+
end
78+
L, p = SparseArrays.sparse(factor.L), factor.p
79+
# We have Q = P' * L * L' * P. We want to find Q = U' * U, so U = L' * P
80+
# First, compute L'. Note I and J are reversed
81+
J, I, V = SparseArrays.findnz(L)
82+
# Then, we want to permute the columns of L'. The rows stay in the same
83+
# order.
84+
return I, p[J], V
85+
end
86+
87+
"""
88+
compute_sparse_sqrt(Q::AbstractMatrix)
89+
90+
Attempts to compute a sparse square root such that `Q = A' * A`.
91+
92+
## Return value
93+
94+
If successful, this function returns an `(I, J, V)` triplet of the sparse `A`
95+
matrix.
96+
97+
If unsuccessful, this function returns `nothing`.
98+
99+
## Extensions
100+
101+
By default, this function attempts to use a Cholesky decomposition. If that
102+
fails, it may optionally use various extension packages.
103+
104+
These extension packages must be loaded before calling `compute_sparse_sqrt`.
105+
106+
The extensions currently supported are:
107+
108+
* The pivoted Cholesky in `CliqueTrees.jl`
109+
"""
110+
function compute_sparse_sqrt(Q::AbstractMatrix)
111+
# There's a big try-catch here because Cholesky can fail even if
112+
# `check = false`. The try-catch isn't a performance concern because the
113+
# alternative is not being able to reformulate the problem.
114+
for ext in (LinearAlgebraExt(), CliqueTrees())
115+
if is_defined(ext)
116+
try
117+
if (ret = compute_sparse_sqrt(ext, Q)) !== nothing
118+
return ret
119+
end
120+
catch
121+
end
122+
end
123+
end
124+
return nothing
125+
end
126+
127+
function _get_sqrt_error_message(is_clique_trees_defined::Bool)
128+
msg = """
129+
## SecondOrderCone reformulation
130+
131+
We tried to reformulate the quadratic constraint into a SecondOrderCone,
132+
but this failed because the quadratic constraint is not strongly convex
133+
and our matrix factorization failed.
134+
"""
135+
if is_clique_trees_defined
136+
return msg
137+
end
138+
clique_trees = """
139+
140+
## CliqueTrees.jl
141+
142+
If the constraint is convex but not strongly convex, you can work-around
143+
this issue by manually installing and loading `CliqueTrees.jl`:
144+
```julia
145+
import Pkg; Pkg.add("CliqueTrees")
146+
using CliqueTrees
147+
```
148+
CliqueTrees.jl is not included by default because it contains a number of
149+
heavy dependencies.
150+
"""
151+
return msg * clique_trees
152+
end
153+
63154
function bridge_constraint(
64155
::Type{QuadtoSOCBridge{T}},
65156
model,
@@ -84,43 +175,9 @@ function bridge_constraint(
84175
MOI.ScalarAffineTerm(scale * term.coefficient, term.variable),
85176
) for term in func.affine_terms
86177
]
87-
sqrt_ret = MOI.Utilities.compute_sparse_sqrt(LinearAlgebra.Symmetric(Q))
178+
sqrt_ret = compute_sparse_sqrt(LinearAlgebra.Symmetric(Q))
88179
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-
"""
180+
msg = _get_sqrt_error_message(is_defined(CliqueTrees()))
124181
return throw(MOI.UnsupportedConstraint{typeof(func),typeof(set)}(msg))
125182
end
126183
for (i, j, v) in zip(sqrt_ret[1], sqrt_ret[2], sqrt_ret[3])

src/Utilities/Utilities.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,5 @@ include("lazy_iterators.jl")
7070
include("set_dot.jl")
7171

7272
include("distance_to_set.jl")
73-
include("sparse_square_root.jl")
7473

7574
end # module

src/Utilities/sparse_square_root.jl

Lines changed: 0 additions & 72 deletions
This file was deleted.

0 commit comments

Comments
 (0)