From dea33dcadb3906d94e4242180c55d3cf33d8f6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 16 May 2026 23:24:13 +0200 Subject: [PATCH 1/2] Fix bridging cost --- src/MOI_wrapper.jl | 20 ++++++++++++++++++ test/test_MathOptInterface.jl | 40 +++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 7d72ae00..c41d7374 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -601,6 +601,16 @@ function MOI.supports_constraint( ) end +function MOI.get( + model::Optimizer{T}, + ::MOI.ConstraintBridgingCost{MOI.ScalarQuadraticFunction{T},S}, +) where {T,S<:MOI.AbstractSet} + return MOI.get( + model.optimizer, + MOI.ConstraintBridgingCost{MOI.ScalarAffineFunction{T},S}(), + ) +end + function MOI.supports_constraint( model::Optimizer, ::Type{MOI.VectorQuadraticFunction{T}}, @@ -613,6 +623,16 @@ function MOI.supports_constraint( ) end +function MOI.get( + model::Optimizer{T}, + ::MOI.ConstraintBridgingCost{MOI.VectorQuadraticFunction{T},S}, +) where {T,S<:MOI.AbstractSet} + return MOI.get( + model.optimizer, + MOI.ConstraintBridgingCost{MOI.VectorAffineFunction{T},S}(), + ) +end + function MOI.supports( model::Optimizer, attr::MOI.ConstraintName, diff --git a/test/test_MathOptInterface.jl b/test/test_MathOptInterface.jl index c82dc0e1..e99f5829 100644 --- a/test/test_MathOptInterface.jl +++ b/test/test_MathOptInterface.jl @@ -2111,6 +2111,46 @@ function test_constrained_variables() return end +function test_constraint_bridging_cost_quadratic() + # POI rewrites `Vector/ScalarQuadraticFunction` constraints into their + # affine counterparts at solve time, so `supports_constraint` for the + # quadratic variant delegates to the affine one. `ConstraintBridgingCost` + # must do the same: otherwise `LazyBridgeOptimizer` sees + # `supports = true, cost = Inf` and treats the node as unreachable when + # building the bridge graph. + optimizer = POI.Optimizer(SCS.Optimizer) + for S in (MOI.Zeros, MOI.Nonnegatives, MOI.SecondOrderCone) + @test MOI.supports_constraint( + optimizer, + MOI.VectorQuadraticFunction{Float64}, + S, + ) + @test MOI.get( + optimizer, + MOI.ConstraintBridgingCost{MOI.VectorQuadraticFunction{Float64},S}(), + ) == MOI.get( + optimizer, + MOI.ConstraintBridgingCost{MOI.VectorAffineFunction{Float64},S}(), + ) + end + optimizer = POI.Optimizer(HiGHS.Optimizer) + for S in (MOI.LessThan{Float64}, MOI.GreaterThan{Float64}, MOI.EqualTo{Float64}) + @test MOI.supports_constraint( + optimizer, + MOI.ScalarQuadraticFunction{Float64}, + S, + ) + @test MOI.get( + optimizer, + MOI.ConstraintBridgingCost{MOI.ScalarQuadraticFunction{Float64},S}(), + ) == MOI.get( + optimizer, + MOI.ConstraintBridgingCost{MOI.ScalarAffineFunction{Float64},S}(), + ) + end + return +end + function test_parameter_index_error() model = POI.Optimizer(MOI.Utilities.Model{Float64}()) POI._add_variable(model, MOI.VariableIndex(1)) From d339974a5dc87b3677e7bdfceff4df84ef3eb1a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sat, 16 May 2026 23:27:55 +0200 Subject: [PATCH 2/2] Fix format --- test/test_MathOptInterface.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_MathOptInterface.jl b/test/test_MathOptInterface.jl index e99f5829..3995f025 100644 --- a/test/test_MathOptInterface.jl +++ b/test/test_MathOptInterface.jl @@ -2134,7 +2134,8 @@ function test_constraint_bridging_cost_quadratic() ) end optimizer = POI.Optimizer(HiGHS.Optimizer) - for S in (MOI.LessThan{Float64}, MOI.GreaterThan{Float64}, MOI.EqualTo{Float64}) + for S in + (MOI.LessThan{Float64}, MOI.GreaterThan{Float64}, MOI.EqualTo{Float64}) @test MOI.supports_constraint( optimizer, MOI.ScalarQuadraticFunction{Float64},