Skip to content

Commit 6f58fcb

Browse files
committed
Update
1 parent 6042ed5 commit 6f58fcb

File tree

2 files changed

+95
-64
lines changed

2 files changed

+95
-64
lines changed

docs/src/submodules/Bridges/implementation.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ arguments: the type of the bridge, the input model as a string, and the output
6666
model as a string.
6767

6868
Here is an example:
69-
```jldoctest
69+
```jldoctest; filter="[0-9.]+s"
7070
julia> MOI.Bridges.runtests(
7171
MOI.Bridges.Constraint.GreaterToLessBridge,
7272
"""
@@ -78,6 +78,8 @@ julia> MOI.Bridges.runtests(
7878
-1.0 * x <= -1.0
7979
""",
8080
)
81+
Test Summary: | Pass Total Time
82+
Bridges.runtests | 29 29 0.0s
8183
```
8284

8385
There are a number of other useful keyword arguments.
@@ -98,7 +100,7 @@ There are a number of other useful keyword arguments.
98100

99101
Here is an example:
100102

101-
```jldoctest
103+
```jldoctest; filter="[0-9.]+s"
102104
julia> MOI.Bridges.runtests(
103105
MOI.Bridges.Constraint.GreaterToLessBridge,
104106
"""
@@ -120,4 +122,6 @@ Subject to:
120122
121123
ScalarAffineFunction{Int64}-in-LessThan{Int64}
122124
(0) - (1) x <= (-1)
125+
Test Summary: | Pass Total Time
126+
Bridges.runtests | 29 29 0.0s
123127
```

src/Bridges/Bridges.jl

Lines changed: 89 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -153,15 +153,21 @@ function _test_structural_identical(
153153
# the variables are added in the same order to both models.
154154
a_x = MOI.get(a, MOI.ListOfVariableIndices())
155155
b_x = MOI.get(b, MOI.ListOfVariableIndices())
156-
attr = MOI.NumberOfVariables()
157-
Test.@test MOI.get(a, attr) == MOI.get(b, attr)
158-
Test.@test length(a_x) == length(b_x)
156+
Test.@testset "Test NumberOfVariables" begin
157+
Test.@test MOI.get(a, MOI.NumberOfVariables()) ==
158+
MOI.get(b, MOI.NumberOfVariables())
159+
end
160+
Test.@testset "Test length ListOfVariableIndices" begin
161+
Test.@test length(a_x) == length(b_x)
162+
end
159163
# A dictionary that maps things from `b`-space to `a`-space.
160164
x_map = Dict(bx => a_x[i] for (i, bx) in enumerate(b_x))
161165
# To check that the constraints, we need to first cache all of the
162166
# constraints in `a`.
163167
constraints = Dict{Any,Any}()
164-
Test.@testset "$F-in-$S" for (F, S) in MOI.get(a, MOI.ListOfConstraintTypesPresent())
168+
a_constraint_types = MOI.get(a, MOI.ListOfConstraintTypesPresent())
169+
b_constraint_types = MOI.get(b, MOI.ListOfConstraintTypesPresent())
170+
Test.@testset "get $F and $S" for (F, S) in a_constraint_types
165171
Test.@test MOI.supports_constraint(a, F, S)
166172
constraints[(F, S)] =
167173
map(MOI.get(a, MOI.ListOfConstraintIndices{F,S}())) do ci
@@ -170,20 +176,16 @@ function _test_structural_identical(
170176
MOI.get(a, MOI.ConstraintSet(), ci),
171177
)
172178
end
173-
end
174-
# Now compare the constraints in `b` with the cache in `constraints`.
175-
b_constraint_types = MOI.get(b, MOI.ListOfConstraintTypesPresent())
176-
# There may be constraint types reported in `a` that are not in `b`, but
177-
# have zero constraints in `a`.
178-
Test.@testset "$F-in-$S" for (F, S) in keys(constraints)
179-
attr = MOI.NumberOfConstraints{F,S}()
180-
Test.@test (F, S) in b_constraint_types || MOI.get(a, attr) == 0
179+
# There may be constraint types reported in `a` that are not in `b`, but
180+
# have zero constraints in `a`.
181+
Test.@test (F, S) in b_constraint_types ||
182+
MOI.get(a, MOI.NumberOfConstraints{F,S}()) == 0
181183
end
182184
Test.@testset "$F-in-$S" for (F, S) in b_constraint_types
183185
Test.@test haskey(constraints, (F, S))
184186
# Check that the same number of constraints are present
185-
attr = MOI.NumberOfConstraints{F,S}()
186-
Test.@test MOI.get(a, attr) == MOI.get(b, attr)
187+
Test.@test MOI.get(a, MOI.NumberOfConstraints{F,S}()) ==
188+
MOI.get(b, MOI.NumberOfConstraints{F,S}())
187189
# Check that supports_constraint is implemented
188190
Test.@test MOI.supports_constraint(b, F, S)
189191
# Check that each function in `b` matches a function in `a`
@@ -206,7 +208,9 @@ function _test_structural_identical(
206208
# Test model attributes are set, like ObjectiveSense and ObjectiveFunction.
207209
a_attrs = MOI.get(a, MOI.ListOfModelAttributesSet())
208210
b_attrs = MOI.get(b, MOI.ListOfModelAttributesSet())
209-
Test.@test length(a_attrs) == length(b_attrs)
211+
Test.@testset "Test length ListOfModelAttributesSet" begin
212+
Test.@test length(a_attrs) == length(b_attrs)
213+
end
210214
Test.@testset "$attr" for attr in b_attrs
211215
Test.@test attr in a_attrs
212216
if attr == MOI.ObjectiveSense()
@@ -259,7 +263,7 @@ and [`MOI.ConstraintPrimalStart`](@ref) to throw [`MOI.GetAttributeNotAllowed`](
259263
260264
## Example
261265
262-
```jldoctest; setup=:(import MathOptInterface as MOI)
266+
```jldoctest; setup=:(import MathOptInterface as MOI), filter="[0-9.]+s"
263267
julia> MOI.Bridges.runtests(
264268
MOI.Bridges.Constraint.ZeroOneBridge,
265269
model -> MOI.add_constrained_variable(model, MOI.ZeroOne()),
@@ -268,9 +272,18 @@ julia> MOI.Bridges.runtests(
268272
MOI.add_constraint(model, 1.0 * x, MOI.Interval(0.0, 1.0))
269273
end,
270274
)
275+
Test Summary: | Pass Total Time
276+
Bridges.runtests | 32 32 0.8s
271277
```
272278
"""
273-
function runtests(
279+
function runtests(args...; kwargs...)
280+
Test.@testset "Bridges.runtests" begin
281+
_runtests(args...; kwargs...)
282+
end
283+
return
284+
end
285+
286+
function _runtests(
274287
Bridge::Type{<:AbstractBridge},
275288
input_fn::Function,
276289
output_fn::Function;
@@ -290,58 +303,61 @@ function runtests(
290303
if print_inner_model
291304
print(inner)
292305
end
293-
# Load a non-bridged input model, and check that getters are the same.
294-
test = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{eltype}())
295-
input_fn(test)
296-
Test.@testset "Outer model" begin
306+
Test.@testset "Test outer bridged model appears like the input" begin
307+
test = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{eltype}())
308+
input_fn(test)
297309
_test_structural_identical(
298310
test,
299311
model;
300312
cannot_unbridge = cannot_unbridge,
301313
)
302314
end
303-
# Load a bridged target model, and check that getters are the same.
304-
target = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{eltype}())
305-
output_fn(target)
306-
Test.@testset "Inner model" begin
315+
Test.@testset "Test inner bridged model appears like the target" begin
316+
target = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{eltype}())
317+
output_fn(target)
307318
_test_structural_identical(target, inner)
308319
end
309-
# Test VariablePrimalStart
310-
attr = MOI.VariablePrimalStart()
311-
bridge_supported = all(values(Variable.bridges(model))) do bridge
312-
return MOI.supports(model, attr, typeof(bridge))
313-
end
314-
if MOI.supports(model, attr, MOI.VariableIndex) && bridge_supported
315-
x = MOI.get(model, MOI.ListOfVariableIndices())
316-
MOI.set(model, attr, x, fill(nothing, length(x)))
317-
Test.@test all(isnothing, MOI.get(model, attr, x))
318-
primal_start = fill(variable_start, length(x))
319-
MOI.set(model, attr, x, primal_start)
320-
if !isempty(x)
321-
# ≈ does not work if x is empty because the return of get is Any[]
322-
Test.@test MOI.get(model, attr, x) primal_start
320+
Test.@testset "Test MOI.VariablePrimalStart" begin
321+
attr = MOI.VariablePrimalStart()
322+
bridge_supported = all(values(Variable.bridges(model))) do bridge
323+
return MOI.supports(model, attr, typeof(bridge))
323324
end
324-
end
325-
# Test ConstraintPrimalStart and ConstraintDualStart
326-
for (F, S) in MOI.get(model, MOI.ListOfConstraintTypesPresent())
327-
for ci in MOI.get(model, MOI.ListOfConstraintIndices{F,S}())
328-
set = try
329-
MOI.get(model, MOI.ConstraintSet(), ci)
330-
catch err
331-
_runtests_error_handler(err, cannot_unbridge)
332-
continue
325+
if MOI.supports(model, attr, MOI.VariableIndex) && bridge_supported
326+
x = MOI.get(model, MOI.ListOfVariableIndices())
327+
MOI.set(model, attr, x, fill(nothing, length(x)))
328+
Test.@test all(isnothing, MOI.get(model, attr, x))
329+
primal_start = fill(variable_start, length(x))
330+
MOI.set(model, attr, x, primal_start)
331+
if !isempty(x)
332+
# ≈ does not work if x is empty because the return of get is Any[]
333+
Test.@test MOI.get(model, attr, x) primal_start
333334
end
334-
for attr in (MOI.ConstraintPrimalStart(), MOI.ConstraintDualStart())
335-
if MOI.supports(model, attr, MOI.ConstraintIndex{F,S})
335+
end
336+
end
337+
Test.@testset "Test ConstraintPrimalStart and ConstraintDualStart" begin
338+
list_of_constraints = MOI.get(model, MOI.ListOfConstraintTypesPresent())
339+
Test.@testset "$F-in-$S" for (F, S) in list_of_constraints
340+
for ci in MOI.get(model, MOI.ListOfConstraintIndices{F,S}())
341+
set = try
342+
MOI.get(model, MOI.ConstraintSet(), ci)
343+
catch err
344+
_runtests_error_handler(err, cannot_unbridge)
345+
continue
346+
end
347+
attrs = (MOI.ConstraintPrimalStart(), MOI.ConstraintDualStart())
348+
Test.@testset "$attr" for attr in attrs
349+
if !MOI.supports(model, attr, MOI.ConstraintIndex{F,S})
350+
continue
351+
end
336352
MOI.set(model, attr, ci, nothing)
337353
Test.@test MOI.get(model, attr, ci) === nothing
338354
start = _fake_start(constraint_start, set)
339355
MOI.set(model, attr, ci, start)
340356
returned_start = try
341357
MOI.get(model, attr, ci)
342358
catch err
343-
# For a Constraint bridge for which the map is not invertible, the constraint primal cannot
344-
# be inverted
359+
# For a Constraint bridge for which the map is not
360+
# invertible, the constraint primal cannot be inverted
345361
_runtests_error_handler(
346362
err,
347363
Bridge <: MOI.Bridges.Constraint.AbstractBridge &&
@@ -354,17 +370,26 @@ function runtests(
354370
end
355371
end
356372
end
357-
# Test other bridge functions
358-
for b in values(Constraint.bridges(model))
359-
_general_bridge_tests(something(b))
360-
end
361-
for b in values(Objective.bridges(model))
362-
_general_bridge_tests(something(b))
373+
Test.@testset "Test general bridge tests" begin
374+
Test.@testset "Constraint" begin
375+
for b in values(Constraint.bridges(model))
376+
_general_bridge_tests(something(b))
377+
end
378+
end
379+
Test.@testset "Objective" begin
380+
for b in values(Objective.bridges(model))
381+
_general_bridge_tests(something(b))
382+
end
383+
end
384+
Test.@testset "Variable" begin
385+
for b in values(Variable.bridges(model))
386+
_general_bridge_tests(something(b))
387+
end
388+
end
363389
end
364-
for b in values(Variable.bridges(model))
365-
_general_bridge_tests(something(b))
390+
Test.@testset "Test delete" begin
391+
_test_delete(Bridge, model, inner)
366392
end
367-
_test_delete(Bridge, model, inner)
368393
return
369394
end
370395

@@ -385,7 +410,7 @@ Run a series of tests that check the correctness of `Bridge`.
385410
386411
## Example
387412
388-
```jldoctest; setup=:(import MathOptInterface as MOI)
413+
```jldoctest; setup=:(import MathOptInterface as MOI), filter="[0-9.]+s"
389414
julia> MOI.Bridges.runtests(
390415
MOI.Bridges.Constraint.ZeroOneBridge,
391416
\"\"\"
@@ -398,6 +423,8 @@ julia> MOI.Bridges.runtests(
398423
1.0 * x in Interval(0.0, 1.0)
399424
\"\"\",
400425
)
426+
Test Summary: | Pass Total Time
427+
Bridges.runtests | 32 32 0.0s
401428
```
402429
"""
403430
function runtests(

0 commit comments

Comments
 (0)