Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support of multiple solvers #56

Merged
merged 1 commit into from
May 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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