From 418a8ca37d80ccfc321db0c612528aa6075f6cf8 Mon Sep 17 00:00:00 2001 From: Guillaume Marques Date: Thu, 8 Jun 2023 16:59:48 +0200 Subject: [PATCH 1/5] Basis record --- src/Algorithm/basic/solvelpform.jl | 1 + src/Algorithm/colgen.jl | 1 + src/Algorithm/conquer.jl | 4 +-- src/Algorithm/formstorages.jl | 36 ++++++++++++++++++++ src/Algorithm/node.jl | 0 src/Benders/Benders.jl | 2 -- src/MathProg/MOIinterface.jl | 54 ++++++++++++++++++++++++++++++ src/MathProg/optimizerwrappers.jl | 4 +++ 8 files changed, 98 insertions(+), 4 deletions(-) delete mode 100644 src/Algorithm/node.jl diff --git a/src/Algorithm/basic/solvelpform.jl b/src/Algorithm/basic/solvelpform.jl index c6b6f6687..4d11abe84 100644 --- a/src/Algorithm/basic/solvelpform.jl +++ b/src/Algorithm/basic/solvelpform.jl @@ -43,6 +43,7 @@ function get_units_usage( push!(units_usage, (form, MasterColumnsUnit, READ_ONLY)) push!(units_usage, (form, MasterBranchConstrsUnit, READ_ONLY)) push!(units_usage, (form, MasterCutsUnit, READ_ONLY)) + push!(units_usage, (form, MasterBasisUnit, READ_ONLY)) end return units_usage end diff --git a/src/Algorithm/colgen.jl b/src/Algorithm/colgen.jl index 697a56f11..91dd0e5ad 100644 --- a/src/Algorithm/colgen.jl +++ b/src/Algorithm/colgen.jl @@ -107,6 +107,7 @@ function get_units_usage(algo::ColumnGeneration, reform::Reformulation) units_usage = Tuple{AbstractModel,UnitType,UnitPermission}[] master = getmaster(reform) push!(units_usage, (master, MasterColumnsUnit, READ_AND_WRITE)) + push!(units_usage, (master, MasterBasisUnit, READ_AND_WRITE)) #push!(units_usage, (master, PartialSolutionUnit, READ_ONLY)) if stabilization_is_used(algo) push!(units_usage, (master, ColGenStabilizationUnit, READ_AND_WRITE)) diff --git a/src/Algorithm/conquer.jl b/src/Algorithm/conquer.jl index 7de1a66be..d5a74fbed 100644 --- a/src/Algorithm/conquer.jl +++ b/src/Algorithm/conquer.jl @@ -264,7 +264,6 @@ end function run_heuristics!(ctx::ColCutGenContext, heuristics, env, reform, node_state) for heuristic in heuristics # TODO: check time limit of Coluna - if ip_gap_closed(node_state, atol = ctx.params.opt_atol, rtol = ctx.params.opt_rtol) return false end @@ -345,7 +344,6 @@ end function run_colcutgen_conquer!(ctx::ColCutGenContext, env, reform, input) node = get_node(input) - restore_from_records!(get_units_to_restore(input), TreeSearch.get_records(node)) node_state = TreeSearch.get_opt_state(node) time_limit_reached!(node_state, env) && return @@ -387,6 +385,8 @@ end function run!(algo::ColCutGenConquer, env::Env, reform::Reformulation, input::AbstractConquerInput) !run_conquer(input) && return ctx = new_context(type_of_context(algo), algo, reform, input) + node = get_node(input) + restore_from_records!(get_units_to_restore(input), TreeSearch.get_records(node)) run_colcutgen_conquer!(ctx, env, reform, input) return end diff --git a/src/Algorithm/formstorages.jl b/src/Algorithm/formstorages.jl index a409b5c8c..68c047708 100644 --- a/src/Algorithm/formstorages.jl +++ b/src/Algorithm/formstorages.jl @@ -234,6 +234,42 @@ function ClB.restore_from_record!( end +#### +#### +struct MasterBasisUnit <: AbstractRecordUnit end + +struct MasterBasisRecord <: AbstractRecord + basis::Union{Nothing,MathProg.Basis} +end + +struct MasterBasisKey <: AbstractStorageUnitKey end + +key_from_storage_unit_type(::Type{MasterBasisUnit}) = MasterBasisKey() +record_type_from_key(::MasterBasisKey) = MasterBasisRecord + +ClB.storage_unit(::Type{MasterBasisUnit}, _) = MasterBasisUnit() + +function ClB.record(::Type{MasterBasisRecord}, id::Int, form::Formulation, unit::MasterBasisUnit) + optimizer = getoptimizer(form, 1) + basis = MathProg.get_basis(form, optimizer) + return MasterBasisRecord(basis) +end + +ClB.record_type(::Type{MasterBasisUnit}) = MasterBasisRecord +ClB.storage_unit_type(::Type{MasterBasisRecord}) = MasterBasisUnit + +apply_set_basis!(form, optimizer::MoiOptimizer, basis) = MathProg.set_basis!(form, optimizer, basis) +apply_set_basis!(form, _, basis) = nothing + +function ClB.restore_from_record!( + form::Formulation, ::MasterBasisUnit, state::MasterBasisRecord +) + optimizer = getoptimizer(form, 1) + if !isnothing(state.basis) + apply_set_basis!(form, optimizer, state.basis) + end + return +end ##### UNCOVERED CODE BELOW ##### diff --git a/src/Algorithm/node.jl b/src/Algorithm/node.jl deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/Benders/Benders.jl b/src/Benders/Benders.jl index 11d71da73..c72abb7ca 100644 --- a/src/Benders/Benders.jl +++ b/src/Benders/Benders.jl @@ -19,8 +19,6 @@ struct UnboundedError <: Exception end "Returns the separation subproblems." @mustimplement "BendersProbInfo" get_benders_subprobs(context) = nothing - - """ optimize_master_problem!(master, context, env) -> MasterResult diff --git a/src/MathProg/MOIinterface.jl b/src/MathProg/MOIinterface.jl index be45c94b5..e1313191c 100644 --- a/src/MathProg/MOIinterface.jl +++ b/src/MathProg/MOIinterface.jl @@ -338,6 +338,60 @@ function get_dual_solutions(form::F, optimizer::MoiOptimizer) where {F <: Formul return solutions end + +struct Basis + vars::Dict{VarId,MOI.BasisStatusCode} + constrs::Dict{ConstrId,MOI.BasisStatusCode} +end + +function get_basis(form::F, optimizer::MoiOptimizer) where {F <: Formulation} + inner = getinner(optimizer) + nb_primal_sols = MOI.get(inner, MOI.ResultCount()) + if nb_primal_sols <= 0 || MOI.get(inner, MOI.PrimalStatus(1)) != MOI.FEASIBLE_POINT + return nothing + end + + vars = Dict{VarId,MOI.BasisStatusCode}() + for (varid, var) in getvars(form) + iscuractive(form, varid) && isexplicit(form, varid) || continue + moi_index = getindex(getmoirecord(var)) + if moi_index.value != -1 + vars[varid] = MOI.get(inner, MOI.VariableBasisStatus(), moi_index) + end + end + + constrs = Dict{ConstrId,MOI.BasisStatusCode}() + for (constrid, constr) in getconstrs(form) + iscuractive(form, constrid) && isexplicit(form, constrid) || continue + moi_index = getindex(getmoirecord(constr)) + if moi_index.value != -1 + constrs[constrid] = MOI.get(inner, MOI.ConstraintBasisStatus(), moi_index) + end + end + return Basis(vars, constrs) +end + +function set_basis!(form::F, optimizer::MoiOptimizer, basis::Basis) where {F <: Formulation} + inner = getinner(optimizer) + for (varid, var) in getvars(form) + iscuractive(form, varid) && isexplicit(form, varid) || continue + moi_index = getindex(getmoirecord(var)) + var_basis = get(basis.vars, varid, nothing) + if !isnothing(var_basis) + MOI.set(inner, MOI.VariableBasisStatus(), moi_index, var_basis) + end + end + for (constrid, constr) in getconstrs(form) + iscuractive(form, constrid) && isexplicit(form, constrid) || continue + moi_index = getindex(getmoirecord(constr)) + constr_basis = get(basis.constrs, constrid, nothing) + if !isnothing(constr_basis) + MOI.set(inner, MOI.ConstraintBasisStatus(), moi_index, constr_basis) + end + end + return +end + function get_dual_infeasibility_certificate(form::F, optimizer::MoiOptimizer) where {F <: Formulation} inner = getinner(optimizer) nb_certificates = MOI.get(inner, MOI.ResultCount()) diff --git a/src/MathProg/optimizerwrappers.jl b/src/MathProg/optimizerwrappers.jl index b2bdedb3a..2e54f1a64 100644 --- a/src/MathProg/optimizerwrappers.jl +++ b/src/MathProg/optimizerwrappers.jl @@ -41,6 +41,10 @@ end getinner(optimizer::MoiOptimizer) = optimizer.inner +function setbasis!(optimizer::MoiOptimizer) + +end + function sync_solver!(optimizer::MoiOptimizer, f::Formulation) @logmsg LogLevel(-1) string("Synching formulation ", getuid(f)) buffer = f.buffer From 62e9ccceb90cbcae34ec52c4fbaed672c8ba5343 Mon Sep 17 00:00:00 2001 From: Guillaume Marques Date: Fri, 9 Jun 2023 19:08:51 +0200 Subject: [PATCH 2/5] rm empty method --- src/MathProg/optimizerwrappers.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/MathProg/optimizerwrappers.jl b/src/MathProg/optimizerwrappers.jl index 2e54f1a64..b2bdedb3a 100644 --- a/src/MathProg/optimizerwrappers.jl +++ b/src/MathProg/optimizerwrappers.jl @@ -41,10 +41,6 @@ end getinner(optimizer::MoiOptimizer) = optimizer.inner -function setbasis!(optimizer::MoiOptimizer) - -end - function sync_solver!(optimizer::MoiOptimizer, f::Formulation) @logmsg LogLevel(-1) string("Synching formulation ", getuid(f)) buffer = f.buffer From 35273b64f8da3f02eaecca87abf3e437d169c4fd Mon Sep 17 00:00:00 2001 From: Guillaume Marques Date: Wed, 23 Aug 2023 09:01:31 +0200 Subject: [PATCH 3/5] Update src/Algorithm/conquer.jl --- src/Algorithm/conquer.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Algorithm/conquer.jl b/src/Algorithm/conquer.jl index 0fa38ed97..97b550c5a 100644 --- a/src/Algorithm/conquer.jl +++ b/src/Algorithm/conquer.jl @@ -379,8 +379,6 @@ end function run!(algo::ColCutGenConquer, env::Env, reform::Reformulation, input::AbstractConquerInput) ctx = new_context(type_of_context(algo), algo, reform, input) - node = get_node(input) - restore_from_records!(get_units_to_restore(input), TreeSearch.get_records(node)) return run_colcutgen_conquer!(ctx, env, reform, input) end From e3b113793f53fe954450018b5bd6825d7e18e099 Mon Sep 17 00:00:00 2001 From: Guillaume Marques Date: Wed, 23 Aug 2023 09:56:40 +0200 Subject: [PATCH 4/5] fixed --- src/MathProg/MOIinterface.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/MathProg/MOIinterface.jl b/src/MathProg/MOIinterface.jl index 9f0fdc47d..5bb417ba7 100644 --- a/src/MathProg/MOIinterface.jl +++ b/src/MathProg/MOIinterface.jl @@ -353,7 +353,7 @@ function get_basis(form::F, optimizer::MoiOptimizer) where {F <: Formulation} vars = Dict{VarId,MOI.BasisStatusCode}() for (varid, var) in getvars(form) iscuractive(form, varid) && isexplicit(form, varid) || continue - moi_index = getindex(getmoirecord(var)) + moi_index = getmoiindex(getmoirecord(var)) if moi_index.value != -1 vars[varid] = MOI.get(inner, MOI.VariableBasisStatus(), moi_index) end @@ -362,7 +362,7 @@ function get_basis(form::F, optimizer::MoiOptimizer) where {F <: Formulation} constrs = Dict{ConstrId,MOI.BasisStatusCode}() for (constrid, constr) in getconstrs(form) iscuractive(form, constrid) && isexplicit(form, constrid) || continue - moi_index = getindex(getmoirecord(constr)) + moi_index = getmoiindex(getmoirecord(constr)) if moi_index.value != -1 constrs[constrid] = MOI.get(inner, MOI.ConstraintBasisStatus(), moi_index) end @@ -374,7 +374,7 @@ function set_basis!(form::F, optimizer::MoiOptimizer, basis::Basis) where {F <: inner = getinner(optimizer) for (varid, var) in getvars(form) iscuractive(form, varid) && isexplicit(form, varid) || continue - moi_index = getindex(getmoirecord(var)) + moi_index = getmoiindex(getmoirecord(var)) var_basis = get(basis.vars, varid, nothing) if !isnothing(var_basis) MOI.set(inner, MOI.VariableBasisStatus(), moi_index, var_basis) @@ -382,7 +382,7 @@ function set_basis!(form::F, optimizer::MoiOptimizer, basis::Basis) where {F <: end for (constrid, constr) in getconstrs(form) iscuractive(form, constrid) && isexplicit(form, constrid) || continue - moi_index = getindex(getmoirecord(constr)) + moi_index = getmoiindex(getmoirecord(constr)) constr_basis = get(basis.constrs, constrid, nothing) if !isnothing(constr_basis) MOI.set(inner, MOI.ConstraintBasisStatus(), moi_index, constr_basis) From b1f4bb5e15861b1e4a781273967522fa018a3fcd Mon Sep 17 00:00:00 2001 From: Artur Alves Pessoa Date: Sat, 16 Sep 2023 16:51:37 -0300 Subject: [PATCH 5/5] Fix index -1 when setting the basis --- src/MathProg/MOIinterface.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MathProg/MOIinterface.jl b/src/MathProg/MOIinterface.jl index 5bb417ba7..e7a678d17 100644 --- a/src/MathProg/MOIinterface.jl +++ b/src/MathProg/MOIinterface.jl @@ -376,7 +376,7 @@ function set_basis!(form::F, optimizer::MoiOptimizer, basis::Basis) where {F <: iscuractive(form, varid) && isexplicit(form, varid) || continue moi_index = getmoiindex(getmoirecord(var)) var_basis = get(basis.vars, varid, nothing) - if !isnothing(var_basis) + if !isnothing(var_basis) && moi_index.value != -1 MOI.set(inner, MOI.VariableBasisStatus(), moi_index, var_basis) end end @@ -384,7 +384,7 @@ function set_basis!(form::F, optimizer::MoiOptimizer, basis::Basis) where {F <: iscuractive(form, constrid) && isexplicit(form, constrid) || continue moi_index = getmoiindex(getmoirecord(constr)) constr_basis = get(basis.constrs, constrid, nothing) - if !isnothing(constr_basis) + if !isnothing(constr_basis) && moi_index.value != -1 MOI.set(inner, MOI.ConstraintBasisStatus(), moi_index, constr_basis) end end