From 5b6eed23bd7ca0daca6960138f6afbf7adf50410 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Mon, 2 Mar 2026 16:59:30 +1300 Subject: [PATCH 1/6] [Bridges] wrap compute_sparse_sqrt in a try-catch --- .../Constraint/bridges/QuadtoSOCBridge.jl | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl b/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl index 23431d0645..ef19ad6120 100644 --- a/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl +++ b/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl @@ -80,22 +80,22 @@ function compute_sparse_sqrt_fallback(Q, ::F, ::S) where {F,S} end function compute_sparse_sqrt(Q, func, set) - factor = try - LinearAlgebra.cholesky(Q; check = false) + try + factor = LinearAlgebra.cholesky(Q; check = false) + if !LinearAlgebra.issuccess(factor) + return compute_sparse_sqrt_fallback(Q, func, set) + end + L, p = SparseArrays.sparse(factor.L), factor.p + # We have Q = P' * L * L' * P. We want to find Q = U' * U, so U = L' * P + # First, compute L'. Note I and J are reversed + J, I, V = SparseArrays.findnz(L) + # Then, we want to permute the columns of L'. The rows stay in the same + # order. + return I, p[J], V catch - msg = "There was an error computing a Cholesky decomposition" + msg = "There was an error computing a matrix square root" throw(MOI.UnsupportedConstraint{typeof(func),typeof(set)}(msg)) end - if !LinearAlgebra.issuccess(factor) - return compute_sparse_sqrt_fallback(Q, func, set) - end - L, p = SparseArrays.sparse(factor.L), factor.p - # We have Q = P' * L * L' * P. We want to find Q = U' * U, so U = L' * P - # First, compute L'. Note I and J are reversed - J, I, V = SparseArrays.findnz(L) - # Then, we want to permute the columns of L'. The rows stay in the same - # order. - return I, p[J], V end function bridge_constraint( From 5022546c2bdd5cd0267515665f0911c9112ba50d Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Tue, 3 Mar 2026 15:01:28 +1300 Subject: [PATCH 2/6] Update --- src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl b/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl index ef19ad6120..334c7a92ca 100644 --- a/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl +++ b/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl @@ -92,7 +92,10 @@ function compute_sparse_sqrt(Q, func, set) # Then, we want to permute the columns of L'. The rows stay in the same # order. return I, p[J], V - catch + catch err + if err isa MOI.AddConstraintNotAllowed + rethrow(err) + end msg = "There was an error computing a matrix square root" throw(MOI.UnsupportedConstraint{typeof(func),typeof(set)}(msg)) end From f10e7f6ab4170644eb1579b09954384cf774f116 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Wed, 4 Mar 2026 08:13:21 +1300 Subject: [PATCH 3/6] Update --- test/Bridges/Constraint/test_QuadtoSOCBridge.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Bridges/Constraint/test_QuadtoSOCBridge.jl b/test/Bridges/Constraint/test_QuadtoSOCBridge.jl index 9ca703a8e4..8838277490 100644 --- a/test/Bridges/Constraint/test_QuadtoSOCBridge.jl +++ b/test/Bridges/Constraint/test_QuadtoSOCBridge.jl @@ -389,6 +389,7 @@ function test_compute_sparse_sqrt_edge_cases() BigFloat[1.0 0.0; 0.0 2.0], BigFloat[1.0 1.0; 1.0 1.0], ] + @show A B = SparseArrays.sparse(A) f = zero(MOI.ScalarQuadraticFunction{eltype(A)}) s = MOI.GreaterThan(zero(eltype(A))) From 19acb0a63795392c5418f4614ee09265e4fd8791 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Wed, 4 Mar 2026 11:18:47 +1300 Subject: [PATCH 4/6] Apply suggestion from @odow --- test/Bridges/Constraint/test_QuadtoSOCBridge.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Bridges/Constraint/test_QuadtoSOCBridge.jl b/test/Bridges/Constraint/test_QuadtoSOCBridge.jl index 8838277490..9ca703a8e4 100644 --- a/test/Bridges/Constraint/test_QuadtoSOCBridge.jl +++ b/test/Bridges/Constraint/test_QuadtoSOCBridge.jl @@ -389,7 +389,6 @@ function test_compute_sparse_sqrt_edge_cases() BigFloat[1.0 0.0; 0.0 2.0], BigFloat[1.0 1.0; 1.0 1.0], ] - @show A B = SparseArrays.sparse(A) f = zero(MOI.ScalarQuadraticFunction{eltype(A)}) s = MOI.GreaterThan(zero(eltype(A))) From 7af698e572fae1ace83295ee552100434aa62d9a Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Wed, 4 Mar 2026 12:41:43 +1300 Subject: [PATCH 5/6] Enhance comments in compute_sparse_sqrt function Added comments to clarify the purpose of the try-catch block in compute_sparse_sqrt function. --- src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl b/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl index 334c7a92ca..80d82a4cea 100644 --- a/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl +++ b/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl @@ -80,6 +80,13 @@ function compute_sparse_sqrt_fallback(Q, ::F, ::S) where {F,S} end function compute_sparse_sqrt(Q, func, set) + # There's a big try-catch here because `cholesky` can fail even if + # `check = false`. As one example, it currently (v1.12) fails with + # `BigFloat`. Similarly, we want to guard against errors in + # `compute_sparse_sqrt_fallback`. + # + # The try-catch isn't a performance concern because the alternative is not + # being able to reformulate the problem. try factor = LinearAlgebra.cholesky(Q; check = false) if !LinearAlgebra.issuccess(factor) From 08bed207925c960a46062cb5dfa0cf26ac8be16a Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Wed, 4 Mar 2026 13:20:05 +1300 Subject: [PATCH 6/6] Apply suggestion from @odow --- src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl b/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl index 80d82a4cea..437547c006 100644 --- a/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl +++ b/src/Bridges/Constraint/bridges/QuadtoSOCBridge.jl @@ -80,7 +80,7 @@ function compute_sparse_sqrt_fallback(Q, ::F, ::S) where {F,S} end function compute_sparse_sqrt(Q, func, set) - # There's a big try-catch here because `cholesky` can fail even if + # There's a big try-catch here because Cholesky can fail even if # `check = false`. As one example, it currently (v1.12) fails with # `BigFloat`. Similarly, we want to guard against errors in # `compute_sparse_sqrt_fallback`.