From ce275be1ff1a7720d18d3101708859d342fe5c08 Mon Sep 17 00:00:00 2001 From: odow Date: Fri, 3 Sep 2021 13:17:11 +1200 Subject: [PATCH 1/4] [Bridges] maintenance of slack.jl --- src/Bridges/Constraint/slack.jl | 67 +++++++++++++++++---------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/Bridges/Constraint/slack.jl b/src/Bridges/Constraint/slack.jl index 109a4c74ed..f13ae5d7e2 100644 --- a/src/Bridges/Constraint/slack.jl +++ b/src/Bridges/Constraint/slack.jl @@ -1,12 +1,12 @@ abstract type AbstractSlackBridge{T,VF,ZS,F,S} <: AbstractBridge end -function MOIB.added_constrained_variable_types( +function MOI.Bridges.added_constrained_variable_types( ::Type{<:AbstractSlackBridge{T,VF,ZS,F,S}}, ) where {T,VF,ZS,F,S} return Tuple{Type}[(S,)] end -function MOIB.added_constraint_types( +function MOI.Bridges.added_constraint_types( ::Type{<:AbstractSlackBridge{T,VF,ZS,F}}, ) where {T,VF,ZS,F} return Tuple{Type,Type}[(F, ZS)] @@ -40,20 +40,26 @@ function MOI.get( return [bridge.slack_in_set] end -# Indices function MOI.delete(model::MOI.ModelLike, bridge::AbstractSlackBridge) MOI.delete(model, bridge.equality) MOI.delete(model, bridge.slack) return end -# Attributes, Bridge acting as a constraint function MOI.supports( - ::MOI.ModelLike, - ::Union{MOI.ConstraintPrimalStart,MOI.ConstraintDualStart}, - ::Type{<:AbstractSlackBridge}, -) - return true + model::MOI.ModelLike, + attr::Union{MOI.ConstraintPrimalStart,MOI.ConstraintDualStart}, + ::Type{AbstractSlackBridge{T,VF,ZS,F,S}}, +) where {T,VF,ZS,F,S} + ret = true + if attr isa MOI.ConstraintPrimalStart + ret = MOI.supports(model, MOI.VariablePrimalStart(), MOI.VariableIndex) + end + # .slack_in_set field is {VF,S} + # .equality field is {F,ZS} + return ret && + MOI.supports(model, attr, MOI.ConstraintIndex{VF,S}) && + MOI.supports(model, attr, MOI.ConstraintIndex{F,ZS}) end function MOI.get( @@ -61,7 +67,8 @@ function MOI.get( attr::Union{MOI.ConstraintPrimal,MOI.ConstraintPrimalStart}, bridge::AbstractSlackBridge, ) - # due to equality, slack should have the same value as original affine function + # Due to equality, slack should have the same value as original affine + # function. return MOI.get(model, attr, bridge.slack_in_set) end @@ -150,16 +157,18 @@ end """ ScalarSlackBridge{T, F, S} -The `ScalarSlackBridge` converts a constraint `G`-in-`S` where `G` is a function different -from `VariableIndex` into the constraints `F`-in-`EqualTo{T}` and `VariableIndex`-in-`S`. -`F` is the result of subtracting a `VariableIndex` from `G`. -Typically `G` is the same as `F`, but that is not mandatory. +The `ScalarSlackBridge` converts a constraint `G`-in-`S` where `G` is a function +different from `VariableIndex` into the constraints `F`-in-`EqualTo{T}` and +`VariableIndex`-in-`S`. + +`F` is the result of subtracting a `VariableIndex` from `G`. Typically `G` is +the same as `F`, but that is not mandatory. """ struct ScalarSlackBridge{T,F,S} <: AbstractSlackBridge{T,MOI.VariableIndex,MOI.EqualTo{T},F,S} slack::MOI.VariableIndex - slack_in_set::CI{MOI.VariableIndex,S} - equality::CI{F,MOI.EqualTo{T}} + slack_in_set::MOI.ConstraintIndex{MOI.VariableIndex,S} + equality::MOI.ConstraintIndex{F,MOI.EqualTo{T}} end function bridge_constraint( @@ -216,11 +225,9 @@ function concrete_bridge_type( return ScalarSlackBridge{T,F2,S} end -# Attributes, Bridge acting as a model MOI.get(b::ScalarSlackBridge, ::MOI.NumberOfVariables)::Int64 = 1 MOI.get(b::ScalarSlackBridge, ::MOI.ListOfVariableIndices) = [b.slack] -# Attributes, Bridge acting as a constraint function MOI.get( model::MOI.ModelLike, ::MOI.ConstraintBasisStatus, @@ -265,16 +272,18 @@ end """ VectorSlackBridge{T, F, S} -The `VectorSlackBridge` converts a constraint `G`-in-`S` where `G` is a function different -from `VectorOfVariables` into the constraints `F`in-`Zeros` and `VectorOfVariables`-in-`S`. -`F` is the result of subtracting a `VectorOfVariables` from `G`. -Tipically `G` is the same as `F`, but that is not mandatory. +The `VectorSlackBridge` converts a constraint `G`-in-`S` where `G` is a function +different from `VectorOfVariables` into the constraints `F`in-`Zeros` and +`VectorOfVariables`-in-`S`. + +`F` is the result of subtracting a `VectorOfVariables` from `G`. Typically `G` +is the same as `F`, but that is not mandatory. """ struct VectorSlackBridge{T,F,S} <: AbstractSlackBridge{T,MOI.VectorOfVariables,MOI.Zeros,F,S} slack::Vector{MOI.VariableIndex} - slack_in_set::CI{MOI.VectorOfVariables,S} - equality::CI{F,MOI.Zeros} + slack_in_set::MOI.ConstraintIndex{MOI.VectorOfVariables,S} + equality::MOI.ConstraintIndex{F,MOI.Zeros} end function bridge_constraint( @@ -331,24 +340,18 @@ function concrete_bridge_type( return VectorSlackBridge{T,F2,S} end -# Attributes, Bridge acting as a model MOI.get(b::VectorSlackBridge, ::MOI.NumberOfVariables)::Int64 = length(b.slack) MOI.get(b::VectorSlackBridge, ::MOI.ListOfVariableIndices) = copy(b.slack) -# Attributes, Bridge acting as a constraint function MOI.set( model::MOI.ModelLike, ::MOI.ConstraintFunction, bridge::VectorSlackBridge{T,F,S}, func::F, ) where {T,F,S} - new_func = MOIU.operate( - -, - T, - func, - MOI.VectorAffineFunction{T}(MOI.VectorOfVariables(bridge.slack)), - ) + slack = MOI.VectorAffineFunction{T}(MOI.VectorOfVariables(bridge.slack)) + new_func = MOIU.operate(-, T, func, slack) MOI.set(model, MOI.ConstraintFunction(), bridge.equality, new_func) return end From 216122c49d985a475b9abce71952a4f9fc3cf8e5 Mon Sep 17 00:00:00 2001 From: odow Date: Sat, 4 Sep 2021 17:39:34 +1200 Subject: [PATCH 2/4] Updates --- src/Bridges/Constraint/slack.jl | 2 +- src/Bridges/bridge_optimizer.jl | 19 +++++++------------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/Bridges/Constraint/slack.jl b/src/Bridges/Constraint/slack.jl index f13ae5d7e2..9816bfdf5c 100644 --- a/src/Bridges/Constraint/slack.jl +++ b/src/Bridges/Constraint/slack.jl @@ -49,7 +49,7 @@ end function MOI.supports( model::MOI.ModelLike, attr::Union{MOI.ConstraintPrimalStart,MOI.ConstraintDualStart}, - ::Type{AbstractSlackBridge{T,VF,ZS,F,S}}, + ::Type{<:AbstractSlackBridge{T,VF,ZS,F,S}}, ) where {T,VF,ZS,F,S} ret = true if attr isa MOI.ConstraintPrimalStart diff --git a/src/Bridges/bridge_optimizer.jl b/src/Bridges/bridge_optimizer.jl index 7724491bf2..f78371f26a 100644 --- a/src/Bridges/bridge_optimizer.jl +++ b/src/Bridges/bridge_optimizer.jl @@ -1218,19 +1218,14 @@ end function MOI.supports( b::AbstractBridgeOptimizer, attr::MOI.AbstractConstraintAttribute, - IndexType::Type{MOI.ConstraintIndex{F,S}}, + ::Type{MOI.ConstraintIndex{F,S}}, ) where {F,S} - return reduce_bridged( - b, - F, - S, - true, - () -> MOI.supports(b.model, attr, IndexType), - ok -> ok && MOI.supports(b, attr, Variable.concrete_bridge_type(b, S)), - ok -> - ok && - MOI.supports(b, attr, Constraint.concrete_bridge_type(b, F, S)), - ) + if is_bridged(b, F, S) + return MOI.supports(b, attr, Constraint.concrete_bridge_type(b, F, S)) + elseif is_bridged(b, S) && is_variable_bridged(b, S) + return MOI.supports(b, attr, Variable.concrete_bridge_type(b, S)) + end + return MOI.supports(b.model, attr, MOI.ConstraintIndex{F,S}) end function _set_substituted( From 553a0ebfa17c64e5f590ae648de72afa153146e3 Mon Sep 17 00:00:00 2001 From: odow Date: Sat, 4 Sep 2021 17:44:55 +1200 Subject: [PATCH 3/4] Add comments --- src/Bridges/bridge_optimizer.jl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Bridges/bridge_optimizer.jl b/src/Bridges/bridge_optimizer.jl index f78371f26a..947c3ae32a 100644 --- a/src/Bridges/bridge_optimizer.jl +++ b/src/Bridges/bridge_optimizer.jl @@ -1220,11 +1220,17 @@ function MOI.supports( attr::MOI.AbstractConstraintAttribute, ::Type{MOI.ConstraintIndex{F,S}}, ) where {F,S} + # If `b` bridges `F`-in-`S`, check that the constraint bridge supports attr. if is_bridged(b, F, S) return MOI.supports(b, attr, Constraint.concrete_bridge_type(b, F, S)) - elseif is_bridged(b, S) && is_variable_bridged(b, S) + end + # If the bridge is capable of bridging the set for `VFT-in-S`, and `b` will + # be used to bridge the set, check the variable bridge supports attr. + VFT = MOI.Utilities.variable_function_type(S) + if F == VFT && is_bridged(b, S) && is_variable_bridged(b, S) return MOI.supports(b, attr, Variable.concrete_bridge_type(b, S)) end + # We're not bridging, so we check if the inner model supports it. return MOI.supports(b.model, attr, MOI.ConstraintIndex{F,S}) end From 80ff96f1bc44dff0fb8790a0088d47715d47c671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Sun, 5 Sep 2021 18:03:46 +0200 Subject: [PATCH 4/4] Fix supports for attribute of self-loop bridges --- src/Bridges/bridge_optimizer.jl | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/Bridges/bridge_optimizer.jl b/src/Bridges/bridge_optimizer.jl index 947c3ae32a..1f4da83852 100644 --- a/src/Bridges/bridge_optimizer.jl +++ b/src/Bridges/bridge_optimizer.jl @@ -1218,20 +1218,27 @@ end function MOI.supports( b::AbstractBridgeOptimizer, attr::MOI.AbstractConstraintAttribute, - ::Type{MOI.ConstraintIndex{F,S}}, + IndexType::Type{MOI.ConstraintIndex{F,S}}, ) where {F,S} - # If `b` bridges `F`-in-`S`, check that the constraint bridge supports attr. - if is_bridged(b, F, S) - return MOI.supports(b, attr, Constraint.concrete_bridge_type(b, F, S)) - end - # If the bridge is capable of bridging the set for `VFT-in-S`, and `b` will - # be used to bridge the set, check the variable bridge supports attr. - VFT = MOI.Utilities.variable_function_type(S) - if F == VFT && is_bridged(b, S) && is_variable_bridged(b, S) - return MOI.supports(b, attr, Variable.concrete_bridge_type(b, S)) - end - # We're not bridging, so we check if the inner model supports it. - return MOI.supports(b.model, attr, MOI.ConstraintIndex{F,S}) + return reduce_bridged( + b, + F, + S, + true, + () -> MOI.supports(b.model, attr, IndexType), + ok -> + ok && MOI.supports( + recursive_model(b), + attr, + Variable.concrete_bridge_type(b, S), + ), + ok -> + ok && MOI.supports( + recursive_model(b), + attr, + Constraint.concrete_bridge_type(b, F, S), + ), + ) end function _set_substituted(