Skip to content

Commit 20b77f2

Browse files
committed
Add tests for ZerosBridge
1 parent b149098 commit 20b77f2

File tree

6 files changed

+80
-20
lines changed

6 files changed

+80
-20
lines changed

src/Bridges/Constraint/map.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,4 +243,5 @@ function Base.empty!(::EmptyMap) end
243243
Base.keys(::EmptyMap) = MOIB.EmptyVector{MOI.VariableIndex}()
244244
Base.values(::EmptyMap) = MOIB.EmptyVector{AbstractBridge}()
245245
has_bridges(::EmptyMap) = false
246-
number_with_set(::EmptyMap, ::Type{<:MOI.AbstractSet}) = 0
246+
number_of_type(::EmptyMap, ::Type{<:MOI.ConstraintIndex}) = 0
247+
keys_of_type(::EmptyMap, C::Type{<:MOI.ConstraintIndex}) = C[]

src/Bridges/Variable/map.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,16 @@ function number_with_set(map::Map, S::Type{<:MOI.AbstractSet})
120120
return count(isequal(S), map.sets)
121121
end
122122

123+
"""
124+
constraints_with_set(map::Map, S::Type{<:MOI.AbstractSet})
125+
126+
Return the list of constraints corresponding to bridged variables in `S`.
127+
"""
128+
function constraints_with_set(map::Map, S::Type{<:MOI.AbstractSet})
129+
F = S <: MOI.AbstractScalarFunction ? MOI.SingleVariable : MOI.VectorOfVariables
130+
return [MOI.ConstraintIndex{F, S}(-i) for i in eachindex(map.sets) if map.sets[i] == S]
131+
end
132+
123133
"""
124134
has_keys(map::Map, vis::Vector{MOI.VariableIndex})::Bool
125135
@@ -299,3 +309,5 @@ Base.values(::EmptyMap) = MOIB.EmptyVector{AbstractBridge}()
299309
has_bridges(::EmptyMap) = false
300310
number_of_variables(::EmptyMap) = 0
301311
number_with_set(::EmptyMap, ::Type{<:MOI.AbstractSet}) = 0
312+
constraints_with_set(::EmptyMap, S::Type{<:MOI.AbstractScalarSet}) = MOI.ConstraintIndex{MOI.SingleVariable, S}[]
313+
constraints_with_set(::EmptyMap, S::Type{<:MOI.AbstractVectorSet}) = MOI.ConstraintIndex{MOI.VectorOfVariables, S}[]

src/Bridges/Variable/zeros.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ the bridged variables were use.
1111
The dual values cannot be determined by the bridge but they can be determined
1212
by the bridged optimizer using [`MathOptInterface.Utilities.get_fallback`](@ref)
1313
if a `CachingOptimizer` is used (since `ConstraintFunction` cannot be got
14-
as functions cannot be unbridged.
14+
as functions cannot be unbridged).
1515
"""
1616
struct ZerosBridge{T} <: AbstractBridge
1717
n::Int # Number of variables

src/Bridges/bridge_optimizer.jl

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,22 @@ end
232232
function get_all_including_bridged(
233233
b::AbstractBridgeOptimizer,
234234
attr::MOI.ListOfConstraintIndices{F, S}) where {F, S}
235-
if is_bridged(b, F, S)
236-
return collect(Constraint.keys_of_type(Constraint.bridges(b),
237-
MOI.ConstraintIndex{F, S}))
235+
list = if is_bridged(b, F, S)
236+
collect(Constraint.keys_of_type(Constraint.bridges(b),
237+
MOI.ConstraintIndex{F, S}))
238238
else
239-
return MOI.get(b.model, attr)
239+
MOI.get(b.model, attr)
240240
end
241+
if F == MOI.VectorOfVariables || F == MOI.SingleVariable
242+
if !is_bridged(b, F, S)
243+
# Even it it is not bridged, it may have been force-bridged because one of the
244+
# variable in the function was bridged.
245+
append!(list, Constraint.keys_of_type(Constraint.bridges(b),
246+
MOI.ConstraintIndex{F, S}))
247+
end
248+
append!(list, Variable.constraints_with_set(Variable.bridges(b), S))
249+
end
250+
return list
241251
end
242252
# Remove constraints bridged by `bridge` from `list`
243253
function _remove_bridged(list, bridge, attr)

test/Bridges/Variable/flip_sign.jl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ const MOIB = MathOptInterface.Bridges
88

99
include("../utilities.jl")
1010

11-
include("../simple_model.jl")
12-
13-
mock = MOIU.MockOptimizer(SimpleModel{Float64}())
11+
mock = MOIU.MockOptimizer(MOIU.Model{Float64}())
1412
config = MOIT.TestConfig()
1513

1614
@testset "NonposToNonneg" begin

test/Bridges/Variable/zeros.jl

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,63 @@ const MOIB = MathOptInterface.Bridges
88

99
include("../utilities.jl")
1010

11-
include("../simple_model.jl")
12-
13-
mock = MOIU.MockOptimizer(SimpleModel{Float64}())
11+
mock = MOIU.MockOptimizer(MOIU.Model{Float64}())
1412
config = MOIT.TestConfig()
1513

1614
@testset "NonposToNonneg" begin
17-
bridged_mock = MOIB.Variable.NonposToNonneg{Float64}(mock)
15+
bridged_mock = MOIB.Variable.Zeros{Float64}(mock)
1816

1917
MOIU.set_mock_optimize!(mock,
2018
(mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(
21-
mock, MOI.INFEASIBLE, MOI.INFEASIBLE_POINT,
22-
MOI.INFEASIBILITY_CERTIFICATE)
19+
mock, [1.0],
20+
(MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => 0.0,
21+
(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => 1.0)
22+
)
23+
24+
x, cx = MOI.add_constrained_variable(bridged_mock, MOI.GreaterThan(0.0))
25+
yz, cyz = MOI.add_constrained_variables(bridged_mock, MOI.Zeros(2))
26+
y, z = yz
27+
fx = MOI.SingleVariable(x)
28+
fy = MOI.SingleVariable(y)
29+
fz = MOI.SingleVariable(z)
30+
c1 = MOI.add_constraint(bridged_mock, 1.0fy + 1.0fz, MOI.EqualTo(0.0))
31+
c2 = MOI.add_constraint(bridged_mock, 1.0fx + 1.0fy + 1.0fz, MOI.GreaterThan(1.0))
32+
MOI.set(bridged_mock, MOI.ObjectiveSense(), MOI.MIN_SENSE)
33+
obj = 1.0fx - 1.0fy - 1.0fz
34+
MOI.set(bridged_mock, MOI.ObjectiveFunction{typeof(obj)}(), obj)
35+
36+
err = ErrorException(
37+
"Cannot unbridge function because some variables are bridged by" *
38+
" variable bridges that do not support reverse mapping, e.g.," *
39+
" `ZerosBridge`."
40+
)
41+
@test_throws err MOI.get(bridged_mock, MOI.ObjectiveFunction{typeof(obj)}())
42+
# With `c1`, the function does not contain any variable so it tests that it
43+
# also throws an error even if it never calls `variable_unbridged_function`.
44+
@test_throws err MOI.get(bridged_mock, MOI.ConstraintFunction(), c1)
45+
@test_throws err MOI.get(bridged_mock, MOI.ConstraintFunction(), c2)
46+
47+
MOI.optimize!(bridged_mock)
48+
@test MOI.get(bridged_mock, MOI.VariablePrimal(), x) == 1.0
49+
@test MOI.get(bridged_mock, MOI.VariablePrimal(), y) == 0.0
50+
@test MOI.get(bridged_mock, MOI.VariablePrimal(), z) == 0.0
51+
52+
@test MOI.get(bridged_mock, MOI.ConstraintDual(), cx) == 0.0
53+
@test MOI.get(bridged_mock, MOI.ConstraintDual(), c1) == 0.0
54+
@test MOI.get(bridged_mock, MOI.ConstraintDual(), c2) == 1.0
55+
56+
err = ArgumentError(
57+
"Bridge of type `MathOptInterface.Bridges.Variable.ZerosBridge{Float64}`" *
58+
" does not support accessing the attribute" *
59+
" `MathOptInterface.ConstraintDual(1)`."
2360
)
24-
MOIT.lin4test(bridged_mock, config)
61+
@test_throws err MOI.get(bridged_mock, MOI.ConstraintDual(), cyz)
2562

2663
@test MOI.get(mock, MOI.NumberOfVariables()) == 1
27-
@test length(MOI.get(mock, MOI.ListOfVariableIndices())) == 1
28-
@test first(MOI.get(mock, MOI.ListOfVariableIndices())).value 0
29-
@test MOI.get(bridged_mock, MOI.NumberOfVariables()) == 1
30-
@test MOI.get(bridged_mock, MOI.ListOfVariableIndices()) == [MOI.VariableIndex(-1)]
64+
@test MOI.get(mock, MOI.ListOfVariableIndices()) == [x]
65+
@test MOI.get(bridged_mock, MOI.NumberOfVariables()) == 3
66+
@test MOI.get(bridged_mock, MOI.ListOfVariableIndices()) == [x, y, z]
67+
@test MOI.get(mock, MOI.NumberOfConstraints{MOI.VectorOfVariables, MOI.Zeros}()) == 0
68+
@test MOI.get(bridged_mock, MOI.NumberOfConstraints{MOI.VectorOfVariables, MOI.Zeros}()) == 1
69+
@test MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorOfVariables, MOI.Zeros}()) == [cyz]
3170
end

0 commit comments

Comments
 (0)