From ee5bd5330bac8609950336f02a98ee65c9745c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Tue, 26 May 2026 18:16:52 +0200 Subject: [PATCH 1/3] Add assert to make bridgeable easier to debug --- src/constraint.jl | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/constraint.jl b/src/constraint.jl index d5d7112..6c98197 100644 --- a/src/constraint.jl +++ b/src/constraint.jl @@ -135,11 +135,34 @@ function _concrete( S, ) end + +# Dispatched assertion that mirrors `_concrete`: a bridge listed in +# `bridges(S)` must, per MOI's contract on `concrete_bridge_type`, support its +# source set before `concrete_bridge_type` (and the downstream +# `added_*_types`) can be called. We dispatch on the bridge supertype so the +# right `supports_*` method is queried. +function _supports( + bridge_type::Type{<:MOI.Bridges.Variable.AbstractBridge}, + S::Type{<:MOI.AbstractSet}, +) + return MOI.Bridges.Variable.supports_constrained_variable(bridge_type, S) +end +function _supports( + bridge_type::Type{<:MOI.Bridges.Constraint.AbstractBridge}, + S::Type{<:MOI.AbstractSet}, +) + return MOI.supports_constraint(bridge_type, MOI.VectorOfVariables, S) +end function bridgeable(c::JuMP.AbstractConstraint, S::Type{<:MOI.AbstractSet}) bridge_types = bridges(S) for bridge_type in bridge_types BT, T = bridge_type c = BridgeableConstraint(c, BT; coefficient_type = T) + # `concrete_bridge_type` documents that it may only be called when + # the bridge's `supports_*` predicate is `true`. + # Otherwise, it just return `BT{T}` for which `added_constrained_variable_types` + # is not implemented and that gives cryptic error. + @assert _supports(BT{T}, S) concrete_bridge_type = _concrete(BT{T}, S) for (ST,) in MOI.Bridges.added_constrained_variable_types(concrete_bridge_type) @@ -169,6 +192,12 @@ function bridgeable( for bridge_type in bridge_types BT, T = bridge_type c = BridgeableConstraint(c, BT, coefficient_type = T) + # Same invariant as the variable version above: a bridge listed in + # `bridges(F, S)` must actually support `F`-in-`S` per MOI's contract + # on `concrete_bridge_type`. Failing this assertion means the call + # site listed a bridge in `bridges(F, S)` that does not bridge `F` in + # `S`. + @assert MOI.supports_constraint(BT{T}, F, S) concrete_bridge_type = MOI.Bridges.Constraint.concrete_bridge_type(BT{T}, F, S) for (ST,) in From 7b07c7e5bcbda7f85f2e23b6e2fe0fb44cdcb142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Wed, 27 May 2026 21:43:48 +0200 Subject: [PATCH 2/3] Fix --- test/testpolymodule.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/testpolymodule.jl b/test/testpolymodule.jl index 74011f7..041c121 100644 --- a/test/testpolymodule.jl +++ b/test/testpolymodule.jl @@ -36,6 +36,13 @@ function PolyJuMP.bridges( PolyJuMP.coefficient_type_or_float(F), )] end +function MOI.supports_constraint( + ::Type{<:DummyNonNegBridge}, + ::Type{<:MOI.AbstractVectorFunction}, + ::Type{<:NonNeg}, +) + return true +end function MOI.Bridges.added_constrained_variable_types( ::Type{<:DummyNonNegBridge}, ) From d83ea30a09737b9223ad4c418efc2cd7517c23c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Wed, 27 May 2026 21:55:14 +0200 Subject: [PATCH 3/3] Fix format --- test/variable.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/variable.jl b/test/variable.jl index 82cf032..bdb1a3e 100644 --- a/test/variable.jl +++ b/test/variable.jl @@ -80,7 +80,7 @@ function test_MonomialBasis(var) @variable(m, p3[2:3], Poly(X)) @test isa(p3, JuMP.Containers.DenseAxisArray{PT,1,Tuple{UnitRange{Int}}}) _test_variable(m, p3[2], X) - @variable(m, p4[i=2:3, j=i:4], Poly(X), binary = true) + @variable(m, p4[i = 2:3, j = i:4], Poly(X), binary = true) _test_variable(m, p4[2, 3], X, true) X = [x^2, y^2]