Skip to content

Commit

Permalink
Add final_touch for bridges
Browse files Browse the repository at this point in the history
  • Loading branch information
blegat committed Jun 17, 2022
1 parent b760048 commit 23578ac
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/Bridges/Constraint/Constraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module Constraint

import LinearAlgebra
import MathOptInterface
import OrderedCollections: OrderedDict
import OrderedCollections: OrderedDict, OrderedSet
import SparseArrays

const MOI = MathOptInterface
Expand Down
39 changes: 39 additions & 0 deletions src/Bridges/Constraint/map.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ struct Map <: AbstractDict{MOI.ConstraintIndex,AbstractBridge}
# of creation so we need `OrderedDict` and not `Dict`.
# For `VariableIndex` constraints: (variable, set type) -> bridge
single_variable_constraints::OrderedDict{Tuple{Int64,Type},AbstractBridge}
needs_final_touch::OrderedDict{Type,OrderedSet}

function Map()
return new(
Union{Nothing,AbstractBridge}[],
Tuple{Type,Type}[],
OrderedDict{Tuple{Int64,Type},AbstractBridge}(),
OrderedDict{Type,OrderedSet}(),
)
end
end
Expand All @@ -48,6 +50,7 @@ function Base.empty!(map::Map)
empty!(map.bridges)
empty!(map.constraint_types)
empty!(map.single_variable_constraints)
empty!(map.needs_final_touch)
return map
end

Expand Down Expand Up @@ -83,6 +86,7 @@ function Base.getindex(
end

function Base.delete!(map::Map, ci::MOI.ConstraintIndex)
_unregister_for_final_touch(map, map.bridges[_index(ci)])
map.bridges[_index(ci)] = nothing
return map
end
Expand All @@ -91,6 +95,8 @@ function Base.delete!(
map::Map,
ci::MOI.ConstraintIndex{MOI.VariableIndex,S},
) where {S}
bridge = map.single_variable_constraints[(ci.value, S)]
_unregister_for_final_touch(map, bridge)
delete!(map.single_variable_constraints, (ci.value, S))
return map
end
Expand Down Expand Up @@ -278,6 +284,7 @@ function add_key_for_bridge(
::F,
::S,
) where {F<:MOI.AbstractFunction,S<:MOI.AbstractSet}
_register_for_final_touch(map, bridge)
push!(map.bridges, bridge)
push!(map.constraint_types, (F, S))
return _index(length(map.bridges), F, S)
Expand All @@ -289,10 +296,40 @@ function add_key_for_bridge(
func::MOI.VariableIndex,
::S,
) where {S<:MOI.AbstractScalarSet}
_register_for_final_touch(map, bridge)
map.single_variable_constraints[(func.value, S)] = bridge
return MOI.ConstraintIndex{MOI.VariableIndex,S}(func.value)
end

function _register_for_final_touch(map::Map, bridge)
if MOI.Bridges.needs_final_touch(bridge)
if !haskey(map.needs_final_touch, typeof(bridge))
map.needs_final_touch[typeof(bridge)] = OrderedSet{typeof(bridge)}()
end
push!(map.needs_final_touch[typeof(bridge)], bridge)
end
return
end
function _unregister_for_final_touch(b::Map, bridge)
if MOI.Bridges.needs_final_touch(bridge)
delete!(b.needs_final_touch[typeof(bridge)], bridge)
end
return
end

# function barrier to iterate over bridges of the same type in an efficient way
function _final_touch(bridges)
for bridge in bridges
MOI.Utilities.final_touch(bridge)
end
end

function MOI.Utilities.final_touch(map::Map)
for bridges in values(map.needs_final_touch)
_final_touch(bridges)
end
end

"""
EmptyMap <: AbstractDict{MOI.ConstraintIndex, AbstractBridge}
Expand All @@ -315,3 +352,5 @@ Base.values(::EmptyMap) = MOI.Utilities.EmptyVector{AbstractBridge}()
has_bridges(::EmptyMap) = false

number_of_type(::EmptyMap, ::Type{<:MOI.ConstraintIndex}) = 0

MOI.Utilities.final_touch(::EmptyMap) = nothing
11 changes: 11 additions & 0 deletions src/Bridges/bridge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,14 @@ MathOptInterface.ScalarAffineFunction{Float64}
```
"""
function set_objective_function_type end

"""
needs_final_touch(bridge::AbstractBridge)
Return whether [`Utilities.final_touch`](@ref) needs to be called on `bridge`.
For instance, if the correctness of `bridge` depends on bounds of variable
or the fact that variables are integer, then the bridging is only valid
if these do not change. In that case, the bridge can check in `final_touch`
that they did not change and change the bridging in case it did.
"""
needs_final_touch(::AbstractBridge) = false
7 changes: 6 additions & 1 deletion src/Bridges/bridge_optimizer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,11 @@ end
# Implementation of the MOI interface for AbstractBridgeOptimizer

# By convention, the model should be stored in a `model` field
MOI.optimize!(b::AbstractBridgeOptimizer) = MOI.optimize!(b.model)
function MOI.optimize!(b::AbstractBridgeOptimizer)
MOI.Utilities.final_touch(Constraint.bridges(b))
MOI.optimize!(b.model)
return
end

function MOI.is_empty(b::AbstractBridgeOptimizer)
return isempty(Variable.bridges(b)) &&
Expand Down Expand Up @@ -454,6 +458,7 @@ function MOI.supports_incremental_interface(b::AbstractBridgeOptimizer)
return MOI.supports_incremental_interface(b.model)
end
function MOI.Utilities.final_touch(uf::AbstractBridgeOptimizer, index_map)
MOI.Utilities.final_touch(Constraint.bridges(b))
return MOI.Utilities.final_touch(uf.model, index_map)
end

Expand Down

0 comments on commit 23578ac

Please sign in to comment.