diff --git a/src/Bridges/Variable/bridges/ParameterToEqualToBridge.jl b/src/Bridges/Variable/bridges/ParameterToEqualToBridge.jl index be6bad31c6..d740e61033 100644 --- a/src/Bridges/Variable/bridges/ParameterToEqualToBridge.jl +++ b/src/Bridges/Variable/bridges/ParameterToEqualToBridge.jl @@ -23,121 +23,38 @@ * One variable node: [`MOI.VariableIndex`](@ref) in [`MOI.EqualTo{T}`](@ref) """ -struct ParameterToEqualToBridge{T} <: AbstractBridge - x::MOI.VariableIndex - ci::MOI.ConstraintIndex{MOI.VariableIndex,MOI.EqualTo{T}} +struct ParameterToEqualToBridge{T} <: + SetMapBridge{T,MOI.EqualTo{T},MOI.Parameter{T}} + variable::MOI.VariableIndex + constraint::MOI.ConstraintIndex{MOI.VariableIndex,MOI.EqualTo{T}} end const ParameterToEqualTo{T,OT<:MOI.ModelLike} = SingleBridgeOptimizer{ParameterToEqualToBridge{T},OT} -function bridge_constrained_variable( - ::Type{ParameterToEqualToBridge{T}}, - model::MOI.ModelLike, - set::MOI.Parameter{T}, -) where {T} - x, ci = MOI.add_constrained_variable(model, MOI.EqualTo(set.value)) - return ParameterToEqualToBridge{T}(x, ci) -end - -function supports_constrained_variable( - ::Type{ParameterToEqualToBridge{T}}, - ::Type{MOI.Parameter{T}}, -) where {T} - return true -end - -function MOI.Bridges.added_constrained_variable_types( - ::Type{ParameterToEqualToBridge{T}}, -) where {T} - return Tuple{Type}[(MOI.EqualTo{T},)] -end - -function MOI.Bridges.added_constraint_types(::Type{<:ParameterToEqualToBridge}) - return Tuple{Type,Type}[] -end - -MOI.get(bridge::ParameterToEqualToBridge, ::MOI.NumberOfVariables)::Int64 = 1 - -function MOI.get(bridge::ParameterToEqualToBridge, ::MOI.ListOfVariableIndices) - return [bridge.x] -end - -function MOI.get( - ::ParameterToEqualToBridge{T}, - ::MOI.NumberOfConstraints{MOI.VariableIndex,MOI.EqualTo{T}}, -)::Int64 where {T} - return 1 -end - -function MOI.get( - bridge::ParameterToEqualToBridge{T}, - ::MOI.ListOfConstraintIndices{MOI.VariableIndex,MOI.EqualTo{T}}, +function MOI.Bridges.map_set( + ::Type{<:ParameterToEqualToBridge{T}}, + set::MOI.EqualTo{T}, ) where {T} - return [bridge.ci] + return MOI.Parameter{T}(set.value) end -function MOI.delete(model::MOI.ModelLike, bridge::ParameterToEqualToBridge) - MOI.delete(model, bridge.x) - return -end - -function MOI.get( - model::MOI.ModelLike, - ::MOI.ConstraintSet, - bridge::ParameterToEqualToBridge{T}, +function MOI.Bridges.inverse_map_set( + ::Type{<:ParameterToEqualToBridge{T}}, + set::MOI.Parameter{T}, ) where {T} - set = MOI.get(model, MOI.ConstraintSet(), bridge.ci) - return MOI.Parameter(set.value) + return MOI.EqualTo{T}(set.value) end -function MOI.get( - model::MOI.ModelLike, - attr::Union{MOI.ConstraintFunction,MOI.ConstraintPrimal,MOI.ConstraintDual}, - bridge::ParameterToEqualToBridge, -) - return MOI.get(model, attr, bridge.ci) -end +MOI.Bridges.map_function(::Type{<:ParameterToEqualToBridge}, f) = f -function _to_one(::Type{T}, x) where {T} - return MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(one(T), x)], zero(T)) -end +MOI.Bridges.inverse_map_function(::Type{<:ParameterToEqualToBridge}, f) = f -function MOI.Bridges.bridged_function( - bridge::ParameterToEqualToBridge{T}, -) where {T} - return _to_one(T, bridge.x) -end +MOI.Bridges.adjoint_map_function(::Type{<:ParameterToEqualToBridge}, f) = f -function unbridged_map( - bridge::ParameterToEqualToBridge{T}, - x::MOI.VariableIndex, -) where {T} - return [bridge.x => _to_one(T, x)] -end - -function MOI.supports( - model::MOI.ModelLike, - attr::MOI.VariablePrimalStart, +function MOI.Bridges.inverse_adjoint_map_function( ::Type{<:ParameterToEqualToBridge}, + f, ) - return MOI.supports(model, attr, MOI.VariableIndex) -end - -function MOI.get( - model::MOI.ModelLike, - attr::Union{MOI.VariablePrimal,MOI.VariablePrimalStart}, - bridge::ParameterToEqualToBridge, -) - return MOI.get(model, attr, bridge.x) -end - -function MOI.set( - model::MOI.ModelLike, - attr::MOI.VariablePrimalStart, - bridge::ParameterToEqualToBridge, - value, -) - MOI.set(model, attr, bridge.x, value) - return + return f end diff --git a/src/Bridges/Variable/map.jl b/src/Bridges/Variable/map.jl index 842025107e..cbdd1dc73a 100644 --- a/src/Bridges/Variable/map.jl +++ b/src/Bridges/Variable/map.jl @@ -282,6 +282,7 @@ is set by this constraint and such bound has already been set for `vi`. """ function MOI.add_constraint(::Map, ::MOI.VariableIndex, ::MOI.AbstractScalarSet) # Nothing to do as this is not recognized as setting a lower or upper bound + return end # We cannot use `SUPPORTED_VARIABLE_SCALAR_SETS` because @@ -321,6 +322,7 @@ function MOI.delete( ci::MOI.ConstraintIndex{MOI.VariableIndex,<:MOI.AbstractScalarSet}, ) # Nothing to do as this is not recognized as setting a lower or upper bound + return end function MOI.delete( diff --git a/src/Bridges/Variable/set_map.jl b/src/Bridges/Variable/set_map.jl index 653a7f1c25..21c9af8105 100644 --- a/src/Bridges/Variable/set_map.jl +++ b/src/Bridges/Variable/set_map.jl @@ -30,24 +30,31 @@ for the following functions must be implemented: See the docstrings of each function to see which feature would be missing if it was not implemented for a given bridge. -""" -abstract type SetMapBridge{T,S1,S2} <: AbstractBridge end -function _add_constrained_var(model, set::MOI.AbstractScalarSet) - return MOI.add_constrained_variable(model, set) -end +## Fieldnames -function _add_constrained_var(model, set::MOI.AbstractVectorSet) - return MOI.add_constrained_variables(model, set) -end +If `S1` and `S2` are [`MOI.AbstractScalarSet`], the struct must have fields: + + * `variable::MOI.VariableIndex` + * `constraint::MOI.ConstraintIndex{MOI.VariableIndex,S1}` + +If `S1` and `S2` are [`MOI.AbstractVectorSet`], the struct must have fields: + + * `variable::Vector{MOI.VariableIndex}` + * `constraint::MOI.ConstraintIndex{MOI.VectorOfVariables,S1}` +""" +abstract type SetMapBridge{T,S1,S2} <: AbstractBridge end function bridge_constrained_variable( BT::Type{<:SetMapBridge{T,S1,S2}}, model::MOI.ModelLike, set::S2, ) where {T,S1,S2} - variables, constraint = - _add_constrained_var(model, MOI.Bridges.inverse_map_set(BT, set)) + # In a Variable.SetMapBridge: + # map_set goes from Bridge -> User + # inverse_map_set goes from User -> Bridge + new_set = MOI.Bridges.inverse_map_set(BT, set) + variables, constraint = _add_constrained_var(model, new_set) return BT(variables, constraint) end @@ -68,26 +75,143 @@ function MOI.Bridges.added_constraint_types(::Type{<:SetMapBridge}) return Tuple{Type,Type}[] end -# Attributes, Bridge acting as a model -function MOI.get(bridge::SetMapBridge, ::MOI.NumberOfVariables)::Int64 - return length(bridge.variables) +function MOI.get( + model::MOI.ModelLike, + attr::Union{ + MOI.ConstraintFunction, + MOI.ConstraintPrimal, + MOI.ConstraintPrimalStart, + }, + bridge::SetMapBridge, +) + value = MOI.get(model, attr, bridge.constraint) + if value === nothing + return + end + # In a Variable.SetMapBridge: + # map_function goes from Bridge -> User + # inverse_map_function goes from User -> Bridge + return MOI.Bridges.map_function(bridge, value) end -function MOI.get(bridge::SetMapBridge, ::MOI.ListOfVariableIndices) - return copy(bridge.variables) +function MOI.set( + model::MOI.ModelLike, + attr::MOI.ConstraintPrimalStart, + bridge::SetMapBridge, + value, +) + if value === nothing + MOI.set(model, attr, bridge.constraint, nothing) + return + end + # In a Variable.SetMapBridge: + # map_function goes from Bridge -> User + # inverse_map_function goes from User -> Bridge + bridged_value = MOI.Bridges.inverse_map_function(bridge, value) + MOI.set(model, attr, bridge.constraint, bridged_value) + return end function MOI.get( - ::SetMapBridge{T,S1}, - ::MOI.NumberOfConstraints{MOI.VariableIndex,S1}, -)::Int64 where {T,S1<:MOI.AbstractScalarSet} + model::MOI.ModelLike, + attr::MOI.ConstraintSet, + bridge::SetMapBridge, +) + set = MOI.get(model, attr, bridge.constraint) + # In a Variable.SetMapBridge: + # map_set goes from Bridge -> User + # inverse_map_set goes from User -> Bridge + return MOI.Bridges.map_set(bridge, set) +end + +function MOI.set( + model::MOI.ModelLike, + attr::MOI.ConstraintSet, + bridge::SetMapBridge{T,S1}, + set::S1, +) where {T,S1} + # In a Variable.SetMapBridge: + # map_set goes from Bridge -> User + # inverse_map_set goes from User -> Bridge + mapped_set = MOI.Bridges.inverse_map_set(bridge, set) + MOI.set(model, attr, bridge.constraint, mapped_set) + return +end + +function MOI.get( + model::MOI.ModelLike, + attr::Union{MOI.ConstraintDual,MOI.ConstraintDualStart}, + bridge::SetMapBridge, +) + value = MOI.get(model, attr, bridge.constraint) + if value === nothing + return + end + # In a Variable.SetMapBridge: + # inverse_adjoint_map_function goes from Bridge -> User + # adjoint_map_function goes from User -> Bridge + return MOI.Bridges.inverse_adjoint_map_function(bridge, value) +end + +function MOI.set( + model::MOI.ModelLike, + attr::MOI.ConstraintDualStart, + bridge::SetMapBridge, + value, +) + if value === nothing + MOI.set(model, attr, bridge.constraint, nothing) + return + end + # In a Variable.SetMapBridge: + # inverse_adjoint_map_function goes from Bridge -> User + # adjoint_map_function goes from User -> Bridge + bridged_value = MOI.Bridges.adjoint_map_function(bridge, value) + MOI.set(model, attr, bridge.constraint, bridged_value) + return +end + +function MOI.supports( + model::MOI.ModelLike, + attr::MOI.VariablePrimalStart, + ::Type{<:SetMapBridge}, +) + return MOI.supports(model, attr, MOI.VariableIndex) +end + +function unbridged_map(bridge::SetMapBridge{T}, vi::MOI.VariableIndex) where {T} + F = MOI.ScalarAffineFunction{T} + # In a Variable.SetMapBridge: + # map_function goes from Bridge -> User + # inverse_map_function goes from User -> Bridge + mapped = MOI.Bridges.inverse_map_function(bridge, vi) + return Pair{MOI.VariableIndex,F}[bridge.variable=>mapped] +end + +# MOI.AbstractScalarSet + +function _add_constrained_var(model, set::MOI.AbstractScalarSet) + return MOI.add_constrained_variable(model, set) +end + +function MOI.get( + ::SetMapBridge{T,S1,<:MOI.AbstractScalarSet}, + ::MOI.NumberOfVariables, +)::Int64 where {T,S1} return 1 end +function MOI.get( + bridge::SetMapBridge{T,S1,<:MOI.AbstractScalarSet}, + ::MOI.ListOfVariableIndices, +) where {T,S1} + return [bridge.variable] +end + function MOI.get( ::SetMapBridge{T,S1}, - ::MOI.NumberOfConstraints{MOI.VectorOfVariables,S1}, -)::Int64 where {T,S1<:MOI.AbstractVectorSet} + ::MOI.NumberOfConstraints{MOI.VariableIndex,S1}, +)::Int64 where {T,S1<:MOI.AbstractScalarSet} return 1 end @@ -98,14 +222,6 @@ function MOI.get( return [bridge.constraint] end -function MOI.get( - bridge::SetMapBridge{T,S1}, - ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables,S1}, -) where {T,S1<:MOI.AbstractVectorSet} - return [bridge.constraint] -end - -# References function MOI.delete( model::MOI.ModelLike, bridge::SetMapBridge{T,S1,S2}, @@ -114,52 +230,88 @@ function MOI.delete( return end -function MOI.delete( - model::MOI.ModelLike, - bridge::SetMapBridge{T,S1,S2}, -) where {T,S1,S2<:MOI.AbstractVectorSet} - MOI.delete(model, bridge.variables) - return +function MOI.Bridges.bridged_function( + bridge::SetMapBridge{T,<:MOI.AbstractScalarSet}, +) where {T} + func = MOI.Bridges.map_function(bridge, bridge.variable) + return convert(MOI.ScalarAffineFunction{T}, func) end -# Attributes, Bridge acting as a constraint - function MOI.get( model::MOI.ModelLike, - attr::MOI.ConstraintSet, + attr::Union{MOI.VariablePrimal,MOI.VariablePrimalStart}, bridge::SetMapBridge, ) - set = MOI.get(model, attr, bridge.constraint) - return MOI.Bridges.map_set(bridge, set) + value = MOI.get(model, attr, bridge.variable) + if value === nothing + return + end + # In a Variable.SetMapBridge: + # map_function goes from Bridge -> User + # inverse_map_function goes from User -> Bridge + return MOI.Bridges.map_function(bridge, value) end function MOI.set( model::MOI.ModelLike, - attr::MOI.ConstraintSet, - bridge::SetMapBridge{T,S1}, - set::S1, -) where {T,S1} - mapped = MOI.Bridges.inverse_map_set(typeof(bridge), set) - MOI.set(model, attr, bridge.constraint, mapped) + attr::MOI.VariablePrimalStart, + bridge::SetMapBridge, + value, +) + if value === nothing + MOI.set(model, attr, bridge.variable, nothing) + return + end + # In a Variable.SetMapBridge: + # map_function goes from Bridge -> User + # inverse_map_function goes from User -> Bridge + bridged_value = MOI.Bridges.inverse_map_function(bridge, value) + MOI.set(model, attr, bridge.variable, bridged_value) return end -function MOI.get( +function MOI.supports( model::MOI.ModelLike, - attr::MOI.ConstraintPrimal, - bridge::SetMapBridge, -) - value = MOI.get(model, attr, bridge.constraint) - return MOI.Bridges.map_function(bridge, value) + attr::Union{MOI.ConstraintPrimalStart,MOI.ConstraintDualStart}, + ::Type{<:SetMapBridge{T,S1}}, +) where {T,S1<:MOI.AbstractScalarSet} + return MOI.supports(model, attr, MOI.ConstraintIndex{MOI.VariableIndex,S1}) +end + +# MOI.AbstractVectorSet + +function _add_constrained_var(model, set::MOI.AbstractVectorSet) + return MOI.add_constrained_variables(model, set) +end + +function MOI.get(bridge::SetMapBridge, ::MOI.NumberOfVariables)::Int64 + return length(bridge.variables) +end + +function MOI.get(bridge::SetMapBridge, ::MOI.ListOfVariableIndices) + return copy(bridge.variables) end function MOI.get( + ::SetMapBridge{T,S1}, + ::MOI.NumberOfConstraints{MOI.VectorOfVariables,S1}, +)::Int64 where {T,S1<:MOI.AbstractVectorSet} + return 1 +end + +function MOI.get( + bridge::SetMapBridge{T,S1}, + ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables,S1}, +) where {T,S1<:MOI.AbstractVectorSet} + return [bridge.constraint] +end + +function MOI.delete( model::MOI.ModelLike, - attr::MOI.ConstraintDual, - bridge::SetMapBridge, -) - value = MOI.get(model, attr, bridge.constraint) - return MOI.Bridges.inverse_adjoint_map_function(typeof(bridge), value) + bridge::SetMapBridge{T,S1,S2}, +) where {T,S1,S2<:MOI.AbstractVectorSet} + MOI.delete(model, bridge.variables) + return end function MOI.get( @@ -170,19 +322,14 @@ function MOI.get( ) value = MOI.get(model, attr, bridge.variables) if any(isnothing, value) - return nothing + return end + # In a Variable.SetMapBridge: + # map_function goes from Bridge -> User + # inverse_map_function goes from User -> Bridge return MOI.Bridges.map_function(bridge, value, i) end -function MOI.supports( - model::MOI.ModelLike, - attr::MOI.VariablePrimalStart, - ::Type{<:SetMapBridge}, -) - return MOI.supports(model, attr, MOI.VariableIndex) -end - function MOI.set( model::MOI.ModelLike, attr::MOI.VariablePrimalStart, @@ -192,37 +339,43 @@ function MOI.set( ) if value === nothing MOI.set(model, attr, bridge.variables[i.value], nothing) - else - bridged_value = MOI.Bridges.inverse_map_function(bridge, value) - MOI.set(model, attr, bridge.variables[i.value], bridged_value) + return end + # In a Variable.SetMapBridge: + # map_function goes from Bridge -> User + # inverse_map_function goes from User -> Bridge + bridged_value = MOI.Bridges.inverse_map_function(bridge, value) + MOI.set(model, attr, bridge.variables[i.value], bridged_value) return end +function MOI.supports( + model::MOI.ModelLike, + attr::Union{MOI.ConstraintPrimalStart,MOI.ConstraintDualStart}, + ::Type{<:SetMapBridge{T,S1}}, +) where {T,S1<:MOI.AbstractVectorSet} + CI = MOI.ConstraintIndex{MOI.VectorOfVariables,S1} + return MOI.supports(model, attr, CI) +end + function MOI.Bridges.bridged_function( bridge::SetMapBridge{T}, i::MOI.Bridges.IndexInVector, ) where {T} - func = MOI.Bridges.map_function( - bridge, - MOI.VectorOfVariables(bridge.variables), - i, - ) + f = MOI.VectorOfVariables(bridge.variables) + func = MOI.Bridges.map_function(bridge, f, i) return convert(MOI.ScalarAffineFunction{T}, func) end -function unbridged_map(bridge::SetMapBridge{T}, vi::MOI.VariableIndex) where {T} - F = MOI.ScalarAffineFunction{T} - mapped = MOI.Bridges.inverse_map_function(bridge, vi) - return Pair{MOI.VariableIndex,F}[bridge.variable=>mapped] -end - function unbridged_map( bridge::SetMapBridge{T}, vis::Vector{MOI.VariableIndex}, ) where {T} F = MOI.ScalarAffineFunction{T} func = MOI.VectorOfVariables(vis) + # In a Variable.SetMapBridge: + # map_function goes from Bridge -> User + # inverse_map_function goes from User -> Bridge funcs = MOI.Bridges.inverse_map_function(bridge, func) scalars = MOI.Utilities.eachscalar(funcs) # FIXME not correct for SetDotProducts, it won't recover the dot product variables diff --git a/test/Bridges/Variable/ParameterToEqualToBridge.jl b/test/Bridges/Variable/ParameterToEqualToBridge.jl index 872ee11298..d394ecc10d 100644 --- a/test/Bridges/Variable/ParameterToEqualToBridge.jl +++ b/test/Bridges/Variable/ParameterToEqualToBridge.jl @@ -8,8 +8,7 @@ module TestVariableParameter using Test -using MathOptInterface -const MOI = MathOptInterface +import MathOptInterface as MOI function runtests() for name in names(@__MODULE__; all = true) @@ -81,6 +80,42 @@ function test_list_of_constraint_indices() return end +function test_VariablePrimalStart() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + model = MOI.Bridges.Variable.ParameterToEqualTo{Float64}(inner) + x, ci = MOI.add_constrained_variable(model, MOI.Parameter(2.0)) + @test MOI.supports(model, MOI.VariablePrimalStart(), MOI.VariableIndex) + MOI.set(model, MOI.VariablePrimalStart(), x, 2.0) + @test MOI.get(model, MOI.VariablePrimalStart(), x) == 2.0 + MOI.set(model, MOI.VariablePrimalStart(), x, nothing) + @test MOI.get(model, MOI.VariablePrimalStart(), x) === nothing + return +end + +function test_ConstraintPrimalStart() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + model = MOI.Bridges.Variable.ParameterToEqualTo{Float64}(inner) + x, ci = MOI.add_constrained_variable(model, MOI.Parameter(2.0)) + @test MOI.supports(model, MOI.ConstraintPrimalStart(), typeof(ci)) + MOI.set(model, MOI.ConstraintPrimalStart(), ci, 2.0) + @test MOI.get(model, MOI.ConstraintPrimalStart(), ci) == 2.0 + MOI.set(model, MOI.ConstraintPrimalStart(), ci, nothing) + @test MOI.get(model, MOI.ConstraintPrimalStart(), ci) === nothing + return +end + +function test_ConstraintDualStart() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + model = MOI.Bridges.Variable.ParameterToEqualTo{Float64}(inner) + x, ci = MOI.add_constrained_variable(model, MOI.Parameter(2.0)) + @test MOI.supports(model, MOI.ConstraintDualStart(), typeof(ci)) + MOI.set(model, MOI.ConstraintDualStart(), ci, 2.0) + @test MOI.get(model, MOI.ConstraintDualStart(), ci) == 2.0 + MOI.set(model, MOI.ConstraintDualStart(), ci, nothing) + @test MOI.get(model, MOI.ConstraintDualStart(), ci) === nothing + return +end + end # module TestVariableParameter.runtests() diff --git a/test/Bridges/Variable/RSOCtoSOCBridge.jl b/test/Bridges/Variable/RSOCtoSOCBridge.jl index 695e9c28a4..ca397beb6c 100644 --- a/test/Bridges/Variable/RSOCtoSOCBridge.jl +++ b/test/Bridges/Variable/RSOCtoSOCBridge.jl @@ -153,6 +153,30 @@ function test_adjoint_map_function() return end +function test_ConstraintPrimalStart() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + model = MOI.Bridges.Variable.RSOCtoSOC{Float64}(inner) + x, ci = MOI.add_constrained_variables(model, MOI.RotatedSecondOrderCone(3)) + @test MOI.supports(model, MOI.ConstraintPrimalStart(), typeof(ci)) + MOI.set(model, MOI.ConstraintPrimalStart(), ci, [2, 0.5, 1]) + @test MOI.get(model, MOI.ConstraintPrimalStart(), ci) ≈ [2, 0.5, 1] + MOI.set(model, MOI.ConstraintPrimalStart(), ci, nothing) + @test MOI.get(model, MOI.ConstraintPrimalStart(), ci) === nothing + return +end + +function test_ConstraintDualStart() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + model = MOI.Bridges.Variable.RSOCtoSOC{Float64}(inner) + x, ci = MOI.add_constrained_variables(model, MOI.RotatedSecondOrderCone(3)) + @test MOI.supports(model, MOI.ConstraintDualStart(), typeof(ci)) + MOI.set(model, MOI.ConstraintDualStart(), ci, [2, 0.5, 1]) + @test MOI.get(model, MOI.ConstraintDualStart(), ci) ≈ [2, 0.5, 1] + MOI.set(model, MOI.ConstraintDualStart(), ci, nothing) + @test MOI.get(model, MOI.ConstraintDualStart(), ci) === nothing + return +end + end # module TestVariableRSOCtoSOC.runtests() diff --git a/test/Bridges/Variable/SOCtoRSOCBridge.jl b/test/Bridges/Variable/SOCtoRSOCBridge.jl index 59388e51aa..788a709eda 100644 --- a/test/Bridges/Variable/SOCtoRSOCBridge.jl +++ b/test/Bridges/Variable/SOCtoRSOCBridge.jl @@ -160,6 +160,30 @@ function test_adjoint_map_function() return end +function test_ConstraintPrimalStart() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + model = MOI.Bridges.Variable.SOCtoRSOC{Float64}(inner) + x, ci = MOI.add_constrained_variables(model, MOI.SecondOrderCone(3)) + @test MOI.supports(model, MOI.ConstraintPrimalStart(), typeof(ci)) + MOI.set(model, MOI.ConstraintPrimalStart(), ci, [2, 0.5, 1]) + @test MOI.get(model, MOI.ConstraintPrimalStart(), ci) ≈ [2, 0.5, 1] + MOI.set(model, MOI.ConstraintPrimalStart(), ci, nothing) + @test MOI.get(model, MOI.ConstraintPrimalStart(), ci) === nothing + return +end + +function test_ConstraintDualStart() + inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}()) + model = MOI.Bridges.Variable.SOCtoRSOC{Float64}(inner) + x, ci = MOI.add_constrained_variables(model, MOI.SecondOrderCone(3)) + @test MOI.supports(model, MOI.ConstraintDualStart(), typeof(ci)) + MOI.set(model, MOI.ConstraintDualStart(), ci, [2, 0.5, 1]) + @test MOI.get(model, MOI.ConstraintDualStart(), ci) ≈ [2, 0.5, 1] + MOI.set(model, MOI.ConstraintDualStart(), ci, nothing) + @test MOI.get(model, MOI.ConstraintDualStart(), ci) === nothing + return +end + end # module TestVariableSOCtoRSOC.runtests() diff --git a/test/Bridges/bridge_optimizer.jl b/test/Bridges/bridge_optimizer.jl index faf7af6b9c..f028340a4e 100644 --- a/test/Bridges/bridge_optimizer.jl +++ b/test/Bridges/bridge_optimizer.jl @@ -726,6 +726,18 @@ function test_recursive_model_variable(::Type{T} = Int) where {T} @test MOI.is_valid(b, x) MOI.delete(b, x) @test !MOI.is_valid(b, x) + MOI.Bridges.runtests( + IdentityBridges.VariableBridge, + """ + constrainedvariable: x in EqualTo(1.0) + minobjective: 1.0 * x + 2.0 + """, + """ + constrainedvariable: x in EqualTo(1.0) + minobjective: 1.0 * x + 2.0 + """, + ) + return end function test_recursive_model_constraint(::Type{T} = Int) where {T} @@ -928,11 +940,7 @@ function test_bridge_supports_issue_1992() MOI.VectorOfVariables([x]), MOI.Nonpositives(1), ) - # !!! warning - # This test is broken with a false negative. (Getting and setting the - # attribute works, even though supports is false) See the discussion in - # PR#1992. - @test_broken MOI.supports(model, MOI.ConstraintDualStart(), typeof(c)) + @test MOI.supports(model, MOI.ConstraintDualStart(), typeof(c)) @test MOI.get(model, MOI.ConstraintDualStart(), c) === nothing MOI.set(model, MOI.ConstraintDualStart(), c, [1.0]) @test MOI.get(model, MOI.ConstraintDualStart(), c) == [1.0] diff --git a/test/Bridges/set_map.jl b/test/Bridges/set_map.jl index cc64cb18ed..612d209a24 100644 --- a/test/Bridges/set_map.jl +++ b/test/Bridges/set_map.jl @@ -57,7 +57,7 @@ function MOI.Bridges.map_function( end # Workaround until https://github.com/jump-dev/MathOptInterface.jl/issues/2117 is fixed -MOI.Bridges.inverse_map_function(::VariableSwapBridge, a::Float64) = a +MOI.Bridges.inverse_map_function(::VariableSwapBridge, a) = a struct ConstraintSwapBridge{T} <: MOI.Bridges.Constraint.SetMapBridge{ T,