Skip to content

Commit

Permalink
Support of multiple solvers
Browse files Browse the repository at this point in the history
  • Loading branch information
guimarqu committed May 15, 2021
1 parent dc64d11 commit ab3d108
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 32 deletions.
17 changes: 8 additions & 9 deletions src/annotations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ mutable struct Annotation{T, F<:Formulation, D<:Decomposition}
axis_index_value::T
lower_multiplicity::Float64
upper_multiplicity::Float64
optimizer_builder::Union{Nothing,MOI.AbstractOptimizer}
pricing_oracle::Union{Nothing,Function}
optimizer_builders::Vector
end

getid(a::Annotation) = a.unique_id
Expand All @@ -29,24 +28,24 @@ getformulation(a::Annotation) = a.formulation
getdecomposition(a::Annotation) = a.decomposition
getlowermultiplicity(a::Annotation) = a.lower_multiplicity
getuppermultiplicity(a::Annotation) = a.upper_multiplicity
getoptimizerbuilder(a::Annotation) = a.optimizer_builder
getpricingoracle(a::Annotation) = a.pricing_oracle
getoptimizerbuilders(a::Annotation) = a.optimizer_builders

setlowermultiplicity!(a::Annotation, lm::Real) = a.lower_multiplicity = lm
setuppermultiplicity!(a::Annotation, um::Real) = a.upper_multiplicity = um
setoptimizerbuilder!(a::Annotation, f::Union{Nothing, MOI.AbstractOptimizer}) = a.optimizer_builder = f
setpricingoracle!(a::Annotation, f::Union{Nothing, Function}) = a.pricing_oracle = f
emptyoptimizerbuilders!(a::Annotation) = empty!(a.optimizer_builders)
pushoptimizerbuilder!(a::Annotation, f::MOI.AbstractOptimizer) = push!(a.optimizer_builders, f)
pushoptimizerbuilder!(a::Annotation, f::Function) = push!(a.optimizer_builders, f)

OriginalAnnotation() = Annotation(0, 0, Original, NoDecomposition, 0, 1.0, 1.0, nothing, nothing)
OriginalAnnotation() = Annotation(0, 0, Original, NoDecomposition, 0, 1.0, 1.0, [])

function MasterAnnotation(tree, D::Type{<:Decomposition})
uid = generateannotationid(tree)
return Annotation(uid, 0, Master, D, 0, 1.0, 1.0, nothing, nothing)
return Annotation(uid, 0, Master, D, 0, 1.0, 1.0, [])
end

function Annotation(tree, F::Type{<:Formulation}, D::Type{<:Decomposition}, v)
uid = generateannotationid(tree)
return Annotation(uid, 0, F, D, v, 1.0, 1.0, nothing, nothing)
return Annotation(uid, 0, F, D, v, 1.0, 1.0, [])
end

function Base.show(io::IO, a::Annotation)
Expand Down
52 changes: 35 additions & 17 deletions src/formulations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,6 @@ function Base.show(io::IO, m::SubproblemForm)
return
end

function _specify!(sp::SubproblemForm, lm::Real, um::Real, opt::Union{MOI.OptimizerWithAttributes, Type{<:MOI.AbstractOptimizer}})
setlowermultiplicity!(sp.annotation, lm)
setuppermultiplicity!(sp.annotation, um)
setoptimizerbuilder!(sp.annotation, MOI._instantiate_and_check(opt))
setpricingoracle!(sp.annotation, nothing)
end

function _specify!(sp::SubproblemForm, lm::Real, um::Real, oracle::Union{Nothing,Function})
setlowermultiplicity!(sp.annotation, lm)
setuppermultiplicity!(sp.annotation, um)
setpricingoracle!(sp.annotation, oracle)
setoptimizerbuilder!(sp.annotation, nothing)
return
end

"""
specify!(
Expand All @@ -99,12 +85,44 @@ The solver of the subproblem is the way the subproblem will be optimized. It can
be either a function (pricing callback), an optimizer of MathOptInterface
(e.g. `Gurobi.Optimizer`, `CPLEX.Optimizer`, `Glpk.Optimizer`... with attributes),
or `nothing`. In the latter case, the solver will use a default optimizer that
should be defined in its parameters.
should be defined in the parameters of the main solver.
**Advanced usage** :
The user can use several solvers to optimize a subproblem :
specify!(subproblem, solver = [Gurobi.Optimizer, my_callback, my_second_callback])
Coluna always uses the first solver by default. Be cautious because changes are always
buffered to all solvers. So you may degrade performances if you use a lot of solvers.
"""
function specify!(
sp::SubproblemForm; lower_multiplicity::Real = 1,
upper_multiplicity::Real = 1, solver::Union{Nothing, Function, MOI.OptimizerWithAttributes, Type{<:MOI.AbstractOptimizer}} = nothing
upper_multiplicity::Real = 1, solver = nothing
)
_specify!(sp, lower_multiplicity, upper_multiplicity, solver)
setlowermultiplicity!(sp.annotation, lower_multiplicity)
setuppermultiplicity!(sp.annotation, upper_multiplicity)
emptyoptimizerbuilders!(sp.annotation)
_specify!(sp, solver)
return
end

# Fallback
_specify!(::SubproblemForm, solver) = error("BlockDecomposition does not support solver of type $(typeof(solver)).")

_specify!(::SubproblemForm, ::Nothing) = return

function _specify!(sp::SubproblemForm, solver::Union{MOI.OptimizerWithAttributes, Type{<:MOI.AbstractOptimizer}})
pushoptimizerbuilder!(sp.annotation, MOI._instantiate_and_check(solver))
end

function _specify!(sp::SubproblemForm, oracle::Function)
pushoptimizerbuilder!(sp.annotation, oracle)
return
end

function _specify!(sp::SubproblemForm, solvers::Vector)
for solver in solvers
_specify!(sp, solver)
end
return
end
11 changes: 5 additions & 6 deletions test/assignsolver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ function test_assignsolver()
subproblems = getsubproblems(dec)

specify!.(subproblems, solver = sp_pricing_oracle)
@test BD.getpricingoracle(subproblems[1].annotation) == sp_pricing_oracle
@test BD.getoptimizerbuilder(subproblems[2].annotation) === nothing
@test BD.getoptimizerbuilders(subproblems[1].annotation) == [sp_pricing_oracle]
specify!(subproblems[2], solver = nothing)
@test BD.getoptimizerbuilder(subproblems[2].annotation) === nothing
@test BD.getpricingoracle(subproblems[2].annotation) === nothing
@test BD.getoptimizerbuilders(subproblems[2].annotation) == []
specify!(subproblems[3], solver = MockOptimizer)
@test BD.getoptimizerbuilder(subproblems[3].annotation) == MockOptimizer()
@test BD.getpricingoracle(subproblems[2].annotation) === nothing
@test BD.getoptimizerbuilders(subproblems[3].annotation) == [MockOptimizer()]
specify!(subproblems[1], solver = [sp_pricing_oracle, MockOptimizer])
@test BD.getoptimizerbuilders(subproblems[1].annotation) == [sp_pricing_oracle, MockOptimizer()]
end
end

0 comments on commit ab3d108

Please sign in to comment.