diff --git a/src/Bridges/Constraint/bridges/AbstractToIntervalBridge.jl b/src/Bridges/Constraint/bridges/AbstractToIntervalBridge.jl index f486d3a697..da3b0e2533 100644 --- a/src/Bridges/Constraint/bridges/AbstractToIntervalBridge.jl +++ b/src/Bridges/Constraint/bridges/AbstractToIntervalBridge.jl @@ -38,7 +38,7 @@ end function MOI.modify( model::MOI.ModelLike, bridge::AbstractToIntervalBridge, - change::MOI.ScalarCoefficientChange, + change::Union{MOI.ScalarConstantChange,MOI.ScalarCoefficientChange}, ) MOI.modify(model, bridge.constraint, change) return diff --git a/src/Bridges/Constraint/bridges/FlipSignBridge.jl b/src/Bridges/Constraint/bridges/FlipSignBridge.jl index 463a11b9f7..bda37b7294 100644 --- a/src/Bridges/Constraint/bridges/FlipSignBridge.jl +++ b/src/Bridges/Constraint/bridges/FlipSignBridge.jl @@ -67,6 +67,16 @@ function MOI.modify( return end +function MOI.modify( + model::MOI.ModelLike, + bridge::FlipSignBridge, + change::MOI.ScalarConstantChange, +) + new_change = MOI.ScalarConstantChange(-change.new_constant) + MOI.modify(model, bridge.constraint, new_change) + return +end + function MOI.modify( model::MOI.ModelLike, bridge::FlipSignBridge, @@ -83,6 +93,16 @@ function MOI.modify( return end +function MOI.modify( + model::MOI.ModelLike, + bridge::FlipSignBridge, + change::MOI.VectorConstantChange, +) + new_change = MOI.VectorConstantChange(-change.new_constant) + MOI.modify(model, bridge.constraint, new_change) + return +end + """ GreaterToLessBridge{T,F,G} <: Bridges.Constraint.AbstractBridge diff --git a/src/Bridges/Constraint/bridges/NormSpecialCaseBridge.jl b/src/Bridges/Constraint/bridges/NormSpecialCaseBridge.jl index de6bc7a0fe..0af8574b2a 100644 --- a/src/Bridges/Constraint/bridges/NormSpecialCaseBridge.jl +++ b/src/Bridges/Constraint/bridges/NormSpecialCaseBridge.jl @@ -38,6 +38,15 @@ function concrete_bridge_type( return NormSpecialCaseBridge{S,T,F} end +function MOI.modify( + model::MOI.ModelLike, + bridge::NormSpecialCaseBridge, + change::Union{MOI.VectorConstantChange,MOI.MultirowChange}, +) + MOI.modify(model, bridge.constraint, change) + return +end + """ NormOneConeToNormConeBridge{T,F} <: Bridges.Constraint.AbstractBridge diff --git a/src/Bridges/Constraint/set_map.jl b/src/Bridges/Constraint/set_map.jl index fed3e8f0d7..70062db687 100644 --- a/src/Bridges/Constraint/set_map.jl +++ b/src/Bridges/Constraint/set_map.jl @@ -226,60 +226,6 @@ function MOI.set( return end -# By linearity of the map, we can just change the constant/coefficient - -function MOI.modify( - model::MOI.ModelLike, - bridge::BT, - change::MOI.ScalarConstantChange, -) where {BT<:MultiSetMapBridge} - new_constant = MOI.Bridges.map_function(BT, change.new_constant) - MOI.modify(model, bridge.constraint, MOI.ScalarConstantChange(new_constant)) - return -end - -function MOI.modify( - model::MOI.ModelLike, - bridge::BT, - change::MOI.VectorConstantChange, -) where {BT<:MultiSetMapBridge} - new_constant = MOI.Bridges.map_function(BT, change.new_constant) - MOI.modify(model, bridge.constraint, MOI.VectorConstantChange(new_constant)) - return -end - -function MOI.modify( - model::MOI.ModelLike, - bridge::BT, - change::MOI.ScalarCoefficientChange, -) where {BT<:MultiSetMapBridge} - new_coefficient = MOI.Bridges.map_function(BT, change.new_coefficient) - new_change = MOI.ScalarCoefficientChange(change.variable, new_coefficient) - MOI.modify(model, bridge.constraint, new_change) - return -end - -function MOI.modify( - model::MOI.ModelLike, - bridge::BT, - change::MOI.MultirowChange{T}, -) where {T,BT<:MultiSetMapBridge{T}} - # It is important here that `change.new_coefficients` contains the complete - # new sparse column associated to the variable. Calling modify twice with - # part of the column won't work since the linear map might reset all the - # column each time. - n = MOI.dimension(MOI.get(model, MOI.ConstraintSet(), bridge.constraint)) - dense = zeros(T, n) - for (row, value) in change.new_coefficients - dense[row] += value - end - map_dense = MOI.Bridges.map_function(BT, dense) - sparse = Tuple{Int64,T}[rv for rv in enumerate(map_dense) if !iszero(rv[2])] - new_change = MOI.MultirowChange(change.variable, sparse) - MOI.modify(model, bridge.constraint, new_change) - return -end - """ abstract type SetMapBridge{T,S2,S1,F,G} <: MultiSetMapBridge{T,S1,G} end diff --git a/test/Bridges/Constraint/test_GreaterToLessBridge.jl b/test/Bridges/Constraint/test_GreaterToLessBridge.jl index 00a8fb577c..001e4f1743 100644 --- a/test/Bridges/Constraint/test_GreaterToLessBridge.jl +++ b/test/Bridges/Constraint/test_GreaterToLessBridge.jl @@ -452,6 +452,47 @@ function test_runtests() return end +function test_GreaterToLess_modify() + inner = MOI.Utilities.Model{Float64}() + model = MOI.Bridges.Constraint.GreaterToLess{Float64}(inner) + x = MOI.add_variable(model) + c = MOI.add_constraint(model, 1.0 * x + 1.0, MOI.GreaterThan(2.0)) + x_inner = only(MOI.get(inner, MOI.ListOfVariableIndices())) + F, S = MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64} + c_inner = only(MOI.get(inner, MOI.ListOfConstraintIndices{F,S}())) + f_inner = MOI.get(inner, MOI.ConstraintFunction(), c_inner) + @test isapprox(f_inner, -1.0 * x_inner - 1.0) + MOI.modify(model, c, MOI.ScalarCoefficientChange(x, -2.0)) + f_inner = MOI.get(inner, MOI.ConstraintFunction(), c_inner) + @test isapprox(f_inner, 2.0 * x_inner - 1.0) + MOI.modify(model, c, MOI.ScalarConstantChange(-3.0)) + f_inner = MOI.get(inner, MOI.ConstraintFunction(), c_inner) + @test isapprox(f_inner, 2.0 * x_inner + 3.0) + @test MOI.get(inner, MOI.ConstraintSet(), c_inner) == MOI.LessThan(-2.0) + return +end + +function test_NonnegToNonpos_modify() + inner = MOI.Utilities.Model{Float64}() + model = MOI.Bridges.Constraint.NonnegToNonpos{Float64}(inner) + x = MOI.add_variable(model) + f = MOI.Utilities.vectorize([1.0 * x + 1.0]) + c = MOI.add_constraint(model, f, MOI.Nonnegatives(1)) + x_inner = only(MOI.get(inner, MOI.ListOfVariableIndices())) + F, S = MOI.VectorAffineFunction{Float64}, MOI.Nonpositives + c_inner = only(MOI.get(inner, MOI.ListOfConstraintIndices{F,S}())) + f_inner = MOI.get(inner, MOI.ConstraintFunction(), c_inner) + @test isapprox(f_inner, MOI.Utilities.vectorize([-1.0 * x_inner - 1.0])) + MOI.modify(model, c, MOI.MultirowChange(x, [(1, -2.0)])) + f_inner = MOI.get(inner, MOI.ConstraintFunction(), c_inner) + @test isapprox(f_inner, MOI.Utilities.vectorize([2.0 * x_inner - 1.0])) + MOI.modify(model, c, MOI.VectorConstantChange([-3.0])) + f_inner = MOI.get(inner, MOI.ConstraintFunction(), c_inner) + @test isapprox(f_inner, MOI.Utilities.vectorize([2.0 * x_inner + 3.0])) + @test MOI.get(inner, MOI.ConstraintSet(), c_inner) == MOI.Nonpositives(1) + return +end + end # module TestConstraintFlipSign.runtests() diff --git a/test/Bridges/General/identity_bridge.jl b/test/Bridges/General/identity_bridge.jl index 830c49f5cc..75e526f30c 100644 --- a/test/Bridges/General/identity_bridge.jl +++ b/test/Bridges/General/identity_bridge.jl @@ -31,6 +31,15 @@ MOI.Bridges.inverse_map_function(::Type{<:IdentityBridge}, func) = func MOI.Bridges.adjoint_map_function(::Type{<:IdentityBridge}, func) = func MOI.Bridges.inverse_adjoint_map_function(::Type{<:IdentityBridge}, func) = func +function MOI.modify( + model::MOI.ModelLike, + bridge::ConstraintBridge, + change::Union{MOI.ScalarConstantChange,MOI.ScalarCoefficientChange}, +) + MOI.modify(model, bridge.constraint, change) + return +end + struct ObjectiveBridge{T} <: MOI.Bridges.Objective.AbstractBridge end function MOI.Bridges.Objective.bridge_objective(