From 25dab60f851c3c16568516190a14899d3d44d162 Mon Sep 17 00:00:00 2001 From: Guillaume Marques Date: Tue, 28 May 2019 11:35:28 +0200 Subject: [PATCH] Dispatch decomposition using BD tree (#103) * store decomposition tree in optimizer * draft new way to decompose * clean --- Manifest.toml | 2 +- src/MOIwrapper.jl | 12 ++-- src/decomposition.jl | 139 ++++++++++++++++++++----------------------- src/problem.jl | 5 +- 4 files changed, 75 insertions(+), 83 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index 65d731b6a..6a83404af 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -23,7 +23,7 @@ version = "0.5.4" [[BlockDecomposition]] deps = ["DataStructures", "JuMP", "MathOptInterface", "Test"] -git-tree-sha1 = "caed35511b5d1dd20fbb53a7bac5bc8f63530973" +git-tree-sha1 = "8868596cdfa9de6ad31630d03ecd8556116fb33b" repo-rev = "master" repo-url = "https://github.com/atoptima/BlockDecomposition.jl.git" uuid = "6cde8614-403a-11e9-12f1-c10d0f0caca0" diff --git a/src/MOIwrapper.jl b/src/MOIwrapper.jl index b3bf87ec5..22557a974 100644 --- a/src/MOIwrapper.jl +++ b/src/MOIwrapper.jl @@ -58,7 +58,7 @@ function MOI.supports(optimizer::Optimizer, return true end -function update_annotations(srs::MOI.ModelLike, +function update_annotations!(srs::MOI.ModelLike, annotation_set::Set{BD.Annotation}, vc_per_block::Dict{Int,C}, annotation::A, @@ -106,7 +106,7 @@ function create_origvars!(f::Formulation, moi_uid_to_coluna_id[moi_index.value] = var_id annotation = MOI.get(src, BD.VariableDecomposition(), moi_index) dest.varmap[moi_index_in_coluna] = var_id - update_annotations( + update_annotations!( src, dest.annotations.annotation_set, dest.annotations.vars_per_block, annotation, v ) @@ -160,7 +160,7 @@ function create_origconstr!(f::Formulation, matrix[constr_id, var_id] = term.coefficient end annotation = MOI.get(src, BD.ConstraintDecomposition(), moi_index) - update_annotations( + update_annotations!( src, dest.annotations.annotation_set, dest.annotations.constrs_per_block, annotation, c ) @@ -206,15 +206,17 @@ function register_original_formulation!(dest::Optimizer, problem = dest.inner orig_form = Formulation{Original}(problem.form_counter) set_original_formulation!(problem, orig_form) - moi_uid_to_coluna_id = Dict{Int,VarId}() + moi_uid_to_coluna_id = Dict{Int,VarId}() create_origvars!(orig_form, dest, src, copy_names, moi_uid_to_coluna_id) create_origconstrs!(orig_form, dest, src, copy_names, moi_uid_to_coluna_id) - load_obj!(orig_form, src, dest.moi_index_to_coluna_uid, moi_uid_to_coluna_id) + sense = MOI.get(src, MOI.ObjectiveSense()) min_sense = (sense == MOI.MIN_SENSE) register_objective_sense!(orig_form, min_sense) + + dest.annotations.tree = MOI.get(src, BD.DecompositionTree()) return end diff --git a/src/decomposition.jl b/src/decomposition.jl index 825abc444..711955205 100644 --- a/src/decomposition.jl +++ b/src/decomposition.jl @@ -45,12 +45,13 @@ function initialize_artificial_variables(master::Formulation, constrs_in_form) # end end -function find_vcs_in_block(uid::Int, vars_per_block::Dict{Int,VarDict}, - constrs_per_block::Dict{Int,ConstrDict}) +function find_vcs_in_block(uid::Int, annotations::Annotations) + vars_per_block = annotations.vars_per_block vars = VarDict() if haskey(vars_per_block, uid) vars = vars_per_block[uid] end + constrs_per_block = annotations.constrs_per_block constrs = ConstrDict() if haskey(constrs_per_block, uid) constrs = constrs_per_block[uid] @@ -160,88 +161,74 @@ function build_dw_pricing_sp!(prob::Problem, return end -function reformulate!(prob::Problem, annotations::Annotations, - strategy::GlobalStrategy) - # This function must be cleaned. - # subproblem formulations are modified in the function build_dw_master - - - # Create formulations & reformulations - - - - # At the moment, BlockDecomposition supports only classic - # Dantzig-Wolfe decomposition. - # TODO : improve all drafts as soon as BlockDecomposition returns a - # decomposition-tree. - - vars_per_block = annotations.vars_per_block - constrs_per_block = annotations.constrs_per_block - annotation_set = annotations.annotation_set - - # Create reformulation - reformulation = Reformulation(prob, strategy) - set_re_formulation!(prob, reformulation) - - # Create master formulation - master_form = Formulation{DwMaster}( - prob.form_counter; parent_formulation = reformulation, +function instanciatemaster!(prob::Problem, reform, ::Type{BD.Master}, ::Type{BD.DantzigWolfe}) + form = Formulation{DwMaster}( + prob.form_counter; parent_formulation = reform, obj_sense = getobjsense(get_original_formulation(prob)) ) - setmaster!(reformulation, master_form) - - # Create pricing subproblem formulations - ann_sorted_by_uid = sort(collect(annotation_set), by = ann -> ann.unique_id) - - formulations = Dict{Int, Formulation}() - optimizer_builders = Dict{Int, Function}() - master_unique_id = -1 - - for annotation in ann_sorted_by_uid - if BD.getoptimizerbuilder(annotation) != nothing - optimizer_builders[BD.getid(annotation)] = BD.getoptimizerbuilder(annotation) - end - if BD.getformulation(annotation) == BD.Master - master_unique_id = BD.getid(annotation) - formulations[BD.getid(annotation)] = master_form - elseif BD.getformulation(annotation) == BD.DwPricingSp - f = Formulation{DwSp}( - prob.form_counter; parent_formulation = master_form, - obj_sense = getobjsense(master_form) - ) - formulations[BD.getid(annotation)] = f - add_dw_pricing_sp!(reformulation, f) - else - error(string("Subproblem type ", BD.getformulation(annotation), - " not supported yet.")) - end - end + setmaster!(reform, form) + return form +end - # Build Pricing Sp - for annotation in ann_sorted_by_uid - if BD.getformulation(annotation) == BD.DwPricingSp - vars, constrs = find_vcs_in_block( - BD.getid(annotation), vars_per_block, constrs_per_block - ) - opt_builder = get(optimizer_builders, BD.getid(annotation), prob.default_optimizer_builder) - build_dw_pricing_sp!(prob, BD.getid(annotation), - formulations[BD.getid(annotation)], - vars, constrs, opt_builder) - end +function createmaster!(form, prob::Problem, reform, ann, annotations, ::Type{BD.Master}, ::Type{BD.DantzigWolfe}) + vars, constrs = find_vcs_in_block(BD.getid(ann), annotations) + opt_builder = prob.default_optimizer_builder + if BD.getoptimizerbuilder(ann) != nothing + opt_builder = BD.getoptimizerbuilder(ann) end + build_dw_master!(prob, BD.getid(ann), reform, form, vars, constrs, opt_builder) +end - # Build Master - vars, constrs = find_vcs_in_block( - master_unique_id, vars_per_block, constrs_per_block +function createsp!(prob::Problem, reform, mast, ann, annotations, ::Type{BD.DwPricingSp}, ::Type{BD.DantzigWolfe}) + form = Formulation{DwSp}( + prob.form_counter; parent_formulation = mast, + obj_sense = getobjsense(mast) ) - opt_builder = get(optimizer_builders, master_unique_id, prob.default_optimizer_builder) - build_dw_master!(prob, master_unique_id, reformulation, - master_form, vars, constrs, opt_builder) + add_dw_pricing_sp!(reform, form) - @debug "\e[1;34m Master formulation \e[00m" master_form - for sp_form in reformulation.dw_pricing_subprs - @debug "\e[1;34m Pricing subproblems formulation \e[00m" sp_form + vars, constrs = find_vcs_in_block(BD.getid(ann), annotations) + opt_builder = prob.default_optimizer_builder + if BD.getoptimizerbuilder(ann) != nothing + opt_builder = BD.getoptimizerbuilder(ann) end + build_dw_pricing_sp!(prob, BD.getid(ann), form, vars, constrs, opt_builder) + return form +end + +function registerformulations!(prob::Problem, annotations::Annotations, reform, + parent, node::BD.Root) + ann = BD.annotation(node) + form_type = BD.getformulation(ann) + dec_type = BD.getdecomposition(ann) + form = instanciatemaster!(prob, reform, form_type, dec_type) + for (id, child) in BD.subproblems(node) + registerformulations!(prob, annotations, reform, node, child) + end + createmaster!(form, prob, reform, ann, annotations, form_type, dec_type) + return +end + +function registerformulations!(prob::Problem, annotations::Annotations, reform, + parent, node::BD.Leaf) + ann = BD.annotation(node) + form_type = BD.getformulation(ann) + dec_type = BD.getdecomposition(ann) + mast = getmaster(reform) + createsp!(prob, reform, mast, ann, annotations, form_type, dec_type) return end +function reformulate!(prob::Problem, annotations::Annotations, + strategy::GlobalStrategy) + vars_per_block = annotations.vars_per_block + constrs_per_block = annotations.constrs_per_block + annotation_set = annotations.annotation_set + decomposition_tree = annotations.tree + + root = BD.getroot(decomposition_tree) + + # Create reformulation + reform = Reformulation(prob, strategy) + set_re_formulation!(prob, reform) + registerformulations!(prob, annotations, reform, reform, root) +end \ No newline at end of file diff --git a/src/problem.jl b/src/problem.jl index a681f14c0..26c208632 100644 --- a/src/problem.jl +++ b/src/problem.jl @@ -1,9 +1,12 @@ -struct Annotations +mutable struct Annotations + tree::Union{BD.Tree, Nothing} vars_per_block::Dict{Int, Dict{Id{Variable},Variable}} constrs_per_block::Dict{Int, Dict{Id{Constraint},Constraint}} annotation_set::Set{BD.Annotation} end + Annotations() = Annotations( + nothing, Dict{Int, Dict{Id{Variable},Variable}}(), Dict{Int, Dict{Id{Constraint},Constraint}}(), Set{BD.Annotation}()