Skip to content

Commit b632fb6

Browse files
authored
[Bridges] fix bug with open intervals in SemiToBinaryBridge (#2963)
1 parent 1393aff commit b632fb6

2 files changed

Lines changed: 43 additions & 1 deletion

File tree

src/Bridges/Constraint/bridges/SemiToBinaryBridge.jl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ function bridge_constraint(
7575
f::MOI.VariableIndex,
7676
s::S,
7777
) where {T<:Real,S<:Union{MOI.Semicontinuous{T},MOI.Semiinteger{T}}}
78+
if !isfinite(s.lower) || !isfinite(s.upper)
79+
# We could be cleverer than this, but this is a simple check that should
80+
# be sufficient for most cases. We can revisit if anyone complains.
81+
msg = "Cannot add constraint $f-in-$s because the set has an open interval. To fix, make sure the lower and upper bounds are both finite."
82+
throw(MOI.AddConstraintNotAllowed{MOI.VariableIndex,S}(msg))
83+
end
7884
binary, binary_con = MOI.add_constrained_variable(model, MOI.ZeroOne())
7985
# var - LB * bin >= 0
8086
lb = MOI.Utilities.operate(*, T, -s.lower, binary)
@@ -147,10 +153,16 @@ end
147153

148154
function MOI.set(
149155
model::MOI.ModelLike,
150-
::MOI.ConstraintSet,
156+
attr::MOI.ConstraintSet,
151157
bridge::SemiToBinaryBridge{T,S},
152158
set::S,
153159
) where {T,S}
160+
if !isfinite(set.lower) || !isfinite(set.upper)
161+
# We could be cleverer than this, but this is a simple check that should
162+
# be sufficient for most cases. We can revisit if anyone complains.
163+
msg = "Cannot modify the set $set because the set has an open interval. To fix, make sure the lower and upper bounds are both finite."
164+
throw(MOI.SetAttributeNotAllowed(attr, msg))
165+
end
154166
bridge.semi_set = set
155167
MOI.modify(
156168
model,

test/Bridges/Constraint/test_SemiToBinaryBridge.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,36 @@ function test_runtests()
304304
return
305305
end
306306

307+
function test_open_interval()
308+
for set in Any[
309+
MOI.Semicontinuous(1.0, Inf),
310+
MOI.Semicontinuous(-1.0, Inf),
311+
MOI.Semicontinuous(-Inf, 1.0),
312+
MOI.Semicontinuous(-Inf, -1.0),
313+
MOI.Semiinteger(1.0, Inf),
314+
MOI.Semiinteger(-1.0, Inf),
315+
MOI.Semiinteger(-Inf, 1.0),
316+
MOI.Semiinteger(-Inf, -1.0),
317+
]
318+
model = MOI.Utilities.Model{Float64}()
319+
bridged = MOI.Bridges.Constraint.SemiToBinary{Float64}(model)
320+
x = MOI.add_variable(bridged)
321+
@test_throws(
322+
MOI.AddConstraintNotAllowed{MOI.VariableIndex,typeof(set)},
323+
MOI.add_constraint(bridged, x, set)
324+
)
325+
model = MOI.Utilities.Model{Float64}()
326+
bridged = MOI.Bridges.Constraint.SemiToBinary{Float64}(model)
327+
x = MOI.add_variable(bridged)
328+
c = MOI.add_constraint(bridged, x, typeof(set)(1.0, 2.0))
329+
@test_throws(
330+
MOI.SetAttributeNotAllowed,
331+
MOI.set(bridged, MOI.ConstraintSet(), c, set),
332+
)
333+
end
334+
return
335+
end
336+
307337
end # module
308338

309339
TestConstraintSemiToBinary.runtests()

0 commit comments

Comments
 (0)