Skip to content

Commit b1bab26

Browse files
committed
Add variable constraint watcher bridges
1 parent 0b5cd4d commit b1bab26

File tree

4 files changed

+58
-5
lines changed

4 files changed

+58
-5
lines changed

src/Bridges/Constraint/single_bridge_optimizer.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ even if they are supported by one of its bridges.
88
"""
99
mutable struct SingleBridgeOptimizer{BT<:AbstractBridge, OT<:MOI.ModelLike} <: MOIB.AbstractBridgeOptimizer
1010
model::OT
11+
watchers::Dict{MOI.VariableIndex, Set{MOIB.AbstractBridge}}
1112
map::Map # index of bridged constraint -> constraint bridge
1213
con_to_name::Dict{MOI.ConstraintIndex, String}
1314
name_to_con::Union{Dict{String, MOI.ConstraintIndex}, Nothing}
1415
end
1516
function SingleBridgeOptimizer{BT}(model::OT) where {BT, OT <: MOI.ModelLike}
1617
SingleBridgeOptimizer{BT, OT}(
17-
model, Map(), Dict{MOI.ConstraintIndex, String}(), nothing)
18+
model, Dict{MOI.VariableIndex, Set{MOIB.AbstractBridge}}(),
19+
Map(), Dict{MOI.ConstraintIndex, String}(), nothing)
1820
end
1921

2022
function bridges(bridge::MOI.Bridges.AbstractBridgeOptimizer)

src/Bridges/bridge.jl

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,25 +78,47 @@ function MOI.set(model::MOI.ModelLike, attr::MOI.AbstractConstraintAttribute,
7878
end
7979

8080
"""
81-
added_constrained_variable_types(BT::Type{<:Variable.AbstractBridge})::Vector{Tuple{DataType}}
81+
added_constrained_variable_types(BT::Type{<:AbstractBridge})::Vector{Tuple{DataType}}
8282
8383
Return a list of the types of constrained variables that bridges of concrete
8484
type `BT` add. This is used by the [`LazyBridgeOptimizer`](@ref).
8585
"""
8686
function added_constrained_variable_types end
8787

8888
"""
89-
added_constraint_types(BT::Type{<:Constraint.AbstractBridge})::Vector{Tuple{DataType, DataType}}
89+
added_constraint_types(BT::Type{<:AbstractBridge})::Vector{Tuple{DataType, DataType}}
9090
9191
Return a list of the types of constraints that bridges of concrete type `BT`
9292
add. This is used by the [`LazyBridgeOptimizer`](@ref).
9393
"""
9494
function added_constraint_types end
9595

9696
"""
97-
set_objective_function_type(BT::Type{<:Objective.AbstractBridge})::Type{<:MOI.AbstractScalarFunction}
97+
set_objective_function_type(BT::Type{<:AbstractBridge})::Type{<:MOI.AbstractScalarFunction}
9898
9999
Return the type of objective function that bridges of concrete type `BT`
100100
set. This is used by the [`LazyBridgeOptimizer`](@ref).
101101
"""
102102
function set_objective_function_type end
103+
104+
"""
105+
watched_variables(::AbstractBridge)::AbstractVector{MOI.VariableIndex}
106+
107+
Return a list of variable indices. For any `S<:MOI.AbstractScalarSet`, whenever
108+
a `MOI.SingleVariable`-in-`S` constraint is added to the model for one variable
109+
of this list, the bridge is notified with [`notify_constraint`]`(@ref) just before
110+
adding the constraint.
111+
If this method is not implemented, it fallbacks to returning
112+
`MOI.Utilities.EmptyVector{MOI.VariableIndex}()`.
113+
"""
114+
watched_variables(::AbstractBridge) = MOIU.EmptyVector{MOI.VariableIndex}()
115+
116+
"""
117+
notify_constraint(bridge::AbstractBridge, model::Model, func::SingleVariable, set::MOI.AbstractScalarSet)::AbstractVector{MOI.VariableIndex}
118+
119+
Notifies `bridge` that the `func`-in-`set` constraint will be might be added to
120+
`model`. The bridge can throw an error if that should not be allowed or add
121+
variables or add/modify constraints due to this change.
122+
See [`watched_variables`](@ref) for being notified when variables are modified.
123+
"""
124+
function notify_constraint end

src/Bridges/bridge_optimizer.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ function MOI.is_empty(b::AbstractBridgeOptimizer)
245245
end
246246
function MOI.empty!(b::AbstractBridgeOptimizer)
247247
MOI.empty!(b.model)
248+
empty!(b.watchers)
248249
if Variable.has_bridges(Variable.bridges(b))
249250
empty!(b.var_to_name)
250251
b.name_to_var = nothing
@@ -391,6 +392,7 @@ function MOI.delete(b::AbstractBridgeOptimizer, ci::MOI.ConstraintIndex)
391392
else
392393
delete!(Constraint.bridges(b), ci)
393394
end
395+
remove_watchers(b, br)
394396
Variable.call_in_context(Variable.bridges(b), ci, () -> MOI.delete(b, br))
395397
b.name_to_con = nothing
396398
delete!(b.con_to_name, ci)
@@ -988,6 +990,23 @@ function MOI.get(b::AbstractBridgeOptimizer,
988990
IdxT, ci_bridged, MOI.get(b.model, IdxT, name), name)
989991
end
990992

993+
function add_watchers(b::AbstractBridgeOptimizer, bridge::AbstractBridge)
994+
for variable in watched_variables(bridge)
995+
bridges = get(b.watchers, variable, nothing)
996+
if bridges === nothing
997+
bridges = Set{AbstractBridge}()
998+
b.watchers[variable] = bridges
999+
end
1000+
push!(bridges, bridge)
1001+
end
1002+
end
1003+
function remove_watchers(b::AbstractBridgeOptimizer, bridge::AbstractBridge)
1004+
for variable in watched_variables(bridge)
1005+
bridges = get(b.watchers, variable, nothing)
1006+
delete!(bridges, bridge)
1007+
end
1008+
end
1009+
9911010
# Constraints
9921011
function MOI.supports_constraint(b::AbstractBridgeOptimizer,
9931012
F::Type{<:MOI.AbstractFunction},
@@ -1004,12 +1023,21 @@ function MOI.supports_constraint(b::AbstractBridgeOptimizer,
10041023
end
10051024
function add_bridged_constraint(b, BridgeType, f, s)
10061025
bridge = Constraint.bridge_constraint(BridgeType, b, f, s)
1026+
add_watchers(b, bridge)
10071027
ci = Constraint.add_key_for_bridge(Constraint.bridges(b), bridge, f, s)
10081028
Variable.register_context(Variable.bridges(b), ci)
10091029
return ci
10101030
end
10111031
function MOI.add_constraint(b::AbstractBridgeOptimizer, f::MOI.AbstractFunction,
10121032
s::MOI.AbstractSet)
1033+
if f isa MOI.SingleVariable
1034+
watchers = get(b.watchers, f.variable, nothing)
1035+
if watchers !== nothing
1036+
for watcher in watchers
1037+
notify_constraint(watcher, b, f, s)
1038+
end
1039+
end
1040+
end
10131041
if Variable.has_bridges(Variable.bridges(b))
10141042
if f isa MOI.SingleVariable
10151043
if is_bridged(b, f.variable)

src/Bridges/lazy_bridge_optimizer.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ it will choose bridge 1 as it allows to bridge `F`-in-`S` using only one bridge
1616
mutable struct LazyBridgeOptimizer{OT<:MOI.ModelLike} <: AbstractBridgeOptimizer
1717
# Internal model
1818
model::OT
19+
watchers::Dict{MOI.VariableIndex, Set{AbstractBridge}}
1920
# Bridged variables
2021
variable_map::Variable.Map
2122
var_to_name::Dict{MOI.VariableIndex, String}
@@ -44,7 +45,7 @@ mutable struct LazyBridgeOptimizer{OT<:MOI.ModelLike} <: AbstractBridgeOptimizer
4445
end
4546
function LazyBridgeOptimizer(model::MOI.ModelLike)
4647
return LazyBridgeOptimizer{typeof(model)}(
47-
model,
48+
model, Dict{MOI.VariableIndex, Set{AbstractBridge}}(),
4849
Variable.Map(), Dict{MOI.VariableIndex, String}(), nothing,
4950
Constraint.Map(), Dict{MOI.ConstraintIndex, String}(), nothing,
5051
Objective.Map(),

0 commit comments

Comments
 (0)