diff --git a/src/Bridges/Bridges.jl b/src/Bridges/Bridges.jl index 119007c243..32b4da2948 100644 --- a/src/Bridges/Bridges.jl +++ b/src/Bridges/Bridges.jl @@ -144,7 +144,11 @@ MOI.get_fallback(model::MOI.ModelLike, ::ListOfNonstandardBridges) = Type[] include("precompile.jl") -function _test_structural_identical(a::MOI.ModelLike, b::MOI.ModelLike) +function _test_structural_identical( + a::MOI.ModelLike, + b::MOI.ModelLike; + cannot_unbridge::Bool = false, +) # Test that the variables are the same. We make the strong assumption that # the variables are added in the same order to both models. a_x = MOI.get(a, MOI.ListOfVariableIndices()) @@ -190,7 +194,16 @@ function _test_structural_identical(a::MOI.ModelLike, b::MOI.ModelLike) Test.@test MOI.supports_constraint(b, F, S) # Check that each function in `b` matches a function in `a` for ci in MOI.get(b, MOI.ListOfConstraintIndices{F,S}()) - f_b = MOI.get(b, MOI.ConstraintFunction(), ci) + f_b = try + MOI.get(b, MOI.ConstraintFunction(), ci) + catch err + if cannot_unbridge && + err isa MOI.GetAttributeNotAllowed{MOI.ConstraintFunction} + continue + else + rethrow(err) + end + end f_b = MOI.Utilities.map_indices(x_map, f_b) s_b = MOI.get(b, MOI.ConstraintSet(), ci) # We don't care about the order that constraints are added, only @@ -225,6 +238,7 @@ end variable_start = 1.2, constraint_start = 1.2, eltype = Float64, + cannot_unbridge::Bool = false, ) Run a series of tests that check the correctness of `Bridge`. @@ -232,6 +246,10 @@ Run a series of tests that check the correctness of `Bridge`. `input_fn` and `output_fn` are functions such that `input_fn(model)` and `output_fn(model)` load the corresponding model into `model`. +Set `cannot_unbridge` to `true` if the bridge is a variable bridge +for which [`Variable.unbridged_map`](@ref) returns `nothing` so that +the tests allow errors that can be raised due to this. + ## Example ```jldoctest; setup=:(import MathOptInterface as MOI) @@ -253,6 +271,7 @@ function runtests( constraint_start = 1.2, eltype = Float64, print_inner_model::Bool = false, + cannot_unbridge::Bool = false, ) # Load model and bridge it inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{eltype}()) @@ -267,7 +286,7 @@ function runtests( # Load a non-bridged input model, and check that getters are the same. test = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{eltype}()) input_fn(test) - _test_structural_identical(test, model) + _test_structural_identical(test, model; cannot_unbridge = cannot_unbridge) # Load a bridged target model, and check that getters are the same. target = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{eltype}()) output_fn(target) @@ -291,7 +310,17 @@ function runtests( # Test ConstraintPrimalStart and ConstraintDualStart for (F, S) in MOI.get(model, MOI.ListOfConstraintTypesPresent()) for ci in MOI.get(model, MOI.ListOfConstraintIndices{F,S}()) - set = MOI.get(model, MOI.ConstraintSet(), ci) + set = try + MOI.get(model, MOI.ConstraintSet(), ci) + catch err + # Could be thrown by `unbridged_function` + if cannot_unbridge && + err isa MOI.GetAttributeNotAllowed{MOI.ConstraintFunction} + continue + else + rethrow(err) + end + end for attr in (MOI.ConstraintPrimalStart(), MOI.ConstraintDualStart()) if MOI.supports(model, attr, MOI.ConstraintIndex{F,S}) MOI.set(model, attr, ci, nothing) diff --git a/test/Bridges/Variable/zeros.jl b/test/Bridges/Variable/zeros.jl index 923bc868b0..7dad8da30c 100644 --- a/test/Bridges/Variable/zeros.jl +++ b/test/Bridges/Variable/zeros.jl @@ -23,6 +23,29 @@ end include("../utilities.jl") +function test_runtests() + MOI.Bridges.runtests( + MOI.Bridges.Variable.ZerosBridge, + model -> begin + x, _ = MOI.add_constrained_variables(model, MOI.Zeros(2)) + MOI.add_constraint( + model, + 1.0 * x[1] + 2.0 * x[2], + MOI.EqualTo(3.0), + ) + end, + model -> begin + MOI.add_constraint( + model, + zero(MOI.ScalarAffineFunction{Float64}), + MOI.EqualTo(3.0), + ) + end; + cannot_unbridge = true, + ) + return +end + function test_zeros() mock = MOI.Utilities.MockOptimizer(MOI.Utilities.Model{Float64}()) bridged_mock = MOI.Bridges.Variable.Zeros{Float64}(mock)