Skip to content

Commit 36f1bc3

Browse files
committed
Throw GetAttributeNotAllowed in AbstractBridge getter
1 parent f604fc1 commit 36f1bc3

4 files changed

Lines changed: 121 additions & 1 deletion

File tree

src/Bridges/Bridges.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ _runtests_error_handler(err, ::Bool) = rethrow(err)
239239
function _runtests_error_handler(
240240
err::Union{
241241
MOI.GetAttributeNotAllowed{MOI.ConstraintFunction},
242+
MOI.GetAttributeNotAllowed{MOI.ConstraintSet},
242243
MOI.GetAttributeNotAllowed{MOI.ConstraintPrimalStart},
243244
},
244245
cannot_unbridge::Bool,

src/Bridges/bridge.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ function MOI.get(
146146
bridge::AbstractBridge,
147147
)
148148
message = _attribute_error_message(attr, typeof(bridge), "accessing")
149-
return throw(ArgumentError(message))
149+
return throw(MOI.GetAttributeNotAllowed(attr, message))
150150
end
151151

152152
function MOI.get(
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Copyright (c) 2017: Miles Lubin and contributors
2+
# Copyright (c) 2017: Google Inc.
3+
#
4+
# Use of this source code is governed by an MIT-style license that can be found
5+
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
6+
7+
# Test with a bridge for which the map is defined on the bridge value and not
8+
# the bridge type
9+
module TestAbstractBridge
10+
11+
using Test
12+
13+
import MathOptInterface as MOI
14+
15+
# A minimal constraint bridge that doesn't implement ConstraintFunction getter.
16+
# Used to test that `cannot_unbridge = true` works with the default bridge
17+
# `MOI.get` (which throws `GetAttributeNotAllowed`).
18+
struct _NoUnbridgeTestBridge{T} <: MOI.Bridges.Constraint.AbstractBridge
19+
ci::MOI.ConstraintIndex{MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}
20+
end
21+
22+
function MOI.Bridges.Constraint.bridge_constraint(
23+
::Type{_NoUnbridgeTestBridge{T}},
24+
model::MOI.ModelLike,
25+
f::MOI.ScalarAffineFunction{T},
26+
::MOI.GreaterThan{T},
27+
) where {T}
28+
ci = MOI.add_constraint(model, f, MOI.EqualTo(zero(T)))
29+
return _NoUnbridgeTestBridge{T}(ci)
30+
end
31+
32+
function MOI.supports_constraint(
33+
::Type{_NoUnbridgeTestBridge{T}},
34+
::Type{MOI.ScalarAffineFunction{T}},
35+
::Type{MOI.GreaterThan{T}},
36+
) where {T}
37+
return true
38+
end
39+
40+
function MOI.Bridges.Constraint.concrete_bridge_type(
41+
::Type{_NoUnbridgeTestBridge{T}},
42+
::Type{MOI.ScalarAffineFunction{T}},
43+
::Type{MOI.GreaterThan{T}},
44+
) where {T}
45+
return _NoUnbridgeTestBridge{T}
46+
end
47+
48+
function MOI.Bridges.added_constraint_types(
49+
::Type{_NoUnbridgeTestBridge{T}},
50+
) where {T}
51+
return Tuple{Type,Type}[(MOI.ScalarAffineFunction{T}, MOI.EqualTo{T})]
52+
end
53+
54+
function MOI.Bridges.added_constrained_variable_types(
55+
::Type{<:_NoUnbridgeTestBridge},
56+
)
57+
return Tuple{Type}[]
58+
end
59+
60+
function MOI.get(
61+
::_NoUnbridgeTestBridge{T},
62+
::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},MOI.EqualTo{T}},
63+
) where {T}
64+
return 1
65+
end
66+
67+
function MOI.get(
68+
bridge::_NoUnbridgeTestBridge{T},
69+
::MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{T},MOI.EqualTo{T}},
70+
) where {T}
71+
return [bridge.ci]
72+
end
73+
74+
function MOI.delete(
75+
model::MOI.ModelLike,
76+
bridge::_NoUnbridgeTestBridge,
77+
)
78+
MOI.delete(model, bridge.ci)
79+
return
80+
end
81+
82+
# Note: ConstraintFunction and ConstraintSet getters are NOT implemented.
83+
# The default MOI.get on AbstractBridge throws GetAttributeNotAllowed.
84+
85+
function test_cannot_unbridge_with_default_getter()
86+
# This test verifies that `cannot_unbridge = true` works when a constraint
87+
# bridge does not implement `ConstraintFunction` getter. Before the fix,
88+
# the default bridge `MOI.get` threw `ArgumentError` which was not caught
89+
# by `_runtests_error_handler`.
90+
MOI.Bridges.runtests(
91+
_NoUnbridgeTestBridge,
92+
model -> begin
93+
x = MOI.add_variable(model)
94+
MOI.add_constraint(model, 1.0 * x, MOI.GreaterThan(0.0))
95+
end,
96+
model -> begin
97+
x = MOI.add_variable(model)
98+
MOI.add_constraint(model, 1.0 * x, MOI.EqualTo(0.0))
99+
end;
100+
cannot_unbridge = true,
101+
)
102+
return
103+
end
104+
105+
function runtests()
106+
for name in names(@__MODULE__; all = true)
107+
if startswith("$(name)", "test_")
108+
@testset "$(name)" begin
109+
getfield(@__MODULE__, name)()
110+
end
111+
end
112+
end
113+
return
114+
end
115+
116+
end
117+
118+
TestAbstractBridge.runtests()

test/Bridges/Variable/test_zeros.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ function test_bridge_error_handler()
5151
ErrorException("abc") => false,
5252
MOI.GetAttributeNotAllowed(MOI.ObjectiveSense()) => false,
5353
MOI.GetAttributeNotAllowed(MOI.ConstraintFunction()) => true,
54+
MOI.GetAttributeNotAllowed(MOI.ConstraintSet()) => true,
5455
)
5556
@test_throws err try
5657
@assert false

0 commit comments

Comments
 (0)