From 6e4db3ba40b4887b7f49613420880a61eca9e0b5 Mon Sep 17 00:00:00 2001 From: Guillaume Marques Date: Mon, 16 Oct 2023 17:09:05 +0200 Subject: [PATCH] [presolve] fix local/global bounds computation --- src/Algorithm/presolve/helpers.jl | 7 +- src/Algorithm/presolve/interface.jl | 301 +++++++------ src/Algorithm/presolve/propagation.jl | 164 +++++-- src/MathProg/formulation.jl | 11 +- test/unit/MathProg/dw_decomposition.jl | 1 - test/unit/Presolve/columns.jl | 14 +- test/unit/Presolve/helpers.jl | 20 +- test/unit/Presolve/partial_solution.jl | 20 +- test/unit/Presolve/propagation.jl | 590 ++++++++++++++----------- 9 files changed, 689 insertions(+), 439 deletions(-) diff --git a/src/Algorithm/presolve/helpers.jl b/src/Algorithm/presolve/helpers.jl index 7813c1236..78e3f2385 100644 --- a/src/Algorithm/presolve/helpers.jl +++ b/src/Algorithm/presolve/helpers.jl @@ -248,7 +248,7 @@ function tighten_bounds_presolve_form_repr(form::PresolveFormRepr, tightened_bou col_mask end -function partial_sol_update(form::PresolveFormRepr, lm, um) +function partial_sol_update(form::PresolveFormRepr, lm, um, store_unpropagated_partial_sol) coef_matrix = form.col_major_coef_matrix rhs = form.rhs sense = form.sense @@ -286,7 +286,7 @@ function partial_sol_update(form::PresolveFormRepr, lm, um) return PresolveFormRepr( coef_matrix, new_rhs, sense, new_lbs, new_ubs, partial_sol, lm, um; - unpropagated_partial_solution = new_partial_sol + unpropagated_partial_solution = store_unpropagated_partial_sol ? new_partial_sol : nothing ), row_mask, col_mask @@ -343,6 +343,7 @@ function PresolveFormRepr( tighten_bounds = true, partial_sol = true, shrink = true, + store_unpropagated_partial_sol = true ) row_mask = ones(Bool, presolve_form_repr.nb_constrs) col_mask = ones(Bool, presolve_form_repr.nb_vars) @@ -353,7 +354,7 @@ function PresolveFormRepr( ) end if partial_sol - presolve_form_repr, row_mask, col_mask = partial_sol_update(presolve_form_repr, lm, um) + presolve_form_repr, row_mask, col_mask = partial_sol_update(presolve_form_repr, lm, um, store_unpropagated_partial_sol) end if shrink presolve_form_repr, row_mask, col_mask, fixed_vars = shrink_presolve_form_repr( diff --git a/src/Algorithm/presolve/interface.jl b/src/Algorithm/presolve/interface.jl index 93ffdad37..45996286b 100644 --- a/src/Algorithm/presolve/interface.jl +++ b/src/Algorithm/presolve/interface.jl @@ -113,6 +113,7 @@ function propagate_in_presolve_form( tighten_bounds = true, partial_sol = true, shrink = true, + store_unpropagated_partial_sol = true ) form_repr, row_mask, col_mask, fixed_vars = PresolveFormRepr( form.form, @@ -123,6 +124,7 @@ function propagate_in_presolve_form( tighten_bounds = tighten_bounds, partial_sol = partial_sol, shrink = shrink, + store_unpropagated_partial_sol = store_unpropagated_partial_sol ) col_to_var = form.col_to_var[col_mask] @@ -180,9 +182,9 @@ function create_presolve_reform(reform::Reformulation{DwMaster}) iscuractive(form, constr) && ( getduty(constrid) <= MasterPureConstr || getduty(constrid) <= MasterMixedConstr || - getduty(constrid) <= MasterConvexityConstr || getduty(constrid) <= MasterBranchOnOrigVarConstr || - getduty(constrid) <= MasterUserCutConstr + getduty(constrid) <= MasterUserCutConstr || + getduty(constrid) <= MasterConvexityConstr ) ) original_master = create_presolve_form(master, original_master_vars, original_master_constrs) @@ -201,9 +203,9 @@ function create_presolve_reform(reform::Reformulation{DwMaster}) iscuractive(form, constr) && ( getduty(constrid) <= MasterPureConstr || getduty(constrid) <= MasterMixedConstr || - getduty(constrid) <= MasterConvexityConstr || getduty(constrid) <= MasterBranchOnOrigVarConstr || - getduty(constrid) <= MasterUserCutConstr + getduty(constrid) <= MasterUserCutConstr || + getduty(constrid) <= MasterConvexityConstr ) ) restricted_master = create_presolve_form(master, restricted_master_vars, restricted_master_constrs) @@ -248,10 +250,83 @@ function create_presolve_reform(reform::Reformulation{DwMaster}) return DwPresolveReform(original_master, restricted_master, dw_sps) end +function _update_partial_sol!(form::Formulation{DwMaster}, presolve_form::PresolveFormulation) + # Update partial solution + partial_sol_counter = 0 + for (col, val) in enumerate(presolve_form.form.partial_solution) + var = presolve_form.col_to_var[col] + if getduty(getid(var)) <= MasterArtVar && !iszero(val) + error(""" Infeasible because artificial variable $(getname(form, var)) is not zero. + Fixed to $(val) in partial solution. + """) + end + if !iszero(val) + MathProg.add_to_partial_solution!(form, var, val) + partial_sol_counter += 1 + end + end + return +end + +_update_partial_sol!(form, presolve_form) = nothing + +function _update_bounds!(form::Formulation, presolve_form::PresolveFormulation) + # Update bounds + for (col, (lb, ub)) in enumerate(Iterators.zip( + presolve_form.form.lbs, + presolve_form.form.ubs + )) + @assert !isnan(lb) + @assert !isnan(ub) + var = presolve_form.col_to_var[col] + + if getduty(getid(var)) <= MasterCol + @assert iszero(lb) + setcurlb!(form, var, 0.0) + # ignore the upper bound (we keep Inf) + else + setcurlb!(form, var, lb) + setcurub!(form, var, ub) + end + end + return +end + +# function _update_convexity_constr!(master::Formulation{DwMaster}, sp_presolve_form, sp::Formulation{DwSp}) +# lm_constr = getconstr(master, sp.duty_data.lower_multiplicity_constr_id) +# um_constr = getconstr(master, sp.duty_data.upper_multiplicity_constr_id) + +# @assert !isnothing(lm_constr) && !isnothing(um_constr) + +# lm = sp_presolve_form.form.lower_multiplicity +# um = sp_presolve_form.form.upper_multiplicity + +# setcurrhs!(master, lm_constr, max(lm, 0)) +# setcurrhs!(master, um_constr, max(um, 0)) +# return +# end + +function _update_rhs!(form::Formulation, presolve_form::PresolveFormulation) + for (row, rhs) in enumerate(presolve_form.form.rhs) + constr = presolve_form.row_to_constr[row] + if getduty(getid(constr)) <= MasterConvexityConstr + if getcursense(form, constr) == Less + setcurrhs!(form, constr, max(rhs, 0)) + elseif getcursense(form, constr) == Greater + setcurrhs!(form, constr, max(rhs, 0)) + end + else + setcurrhs!(form, constr, rhs) + end + end + return +end + function update_form_from_presolve!( - form::Formulation, presolve_form::PresolveFormulation; update_rhs = true + form::Formulation, presolve_form::PresolveFormulation; + update_rhs = true, + update_partial_sol = true, ) - println("Updating formulation #$(getuid(form)).") # Deactivate Constraints constr_deactivation_counter = 0 for constr_id in presolve_form.deactivated_constrs @@ -260,7 +335,6 @@ function update_form_from_presolve!( constr_deactivation_counter += 1 end end - println("\t Deactivating $(constr_deactivation_counter) constraints.") # Fixed variables var_fix_counter = 0 @@ -273,80 +347,40 @@ function update_form_from_presolve!( var_fix_counter += 1 end end - println("\t Fixing $(var_fix_counter) variables.") - # Update rhs if update_rhs - for (row, rhs) in enumerate(presolve_form.form.rhs) - constr = presolve_form.row_to_constr[row] - - if getduty(getid(constr)) <= MasterConvexityConstr - if getcursense(form, constr) == Less - setcurrhs!(form, constr, max(rhs, 0)) - elseif getcursense(form, constr) == Greater - setcurrhs!(form, constr, max(rhs, 0)) - end - else - setcurrhs!(form, constr, rhs) - end - end + _update_rhs!(form, presolve_form) end - # Update bounds - for (col, (lb, ub)) in enumerate(Iterators.zip( - presolve_form.form.lbs, - presolve_form.form.ubs - )) - @assert !isnan(lb) - @assert !isnan(ub) - var = presolve_form.col_to_var[col] - - if getduty(getid(var)) <= MasterCol - @assert iszero(lb) - setcurlb!(form, var, 0.0) - # ignore the upper bound (we keep Inf) - else - setcurlb!(form, var, lb) - setcurub!(form, var, ub) - end - end + _update_bounds!(form, presolve_form) - # Update partial solution - partial_sol_counter = 0 - for (col, val) in enumerate(presolve_form.form.partial_solution) - var = presolve_form.col_to_var[col] - if getduty(getid(var)) <= MasterArtVar && !iszero(val) - error(""" Infeasible because artificial variable $(getname(form, var)) is not zero. - Fixed to $(val) in partial solution. - """) - end - if !iszero(val) - MathProg.add_to_partial_solution!(form, var, val) - partial_sol_counter += 1 - end + if update_partial_sol + _update_partial_sol!(form, presolve_form) end - println("\t Adding $(partial_sol_counter) variables to partial solution.") return end -function update_reform_from_presolve!(reform::Reformulation{DwMaster}, presolve_reform::DwPresolveReform) - master = getmaster(reform) - +function update_reform_from_presolve!( + master::Formulation{DwMaster}, + dw_pricing_sps::Dict, + presolve_reform::DwPresolveReform +) # Update master presolve_restr_master = presolve_reform.restricted_master - println("Updating restricted master.") update_form_from_presolve!(master, presolve_restr_master) # Update subproblems - presolve_repr_master = presolve_reform.original_master - for (spid, sp) in get_dw_pricing_sps(reform) + for (spid, sp) in dw_pricing_sps sp_presolve_form = presolve_reform.dw_sps[spid] - println("Updating subproblem.") update_form_from_presolve!(sp, sp_presolve_form) end - println("Updating representative master.") - update_form_from_presolve!(master, presolve_repr_master) + presolve_repr_master = presolve_reform.original_master + update_form_from_presolve!( + master, presolve_repr_master; + update_partial_sol = false, + update_rhs = false + ) return end @@ -382,13 +416,75 @@ struct PresolveOutput feasible::Bool end +function propagate_partial_sol_into_master(presolve_reform, dw_pricing_sps) + # Step 1 (before main loop): + # Create the partial solution + new_restr_master = propagate_in_presolve_form( + presolve_reform.restricted_master, + Int[], # we don't perform constraint deactivation + Dict{Int, Tuple{Float64, Bool, Float64, Bool}}(); # we don't perform bound tightening on the restricted master. + tighten_bounds = false, + shrink = false + ) + presolve_reform.restricted_master = new_restr_master + + # Step 2: Propagate the partial solution to the local bounds. + propagate_partial_sol_to_repr_master!( + dw_pricing_sps, + presolve_reform + ) + + new_repr_master = propagate_in_presolve_form( + presolve_reform.original_master, + Int[], + Dict{Int, Tuple{Float64, Bool, Float64, Bool}}(); + tighten_bounds = false, + shrink = false, + store_unpropagated_partial_sol = false + ) + presolve_reform.original_master = new_repr_master + + # The right rhs is the one from the restricted master because the master may + # contain non-robust cuts. + @assert length(presolve_reform.restricted_master.form.rhs) == length(presolve_reform.original_master.form.rhs) + for (row, rhs) in enumerate(presolve_reform.restricted_master.form.rhs) + presolve_reform.original_master.form.rhs[row] = rhs + end +end + +function presolve_iteration!(presolve_reform, master, dw_pricing_sps) + # Step 5: Propagate and strengthen local and global bounds. + propagate_global_to_local_bounds!(master, dw_pricing_sps, presolve_reform) + propagate_local_to_global_bounds!(master, dw_pricing_sps, presolve_reform) + propagate_global_to_local_bounds!(master, dw_pricing_sps, presolve_reform) + propagate_local_to_global_bounds!(master, dw_pricing_sps, presolve_reform) + + # Step 3: presolve the respresentative master. + # Bounds tightening, we do not shrink the formulation. + tightened_bounds_repr = bounds_tightening(presolve_reform.original_master.form) + new_repr_master = propagate_in_presolve_form( + presolve_reform.original_master, + Int[], + + tightened_bounds_repr; shrink = false + ) + + presolve_reform.original_master = new_repr_master + + # Step 6: Shrink the formulation (remove fixed variables). + new_restr_master = propagate_in_presolve_form( + presolve_reform.restricted_master, + Int[], + Dict{Int, Tuple{Float64, Bool, Float64, Bool}}(); + tighten_bounds = false, + partial_sol = false + ) + + presolve_reform.restricted_master = new_restr_master + return +end + function run!(algo::PresolveAlgorithm, ::Env, reform::Reformulation, input::PresolveInput)::PresolveOutput - # TO DO : if input.partial_sol_to_fix is not empty, we first need to - # 1) augment partial solution inside reform.master with input.partial_sol_to_fix - # 2) change RHS of master constraints correspondigly - # 3) fix pure master variables in input.partial_sol_to_fix - # 4) update global bounds of subproblem variables participating in columns in input.partial_sol_to_fix - # (see document FixingColumnInColuna.md) # Should be move in the diving (when generating the formulation of the children because # formulation is the single source of truth). @@ -403,57 +499,18 @@ function run!(algo::PresolveAlgorithm, ::Env, reform::Reformulation, input::Pres presolve_reform = create_presolve_reform(reform) + propagate_partial_sol_into_master(presolve_reform, get_dw_pricing_sps(reform)) + for i in 1:3 println("**** Presolve step $i ****") - # Step 1: we first perform presolve on the restricted master to update the rhs on the constraints - # and determine the new partial solution. - new_restr_master = propagate_in_presolve_form( - presolve_reform.restricted_master, - Int[], # we don't perform constraint deactivation - Dict{Int, Tuple{Float64, Bool, Float64, Bool}}(); # we don't perform bound tightening on the restricted master. - tighten_bounds = false, - shrink = false - ) - - # Step 2: we propagate the new rhs to the respresentative master. - @assert length(new_restr_master.form.rhs) == length(presolve_reform.original_master.form.rhs) - for (row, rhs) in enumerate(new_restr_master.form.rhs) - presolve_reform.original_master.form.rhs[row] = rhs - end - - # Step 3: presolve the respresentative master. - # Bounds tightening, we do not shrink the formulation. - print("Presolving representative master #1. ") - tightened_bounds_repr = bounds_tightening(presolve_reform.original_master.form) - println("$(length(tightened_bounds_repr)) tightened bounds. ") - new_repr_master = propagate_in_presolve_form( - presolve_reform.original_master, Int[], tightened_bounds_repr; shrink = false - ) - - presolve_reform.restricted_master = new_restr_master - presolve_reform.original_master = new_repr_master - - # Step 4: Propagate the partial solution to the local bounds. - propagate_partial_sol_to_local_bounds!(reform, presolve_reform) - - # Step 5: Propagate and strengthen local and global bounds. - propagate_local_to_global_bounds!(reform, presolve_reform) - propagate_global_to_local_bounds!(reform, presolve_reform) - propagate_local_to_global_bounds!(reform, presolve_reform) - - # Step 6: Shrink the formulation (remove fixed variables). - new_restr_master = propagate_in_presolve_form( - presolve_reform.restricted_master, - Int[], - Dict{Int, Tuple{Float64, Bool, Float64, Bool}}(); - tighten_bounds = false, - partial_sol = false - ) - presolve_reform.restricted_master = new_restr_master + presolve_iteration!(presolve_reform, getmaster(reform), get_dw_pricing_sps(reform)) end - update_reform_from_presolve!(reform, presolve_reform) - + update_reform_from_presolve!( + getmaster(reform), + get_dw_pricing_sps(reform), + presolve_reform + ) return PresolveOutput(true) end @@ -470,15 +527,3 @@ function _column_is_proper(col_id, sp_form) return true end -# function treat!(algo::PresolveAlgorithm, reform::Reformulation{DwMaster}) -# presolve_reform = create_presolve_reform(reform) - -# @show presolve_reform.original_master.form - -# @show rows_to_deactivate!(presolve_reform.original_master.form) -# @show bounds_tightening(presolve_reform.original_master.form) - -# @show presolve_reform - -# update_reform!(reform, presolve_reform) -# end diff --git a/src/Algorithm/presolve/propagation.jl b/src/Algorithm/presolve/propagation.jl index a7625a77c..3fe2d3657 100644 --- a/src/Algorithm/presolve/propagation.jl +++ b/src/Algorithm/presolve/propagation.jl @@ -56,22 +56,13 @@ function propagate_var_bounds_from!(dest::PresolveFormulation, src::PresolveForm return end -function propagate_partial_sol_to_local_bounds!(reform::Reformulation, presolve_form_repr::DwPresolveReform) - master = getmaster(reform) - presolve_restr_master = presolve_form_repr.restricted_master - for (spid, spform) in get_dw_pricing_sps(reform) - presolve_sp = presolve_form_repr.dw_sps[spid] - propagate_partial_sol_to_local_bounds!(presolve_sp, presolve_restr_master, spform, master) - end - presolve_restr_master.form.unpropagated_partial_solution = zeros(Float64, presolve_restr_master.form.nb_vars) - presolve_restr_master.form.unpropagated_partial_solution_flag = false - return -end - -function propagate_local_to_global_bounds!(reform::Reformulation, presolve_reform_repr::DwPresolveReform) - master = getmaster(reform) +function propagate_local_to_global_bounds!( + master::Formulation{DwMaster}, + dw_pricing_sps::Dict, + presolve_reform_repr::DwPresolveReform +) presolve_repr_master = presolve_reform_repr.original_master - for (spid, spform) in get_dw_pricing_sps(reform) + for (spid, spform) in dw_pricing_sps presolve_sp = presolve_reform_repr.dw_sps[spid] propagate_global_bounds!(presolve_repr_master, master, presolve_sp, spform) end @@ -98,35 +89,64 @@ function propagate_global_bounds!(presolve_repr_master::PresolveFormulation, mas return end -function propagate_global_to_local_bounds!(reform::Reformulation, presolve_reform_repr::DwPresolveReform) - master = getmaster(reform) +function propagate_global_to_local_bounds!( + master::Formulation{DwMaster}, + dw_pricing_sps::Dict, + presolve_reform_repr::DwPresolveReform +) presolve_repr_master = presolve_reform_repr.original_master - for (spid, spform) in get_dw_pricing_sps(reform) + for (spid, spform) in dw_pricing_sps presolve_sp = presolve_reform_repr.dw_sps[spid] propagate_local_bounds!(presolve_repr_master, master, presolve_sp, spform) end return end +function _get_local_lb(global_lb, prec_local_lb, lm, um) + if global_lb < 0 + return max(global_lb, prec_local_lb) + elseif global_lb > 0 + return min(global_lb, prec_local_lb) + end + if prec_local_lb < 0 && iszero(um) || prec_local_lb > 0 && iszero(lm) + return prec_local_lb + end + return 0.0 +end + +function _get_local_ub(global_ub, prec_local_ub, lm, um) + if global_ub < 0 + return max(global_ub, prec_local_ub) + elseif global_ub > 0 + return min(global_ub, prec_local_ub) + end + if prec_local_ub < 0 && iszero(lm) || prec_local_ub > 0 && iszero(um) + return prec_local_ub + end + return 0.0 +end + function propagate_local_bounds!(presolve_repr_master::PresolveFormulation, master::Formulation, presolve_sp::PresolveFormulation, spform::Formulation) # TODO: does not work with representatives of multiple subproblems. lm = presolve_sp.form.lower_multiplicity um = presolve_sp.form.upper_multiplicity - for (i, var) in enumerate(presolve_sp.col_to_var) + for (i, var) in enumerate(presolve_sp.col_to_var) repr_col = get(presolve_repr_master.var_to_col, getid(var), nothing) if !isnothing(repr_col) global_lb = presolve_repr_master.form.lbs[repr_col] global_ub = presolve_repr_master.form.ubs[repr_col] - local_lb = presolve_sp.form.lbs[i] - local_ub = presolve_sp.form.ubs[i] + prec_local_lb = presolve_sp.form.lbs[i] + prec_local_ub = presolve_sp.form.ubs[i] + local_lb = _get_local_lb(global_lb, prec_local_lb, lm, um) + local_ub = _get_local_ub(global_ub, prec_local_ub, lm, um) if !isinf(global_lb) && !isinf(local_ub) - new_local_lb = global_lb - local_ub * (local_ub < 0 ? um : lm) + new_local_lb = global_lb - local_ub * (local_ub > 0 ? um : lm) presolve_sp.form.lbs[i] = max(new_local_lb, local_lb) end - + if !isinf(global_ub) && !isinf(local_lb) - new_local_ub = global_ub - local_lb * (local_lb < 0 ? lm : um) + new_local_ub = global_ub - local_lb * (local_lb > 0 ? lm : um) presolve_sp.form.ubs[i] = min(new_local_ub, local_ub) end end @@ -134,7 +154,7 @@ function propagate_local_bounds!(presolve_repr_master::PresolveFormulation, mast return end -function propagate_partial_sol_to_local_bounds!(presolve_sp::PresolveFormulation, presolve_master::PresolveFormulation, spform::Formulation, master::Formulation) +function propagate_partial_sol_to_global_bounds!(presolve_sp::PresolveFormulation, presolve_master::PresolveFormulation, spform::Formulation, master::Formulation) partial_solution = zeros(Float64, presolve_sp.form.nb_vars) # Get new columns in partial solution. @@ -160,9 +180,57 @@ function propagate_partial_sol_to_local_bounds!(presolve_sp::PresolveFormulation end new_column_explored = true end + return +end + +function partial_sol_on_repr( + dw_pricing_sps::Dict, + presolve_reform_repr::DwPresolveReform +) + presolve_master_repr = presolve_reform_repr.original_master + partial_solution = zeros(Float64, presolve_master_repr.form.nb_vars) + + # partial solution + presolve_master_restr = presolve_reform_repr.restricted_master + + dw_pricing_sps = dw_pricing_sps + nb_fixed_columns = Dict(spid => 0 for (spid, _) in dw_pricing_sps) + new_column_explored = false + for (col, partial_sol_value) in enumerate(presolve_master_restr.form.unpropagated_partial_solution) + if abs(partial_sol_value) > Coluna.TOL + var = presolve_master_restr.col_to_var[col] + varid = getid(var) + spid = getoriginformuid(varid) + spform = get(dw_pricing_sps, spid, nothing) + @assert !isnothing(spform) + column = @view get_primal_sol_pool(spform).solutions[varid,:] + for (varid, val) in column + getduty(varid) <= DwSpPricingVar || continue + master_repr_var_col = get(presolve_master_repr.var_to_col, varid, nothing) + if !isnothing(master_repr_var_col) + partial_solution[master_repr_var_col] += val * partial_sol_value + end + if !new_column_explored + nb_fixed_columns[spid] += partial_sol_value + new_column_explored = true + end + end + new_column_explored = false + end + end + return partial_solution, nb_fixed_columns +end - new_lbs = zeros(Float64, presolve_sp.form.nb_vars) - new_ubs = zeros(Float64, presolve_sp.form.nb_vars) +function propagate_partial_sol_to_repr_master!( + dw_pricing_sps::Dict, + presolve_reform::DwPresolveReform +) + partial_solution, nb_fixed_columns_per_sp = partial_sol_on_repr(dw_pricing_sps, presolve_reform) + + presolve_repr_master = presolve_reform.original_master + + new_lbs = zeros(Float64, presolve_repr_master.form.nb_vars) + new_ubs = zeros(Float64, presolve_repr_master.form.nb_vars) # when there is a partial solution, we update the bound so that the lower bound # on the absolute value of the variable is improved. @@ -171,30 +239,42 @@ function propagate_partial_sol_to_local_bounds!(presolve_sp::PresolveFormulation # -3 <= x <= 3 & x = -1 -> -3 <= x <= -1 # 2 <= x <= 4 & x = 3 -> 3 <= x <= 4 # -5 <= x <= 0 & x = -2 -> -5 <= x <= -2 - for (col, (val, lb, ub)) in enumerate(Iterators.zip(partial_solution, presolve_sp.form.lbs, presolve_sp.form.ubs)) - if val < 0 - new_lbs[col] = lb - val - new_ubs[col] = min(0, ub - val) - elseif val > 0 - new_lbs[col] = max(0, lb - val) - new_ubs[col] = ub - val + for (col, (val, lb, ub)) in enumerate( + Iterators.zip( + partial_solution, + presolve_repr_master.form.lbs, + presolve_repr_master.form.ubs + ) + ) + if val > 0 + new_lbs[col] = val + new_ubs[col] = ub + elseif val < 0 + new_lbs[col] = lb + new_ubs[col] = val else new_lbs[col] = lb new_ubs[col] = ub end - if lb > ub + if new_lbs[col] > new_ubs[col] error("Infeasible.") end end - presolve_sp.form.lbs = new_lbs - presolve_sp.form.ubs = new_ubs + presolve_repr_master.form.lbs = new_lbs + presolve_repr_master.form.ubs = new_ubs - lm = presolve_sp.form.lower_multiplicity - um = presolve_sp.form.upper_multiplicity + for (spid, presolve_sp) in presolve_reform.dw_sps + lm = presolve_sp.form.lower_multiplicity + um = presolve_sp.form.upper_multiplicity - presolve_sp.form.lower_multiplicity = max(0, lm - nb_fixed_columns) - presolve_sp.form.upper_multiplicity = max(0, um - nb_fixed_columns) # TODO if < 0 -> error + presolve_sp.form.lower_multiplicity = max(0, lm - nb_fixed_columns_per_sp[spid]) + presolve_sp.form.upper_multiplicity = max(0, um - nb_fixed_columns_per_sp[spid]) # TODO if < 0 -> error + end + + presolve_restr_master = presolve_reform.restricted_master + presolve_restr_master.form.unpropagated_partial_solution = zeros(Float64, presolve_restr_master.form.nb_vars) + presolve_restr_master.form.unpropagated_partial_solution_flag = false return -end +end \ No newline at end of file diff --git a/src/MathProg/formulation.jl b/src/MathProg/formulation.jl index 024f81b84..4defd1f07 100644 --- a/src/MathProg/formulation.jl +++ b/src/MathProg/formulation.jl @@ -694,6 +694,14 @@ function _show_variables(io::IO, form::Formulation) end end +function _show_partial_sol(io::IO, form::Formulation) + println(io, "Partial solution:") + for (varid, val) in form.manager.partial_solution + println(io, getname(form, varid), " = ", val) + end + return +end + function Base.show(io::IO, form::Formulation{Duty}) where {Duty <: AbstractFormDuty} compact = get(io, :compact, false) if compact @@ -703,7 +711,8 @@ function Base.show(io::IO, form::Formulation{Duty}) where {Duty <: AbstractFormD println(io, "Formulation id = ", getuid(form)) _show_obj_fun(io, form) _show_constraints(io, form) - _show_variables(io, form) + #_show_variables(io, form) + _show_partial_sol(io, form) end return end diff --git a/test/unit/MathProg/dw_decomposition.jl b/test/unit/MathProg/dw_decomposition.jl index b641f6a5b..f7d50f77e 100644 --- a/test/unit/MathProg/dw_decomposition.jl +++ b/test/unit/MathProg/dw_decomposition.jl @@ -279,7 +279,6 @@ function dw_decomposition_repr() master_vars = Dict(getname(master, varid) => var for (varid, var) in Coluna.MathProg.getvars(master)) master_constrs = Dict(getname(master, constrid) => constr for (constrid, constr) in Coluna.MathProg.getconstrs(master)) - @show length(master_vars) @test Coluna.MathProg.getcurlb(master, master_vars["e1"]) == 1.0 * (0 + 1) @test Coluna.MathProg.getcurub(master, master_vars["e1"]) == 2.0 * (2 + 3) @test Coluna.MathProg.getcurrhs(master, master_constrs["c1"]) == 4.0 diff --git a/test/unit/Presolve/columns.jl b/test/unit/Presolve/columns.jl index 5b564c7bd..bd845eba1 100644 --- a/test/unit/Presolve/columns.jl +++ b/test/unit/Presolve/columns.jl @@ -16,11 +16,11 @@ function test_non_proper_column1() Coluna.MathProg.DwMaster(), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 2.0, nothing), - ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC2", Coluna.MathProg.MasterCol, 2.0, 0.0, 1.0, nothing), - ("MC3", Coluna.MathProg.MasterCol, 4.0, 0.0, 1.0, nothing), + ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 2.0, nothing, nothing), + ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, 2), + ("MC2", Coluna.MathProg.MasterCol, 2.0, 0.0, 1.0, nothing, 2), + ("MC3", Coluna.MathProg.MasterCol, 4.0, 0.0, 1.0, nothing, 2), ], [ # name, duty, rhs, sense , id @@ -53,8 +53,8 @@ function test_non_proper_column1() ), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["x1"])), - ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 2.0, Coluna.Algorithm.getid(master_name_to_var["x2"])) + ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["x1"]), nothing), + ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 2.0, Coluna.Algorithm.getid(master_name_to_var["x2"]), nothing) ], [ # name, duty, rhs, sense, id diff --git a/test/unit/Presolve/helpers.jl b/test/unit/Presolve/helpers.jl index 4d501c2fc..0e12c6e5a 100644 --- a/test/unit/Presolve/helpers.jl +++ b/test/unit/Presolve/helpers.jl @@ -87,7 +87,10 @@ function test_presolve_builder2() rows_to_deactivate = [1, 3, 6] tightened_bounds = Dict{Int, Tuple{Float64, Bool, Float64, Bool}}() - form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr(form, rows_to_deactivate, tightened_bounds, 1.0, 1.0) + form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr( + form, rows_to_deactivate, tightened_bounds, 1.0, 1.0; + store_unpropagated_partial_sol = false + ) @test form2.nb_vars == 7 @test form2.nb_constrs == 3 @test all(form2.col_major_coef_matrix .== coef_matrix[[2, 4, 5], :]) @@ -139,7 +142,10 @@ function test_presolve_builder3() # <= -1 - 2 + 4 -> 1 # == -6 +2*2 - 5.5 -> -7.5 - form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr(form, rows_to_deactivate, tightened_bounds, 1.0, 1.0) + form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr( + form, rows_to_deactivate, tightened_bounds, 1.0, 1.0; + store_unpropagated_partial_sol = false + ) @test form2.nb_vars == 3 @test form2.nb_constrs == 6 @test all(form2.col_major_coef_matrix .== coef_matrix[:, [2, 4, 5]]) @@ -177,7 +183,10 @@ function test_presolve_builder4() 3 => (-1, false, 3, false), 6 => (0.5, true, 0.5, true) # the flag forces the update! ) - form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr(form, rows_to_deactivate, tightened_bounds, 1.0, 1.0) + form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr( + form, rows_to_deactivate, tightened_bounds, 1.0, 1.0; + store_unpropagated_partial_sol = false + ) @test form2.nb_vars == 6 @test form2.nb_constrs == 6 @test all(form2.col_major_coef_matrix .== coef_matrix[:, [1, 2, 3, 4, 5, 7]]) @@ -211,7 +220,10 @@ function test_presolve_builder5() 3 => (1, true, 2, true) ) - form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr(form, rows_to_deactivate, tightened_bounds, 1.0, 1.0) + form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr( + form, rows_to_deactivate, tightened_bounds, 1.0, 1.0; + store_unpropagated_partial_sol = false + ) @test form2.nb_vars == 3 @test form2.nb_constrs == 2 @test all(form2.col_major_coef_matrix .== coef_matrix) diff --git a/test/unit/Presolve/partial_solution.jl b/test/unit/Presolve/partial_solution.jl index ac29ab725..8bd2a3c80 100644 --- a/test/unit/Presolve/partial_solution.jl +++ b/test/unit/Presolve/partial_solution.jl @@ -27,7 +27,10 @@ function test_partial_solution1() 2 => (2, true, Inf, false) ) - form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr(form, rows_to_deactivate, tightened_bounds, 1, 1) + form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr( + form, rows_to_deactivate, tightened_bounds, 1, 1; + store_unpropagated_partial_sol = false + ) @test form2.nb_vars == 2 @test form2.nb_constrs == 1 @test all(form2.col_major_coef_matrix .== coef_matrix) @@ -68,7 +71,10 @@ function test_partial_solution2() 2 => (2, true, Inf, false) ) - form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr(form, rows_to_deactivate, tightened_bounds, 1, 1) + form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr( + form, rows_to_deactivate, tightened_bounds, 1, 1; + store_unpropagated_partial_sol = false + ) @test form2.nb_vars == 2 @test form2.nb_constrs == 1 @test all(form2.col_major_coef_matrix .== coef_matrix) @@ -109,7 +115,10 @@ function test_partial_solution3() 2 => (-10, false, 8, true) ) - form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr(form, rows_to_deactivate, tightened_bounds, 1, 1) + form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr( + form, rows_to_deactivate, tightened_bounds, 1, 1; + store_unpropagated_partial_sol = false + ) @test form2.nb_vars == 2 @test form2.nb_constrs == 2 @test all(form2.col_major_coef_matrix .== coef_matrix) @@ -149,7 +158,10 @@ function test_partial_solution4() 2 => (-Inf, false, -1.0, true) ) - form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr(form, rows_to_deactivate, tightened_bounds, 1, 1) + form2, _, _, _ = Coluna.Algorithm.PresolveFormRepr( + form, rows_to_deactivate, tightened_bounds, 1, 1; + store_unpropagated_partial_sol = false + ) @test form2.nb_vars == 2 @test form2.nb_constrs == 2 @test all(form2.col_major_coef_matrix .== coef_matrix) diff --git a/test/unit/Presolve/propagation.jl b/test/unit/Presolve/propagation.jl index 5591b7407..ed0b20ebd 100644 --- a/test/unit/Presolve/propagation.jl +++ b/test/unit/Presolve/propagation.jl @@ -29,11 +29,25 @@ function _presolve_propagation_vars(form, var_descriptions) vars = Tuple{String, Coluna.MathProg.Variable}[] - for (name, duty, cost, lb, ub, id) in var_descriptions + for (name, duty, cost, lb, ub, id, origin_form_id) in var_descriptions if isnothing(id) - var = Coluna.MathProg.setvar!(form, name, duty, cost = cost, lb = lb, ub = ub) + var = if isnothing(origin_form_id) + Coluna.MathProg.setvar!(form, name, duty, cost = cost, lb = lb, ub = ub) + else + Coluna.MathProg.setvar!( + form, name, duty, cost = cost, lb = lb, ub = ub, id = Coluna.MathProg.VarId( + duty, + form.env.var_counter += 1, + origin_form_id; + ) + ) + end else - id_of_clone = ClMP.VarId(id; duty = duty) + id_of_clone = if isnothing(origin_form_id) + ClMP.VarId(id; duty = duty) + else + ClMP.VarId(id; duty = duty, origin_form_uid = origin_form_id) + end var = Coluna.MathProg.setvar!(form, name, duty; id = id_of_clone, cost = cost, lb = lb, ub = ub) end push!(vars, (name, var)) @@ -131,13 +145,13 @@ function test_constr_removing_propagation_from_original_to_master() Coluna.MathProg.Original(), [ # name, duty, cost, lb, ub, id - ("x", Coluna.MathProg.OriginalVar, 1.0, 0.0, 1.0, nothing), - ("y", Coluna.MathProg.OriginalVar, 1.0, 0.0, 1.0, nothing) + ("x", Coluna.MathProg.OriginalVar, 1.0, 0.0, 1.0, nothing, nothing), + ("y", Coluna.MathProg.OriginalVar, 1.0, 0.0, 1.0, nothing, nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.OriginalConstr, 1.0, ClMP.Less, nothing), - ("c2", Coluna.MathProg.OriginalConstr, 3.0, ClMP.Less, nothing) + ("c1", Coluna.MathProg.OriginalConstr, 1.0, ClMP.Less, nothing, nothing), + ("c2", Coluna.MathProg.OriginalConstr, 3.0, ClMP.Less, nothing, nothing) ] ) @@ -150,15 +164,15 @@ function test_constr_removing_propagation_from_original_to_master() Coluna.MathProg.DwMaster(), [ # name, duty, cost, lb, ub, id - ("_x", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(orig_name_to_var["x"])), - ("_y", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(orig_name_to_var["y"])), - ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("a", Coluna.MathProg.MasterArtVar, 1000.0, 0.0, Inf, nothing) + ("_x", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(orig_name_to_var["x"]), nothing), + ("_y", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(orig_name_to_var["y"]), nothing), + ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("a", Coluna.MathProg.MasterArtVar, 1000.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, lb, ub, id - ("c1", Coluna.MathProg.MasterPureConstr, 1.0, ClMP.Less, Coluna.Algorithm.getid(orig_name_to_constr["c1"])), - ("c2", Coluna.MathProg.MasterPureConstr, 3.0, ClMP.Less, Coluna.Algorithm.getid(orig_name_to_constr["c2"])) + ("c1", Coluna.MathProg.MasterPureConstr, 1.0, ClMP.Less, Coluna.Algorithm.getid(orig_name_to_constr["c1"]), nothing), + ("c2", Coluna.MathProg.MasterPureConstr, 3.0, ClMP.Less, Coluna.Algorithm.getid(orig_name_to_constr["c2"]), nothing) ] ) @@ -205,21 +219,26 @@ function test_constr_removing_propagation_from_original_to_subproblem() Coluna.MathProg.Original(), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.OriginalVar, 1.0, 0.0, 1.0, nothing), - ("x2", Coluna.MathProg.OriginalVar, 1.0, 0.0, 1.0, nothing), - ("y1", Coluna.MathProg.OriginalVar, 1.0, 0.0, 2.0, nothing), - ("y2", Coluna.MathProg.OriginalVar, 1.0, 0.0, 2.0, nothing) + ("x1", Coluna.MathProg.OriginalVar, 1.0, 0.0, 1.0, nothing, nothing), + ("x2", Coluna.MathProg.OriginalVar, 1.0, 0.0, 1.0, nothing, nothing), + ("y1", Coluna.MathProg.OriginalVar, 1.0, 0.0, 2.0, nothing, nothing), + ("y2", Coluna.MathProg.OriginalVar, 1.0, 0.0, 2.0, nothing, nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.OriginalConstr, 3.0, ClMP.Less, nothing), - ("c2", Coluna.MathProg.OriginalConstr, 2.0, ClMP.Less, nothing), - ("c3", Coluna.MathProg.OriginalConstr, 1.0, ClMP.Less, nothing) + ("c1", Coluna.MathProg.OriginalConstr, 3.0, ClMP.Less, nothing, nothing), + ("c2", Coluna.MathProg.OriginalConstr, 2.0, ClMP.Less, nothing, nothing), + ("c3", Coluna.MathProg.OriginalConstr, 1.0, ClMP.Less, nothing, nothing) ] ) orig_presolve_form = _presolve_formulation( - ["x1", "x2", "y1", "y2"], ["c1", "c2", "c3"], [1 1 1 1; 1 1 0 0; 0 0 1 1], orig_form, orig_name_to_var, orig_name_to_constr + ["x1", "x2", "y1", "y2"], + ["c1", "c2", "c3"], + [1 1 1 1; 1 1 0 0; 0 0 1 1], + orig_form, + orig_name_to_var, + orig_name_to_constr ) sp1_form, sp1_name_to_var, sp1_name_to_constr = _mathprog_formulation!( @@ -229,12 +248,12 @@ function test_constr_removing_propagation_from_original_to_subproblem() ), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(orig_name_to_var["x1"])), - ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(orig_name_to_var["x2"])) + ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(orig_name_to_var["x1"]), nothing), + ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(orig_name_to_var["x2"]), nothing) ], [ # name, duty, rhs, sense, id - ("c2", Coluna.MathProg.DwSpPureConstr, 2.0, ClMP.Less, Coluna.Algorithm.getid(orig_name_to_constr["c2"])) + ("c2", Coluna.MathProg.DwSpPureConstr, 2.0, ClMP.Less, Coluna.Algorithm.getid(orig_name_to_constr["c2"]), nothing) ], ) @@ -249,12 +268,12 @@ function test_constr_removing_propagation_from_original_to_subproblem() ), [ # name, duty, cost, lb, ub, id - ("y1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(orig_name_to_var["y1"])), - ("y2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(orig_name_to_var["y2"])) + ("y1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(orig_name_to_var["y1"]), nothing), + ("y2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(orig_name_to_var["y2"]), nothing) ], [ # name, duty, rhs, sense, id - ("c3", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Less, Coluna.Algorithm.getid(orig_name_to_constr["c3"])) + ("c3", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Less, Coluna.Algorithm.getid(orig_name_to_constr["c3"]), nothing) ], ) @@ -295,30 +314,34 @@ function test_var_bound_propagation_within_restricted_master() Coluna.MathProg.DwMaster(), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("y1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("y2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, Inf, nothing), - ("MC2", Coluna.MathProg.MasterCol, 1.0, 1.0, Inf, nothing), - ("MC3", Coluna.MathProg.MasterCol, 1.0, 0.0, Inf, nothing), - ("a", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing) + ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("y1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("y2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, Inf, nothing, nothing), + ("MC2", Coluna.MathProg.MasterCol, 1.0, 1.0, Inf, nothing, nothing), + ("MC3", Coluna.MathProg.MasterCol, 1.0, 0.0, Inf, nothing, nothing), + ("a", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, sense , id - ("c1", Coluna.MathProg.MasterMixedConstr, 1.0, ClMP.Greater, nothing), - ("c2", Coluna.MathProg.MasterConvexityConstr, 2.0, ClMP.Less, nothing), - ("c3", Coluna.MathProg.MasterConvexityConstr, 0.0, ClMP.Greater, nothing) + ("c1", Coluna.MathProg.MasterMixedConstr, 1.0, ClMP.Greater, nothing, nothing), + ("c2", Coluna.MathProg.MasterConvexityConstr, 2.0, ClMP.Less, nothing, nothing), + ("c3", Coluna.MathProg.MasterConvexityConstr, 0.0, ClMP.Greater, nothing, nothing) ] ) master_presolve_form = _presolve_formulation( ["MC1", "MC2", "MC3", "a"], ["c1", "c2", "c3"], [1 1 1 1; 1 1 1 0; 1 1 1 0], master_form, master_name_to_var, master_constr_to_var ) - + result = Coluna.Algorithm.bounds_tightening(master_presolve_form.form) - new_master_presolve_form = Coluna.Algorithm.propagate_in_presolve_form(master_presolve_form, Int[], result; shrink = false) - new_master_presolve_form.form.unpropagated_partial_solution_flag = false + new_master_presolve_form = Coluna.Algorithm.propagate_in_presolve_form( + master_presolve_form, + Int[], + result; + store_unpropagated_partial_sol = false + ) no_tightening = Dict{Int, Tuple{Float64, Bool, Float64, Bool}}() new_master_presolve_form = Coluna.Algorithm.propagate_in_presolve_form(new_master_presolve_form, Int[], no_tightening; tighten_bounds=false, partial_sol = false) @@ -342,14 +365,14 @@ register!(unit_tests, "presolve_propagation", test_var_bound_propagation_within_ function test_col_bounds_propagation_from_restricted_master() # Original Master # min x1 + x2 - # s.t. x1 + x2 >= 10 - # 1 <= x1 <= 2 (repr) - # 1 <= x2 <= 3 (repr) + # s.t. x1 + x2 >= 0 + # 1 <= x1 <= 4 (repr) + # 1 <= x2 <= 6 (repr) # Restricted master # min 2MC1 + 3MC2 + 3MC3 + 1000a1 - # s.t. 2MC1 + 3MC2 + 3MC3 + a1 >= 10 - # MC1 + MC2 + MC3 >= 0 (convexity) + # s.t. 2MC1 + 3MC2 + 3MC3 + a1 >= 0 + # MC1 + MC2 + MC3 >= 1 (convexity) # MC1 + MC2 + MC3 <= 2 (convexity) # MC1, MC2, MC3 >= 0 @@ -364,22 +387,24 @@ function test_col_bounds_propagation_from_restricted_master() Coluna.MathProg.DwMaster(), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 1.0, 2.0, nothing), - ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 1.0, 3.0, nothing), - ("MC1", Coluna.MathProg.MasterCol, 2.0, 0.0, Inf, nothing), - ("MC2", Coluna.MathProg.MasterCol, 3.0, 0.0, Inf, nothing), - ("MC3", Coluna.MathProg.MasterCol, 3.0, 0.0, Inf, nothing), - ("a", Coluna.MathProg.MasterArtVar, 1000.0, 0.0, Inf, nothing), - ("pricing_setup", Coluna.MathProg.MasterRepPricingSetupVar, 0.0, 0.0, 1.0, nothing) + ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 1.0, 4.0, nothing, nothing), + ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 1.0, 6.0, nothing, nothing), + ("MC1", Coluna.MathProg.MasterCol, 2.0, 0.0, Inf, nothing, 2), + ("MC2", Coluna.MathProg.MasterCol, 3.0, 0.0, Inf, nothing, 2), + ("MC3", Coluna.MathProg.MasterCol, 3.0, 0.0, Inf, nothing, 2), + ("a", Coluna.MathProg.MasterArtVar, 1000.0, 0.0, Inf, nothing, nothing), + ("pricing_setup", Coluna.MathProg.MasterRepPricingSetupVar, 0.0, 0.0, 1.0, nothing, nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.MasterMixedConstr, 10.0, ClMP.Greater, nothing), - ("c2", Coluna.MathProg.MasterConvexityConstr, 0.0, ClMP.Greater, nothing), - ("c3", Coluna.MathProg.MasterConvexityConstr, 2.0, ClMP.Less, nothing) + ("c1", Coluna.MathProg.MasterMixedConstr, 0.0, ClMP.Greater, nothing, nothing), + ("c2", Coluna.MathProg.MasterConvexityConstr, 1.0, ClMP.Greater, nothing, nothing), + ("c3", Coluna.MathProg.MasterConvexityConstr, 2.0, ClMP.Less, nothing, nothing) ] ) + master_form_uid = Coluna.MathProg.getuid(master_form) + spform, sp_name_to_var, sp_name_to_constr = _mathprog_formulation!( env, Coluna.MathProg.DwSp( @@ -389,8 +414,8 @@ function test_col_bounds_propagation_from_restricted_master() Coluna.MathProg.Integ ), [ - ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 1.0, 2.0, Coluna.Algorithm.getid(master_name_to_var["x1"])), - ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 1.0, 3.0, Coluna.Algorithm.getid(master_name_to_var["x2"])) + ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 1.0, 2.0, Coluna.Algorithm.getid(master_name_to_var["x1"]), master_form_uid), + ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 1.0, 3.0, Coluna.Algorithm.getid(master_name_to_var["x2"]), master_form_uid) ], [] ) @@ -407,7 +432,11 @@ function test_col_bounds_propagation_from_restricted_master() Float64[2.0, 2.0] ] ) - col_id = Coluna.MathProg.VarId(Coluna.MathProg.getid(master_name_to_var[name]); duty = Coluna.MathProg.DwSpPrimalSol) + col_id = Coluna.MathProg.VarId( + Coluna.MathProg.getid(master_name_to_var[name]); + origin_form_uid = Coluna.MathProg.getuid(spform), + duty = Coluna.MathProg.DwSpPrimalSol + ) Coluna.MathProg.push_in_pool!( pool, Coluna.MathProg.PrimalSolution(spform, var_ids, vals, 1.0, Coluna.MathProg.FEASIBLE_SOL), @@ -416,12 +445,14 @@ function test_col_bounds_propagation_from_restricted_master() ) end + dw_pricing_sps = Dict(Coluna.MathProg.getuid(spform) => spform) + ## MC3 >= 1 Coluna.MathProg.setcurlb!(master_form, master_name_to_var["MC3"], 1.0) ## We create the presolve formulations master_presolve_form = _presolve_formulation( - ["x1", "x2"], ["c1"], [1 1], master_form, master_name_to_var, master_name_to_constr + ["x1", "x2"], ["c1", "c2", "c3"], [1 1; 0 0 ;0 0], master_form, master_name_to_var, master_name_to_constr ) restricted_presolve_form = _presolve_formulation( @@ -430,26 +461,60 @@ function test_col_bounds_propagation_from_restricted_master() ) sp_presolve_form = _presolve_formulation( - ["x1", "x2"], [], [1 1], spform, sp_name_to_var, sp_name_to_constr; lm = 0 , um = 2 + ["x1", "x2"], [], [1 1], spform, sp_name_to_var, sp_name_to_constr; lm = 1, um = 2 ) - ## We run the presolve on the restricted master - tightened_bounds = Coluna.Algorithm.bounds_tightening(restricted_presolve_form.form) - new_restricted_master = Coluna.Algorithm.propagate_in_presolve_form(restricted_presolve_form, Int[], tightened_bounds; shrink = false) - new_restricted_master.form.unpropagated_partial_solution_flag = false - no_tightening = Dict{Int, Tuple{Float64, Bool, Float64, Bool}}() - new_restricted_master = Coluna.Algorithm.propagate_in_presolve_form(new_restricted_master, Int[], no_tightening; tighten_bounds=false, partial_sol = false) + presolve_reform = Coluna.Algorithm.DwPresolveReform( + master_presolve_form, + restricted_presolve_form, + Dict{Int16, Coluna.Algorithm.PresolveFormulation}( + Coluna.MathProg.getuid(spform) => sp_presolve_form + ) + ) + + @test presolve_reform.original_master.form.lbs == [1, 1] + @test presolve_reform.original_master.form.ubs == [4, 6] + + @test presolve_reform.dw_sps[2].form.lbs == [1, 1] + @test presolve_reform.dw_sps[2].form.ubs == [2, 3] + + Coluna.Algorithm.propagate_partial_sol_into_master( + presolve_reform, + dw_pricing_sps + ) + + # repr before fixing + # 1 <= x1 <= 4 (repr) + # 1 <= x2 <= 6 (repr) + + # fixing MC3 [x1 = 2, x2 = 2] + # 2 <= x1 <= 4 => 0 <= x1 <= 2 + # 2 <= x2 <= 6 => 0 <= x2 <= 4 + + @test presolve_reform.original_master.form.lbs == [0, 0] + @test presolve_reform.original_master.form.ubs == [2, 4] + + @test presolve_reform.dw_sps[2].form.lbs == [1, 1] + @test presolve_reform.dw_sps[2].form.ubs == [2, 3] + + Coluna.Algorithm.presolve_iteration!(presolve_reform, master_form, dw_pricing_sps) + - Coluna.Algorithm.update_form_from_presolve!(master_form, new_restricted_master) - Coluna.Algorithm.propagate_local_bounds!(sp_presolve_form, spform, new_restricted_master, master_form) - Coluna.Algorithm.propagate_global_bounds!(master_presolve_form, master_form, sp_presolve_form, spform) - Coluna.Algorithm.update_form_from_presolve!(spform, sp_presolve_form) - Coluna.Algorithm.update_form_from_presolve!(master_form, master_presolve_form) + # Global bounds: + # 0 <= x1 <= 2 + # 0 <= x2 <= 4 - # Fix MC3 [x1 = 2, x2 = 2] - # we should have - # 0 <= x1 <= 0, - # 0 <= x2 <= 1 + # new local bounds: + # 0 <= x1 <= 2 + # 0 <= x2 <= 3 => strengthen global bound because um = 1 + + @test presolve_reform.original_master.form.lbs == [0, 0] + @test presolve_reform.original_master.form.ubs == [2, 3] + + @test presolve_reform.dw_sps[2].form.lbs == [1, 1] + @test presolve_reform.dw_sps[2].form.ubs == [2, 3] + + Coluna.Algorithm.update_reform_from_presolve!(master_form, dw_pricing_sps, presolve_reform) # Partial solution: MC3 = 1 @test Coluna.MathProg.get_value_in_partial_sol(master_form, master_name_to_var["MC1"]) ≈ 0 @@ -466,23 +531,15 @@ function test_col_bounds_propagation_from_restricted_master() @test sp_presolve_form.form.lower_multiplicity == 0 @test sp_presolve_form.form.upper_multiplicity == 1 - # Partial solution: x1 = 2, x2 = 2 |||| x1 = 0, 0 <= x2 <= 1 - #@test Coluna.MathProg.get_value_in_partial_sol(spform, sp_name_to_var["x1"]) ≈ 2 - #@test Coluna.MathProg.get_value_in_partial_sol(spform, sp_name_to_var["x2"]) ≈ 2 - - @test Coluna.MathProg.getcurlb(spform, sp_name_to_var["x1"]) ≈ 0 - @test Coluna.MathProg.getcurub(spform, sp_name_to_var["x1"]) ≈ 0 - @test Coluna.MathProg.getcurlb(spform, sp_name_to_var["x2"]) ≈ 0 - @test Coluna.MathProg.getcurub(spform, sp_name_to_var["x2"]) ≈ 1 - - # representative after propagation to global bounds - # 0 <= x1 <= 0 - # 0 <= x2 <= 1 # because new upper multiplicity = 1 - @test Coluna.MathProg.getcurlb(master_form, sp_name_to_var["x1"]) ≈ 0 - @test Coluna.MathProg.getcurub(master_form, sp_name_to_var["x1"]) ≈ 0 - @test Coluna.MathProg.getcurlb(master_form, sp_name_to_var["x2"]) ≈ 0 - @test Coluna.MathProg.getcurub(master_form, sp_name_to_var["x2"]) ≈ 1 + @test Coluna.MathProg.getcurlb(spform, sp_name_to_var["x1"]) ≈ 1 + @test Coluna.MathProg.getcurub(spform, sp_name_to_var["x1"]) ≈ 2 + @test Coluna.MathProg.getcurlb(spform, sp_name_to_var["x2"]) ≈ 1 + @test Coluna.MathProg.getcurub(spform, sp_name_to_var["x2"]) ≈ 3 + @test Coluna.MathProg.getcurlb(master_form, master_name_to_var["x1"]) ≈ 0 + @test Coluna.MathProg.getcurub(master_form, master_name_to_var["x1"]) ≈ 2 + @test Coluna.MathProg.getcurlb(master_form, master_name_to_var["x2"]) ≈ 0 + @test Coluna.MathProg.getcurub(master_form, master_name_to_var["x2"]) ≈ 3 return end register!(unit_tests, "presolve_propagation", test_col_bounds_propagation_from_restricted_master) @@ -490,9 +547,9 @@ register!(unit_tests, "presolve_propagation", test_col_bounds_propagation_from_r function test_col_bounds_propagation_from_restricted_master2() # Original Master # min x1 + x2 - # s.t. x1 + x2 >= 10 + # s.t. x1 + x2 <= 10 # -9 <= x1 <= 9 (repr) - # -30 <= x2 <= -3 (repr) + # -30 <= x2 <= 0 (repr) # Restricted master # min 2MC1 + 3MC2 + 3MC3 + 1000a1 @@ -512,19 +569,19 @@ function test_col_bounds_propagation_from_restricted_master2() Coluna.MathProg.DwMaster(), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, -9.0, 9.0, nothing), - ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, -30.0, -3.0, nothing), - ("MC1", Coluna.MathProg.MasterCol, 2.0, 0.0, Inf, nothing), - ("MC2", Coluna.MathProg.MasterCol, 3.0, 0.0, Inf, nothing), - ("MC3", Coluna.MathProg.MasterCol, 3.0, 0.0, Inf, nothing), - ("a", Coluna.MathProg.MasterArtVar, 1000.0, 0.0, Inf, nothing), - ("pricing_setup", Coluna.MathProg.MasterRepPricingSetupVar, 0.0, 0.0, 1.0, nothing) + ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, -9.0, 9.0, nothing, nothing), + ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, -30.0, 0.0, nothing, nothing), + ("MC1", Coluna.MathProg.MasterCol, 2.0, 0.0, Inf, nothing, 2), + ("MC2", Coluna.MathProg.MasterCol, 3.0, 0.0, Inf, nothing, 2), + ("MC3", Coluna.MathProg.MasterCol, 3.0, 0.0, Inf, nothing, 2), + ("a", Coluna.MathProg.MasterArtVar, 1000.0, 0.0, Inf, nothing, nothing), + ("pricing_setup", Coluna.MathProg.MasterRepPricingSetupVar, 0.0, 0.0, 1.0, nothing, nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.MasterMixedConstr, 10.0, ClMP.Greater, nothing), - ("c2", Coluna.MathProg.MasterConvexityConstr, 0.0, ClMP.Greater, nothing), - ("c3", Coluna.MathProg.MasterConvexityConstr, 3.0, ClMP.Less, nothing) + ("c1", Coluna.MathProg.MasterMixedConstr, 10.0, ClMP.Less, nothing, nothing), + ("c2", Coluna.MathProg.MasterConvexityConstr, 0.0, ClMP.Greater, nothing, nothing), + ("c3", Coluna.MathProg.MasterConvexityConstr, 3.0, ClMP.Less, nothing, nothing) ] ) @@ -537,8 +594,8 @@ function test_col_bounds_propagation_from_restricted_master2() Coluna.MathProg.Integ ), [ - ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, -3.0, 3.0, Coluna.Algorithm.getid(master_name_to_var["x1"])), - ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, -10.0, -1.0, Coluna.Algorithm.getid(master_name_to_var["x2"])) + ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, -3.0, 3.0, Coluna.Algorithm.getid(master_name_to_var["x1"]), nothing), + ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, -10.0, -1.0, Coluna.Algorithm.getid(master_name_to_var["x2"]), nothing) ], [] ) @@ -555,7 +612,11 @@ function test_col_bounds_propagation_from_restricted_master2() Float64[-2.0, -2.0] ] ) - col_id = Coluna.MathProg.VarId(Coluna.MathProg.getid(master_name_to_var[name]); duty = Coluna.MathProg.DwSpPrimalSol) + col_id = Coluna.MathProg.VarId( + Coluna.MathProg.getid(master_name_to_var[name]); + origin_form_uid = Coluna.MathProg.getuid(spform), + duty = Coluna.MathProg.DwSpPrimalSol + ) Coluna.MathProg.push_in_pool!( pool, Coluna.MathProg.PrimalSolution(spform, var_ids, vals, 1.0, Coluna.MathProg.FEASIBLE_SOL), @@ -564,12 +625,14 @@ function test_col_bounds_propagation_from_restricted_master2() ) end + dw_pricing_sps = Dict(Coluna.MathProg.getuid(spform) => spform) + ## MC3 >= 1 Coluna.MathProg.setcurlb!(master_form, master_name_to_var["MC2"], 1.0) ## We create the presolve formulations master_presolve_form = _presolve_formulation( - ["x1", "x2"], ["c1"], [1 1], master_form, master_name_to_var, master_name_to_constr + ["x1", "x2"], ["c1", "c2", "c3"], [1 1; 0 0; 0 0], master_form, master_name_to_var, master_name_to_constr ) restricted_presolve_form = _presolve_formulation( @@ -581,22 +644,48 @@ function test_col_bounds_propagation_from_restricted_master2() ["x1", "x2"], [], [1 1], spform, sp_name_to_var, sp_name_to_constr; lm = 0, um = 3 ) - ## We run the presolve on the restricted master - tightened_bounds = Coluna.Algorithm.bounds_tightening(restricted_presolve_form.form) - new_restricted_master = Coluna.Algorithm.propagate_in_presolve_form( - restricted_presolve_form, Int[], tightened_bounds + presolve_reform = Coluna.Algorithm.DwPresolveReform( + master_presolve_form, + restricted_presolve_form, + Dict{Int16, Coluna.Algorithm.PresolveFormulation}( + Coluna.MathProg.getuid(spform) => sp_presolve_form + ) + ) + + Coluna.Algorithm.propagate_partial_sol_into_master( + presolve_reform, + dw_pricing_sps ) - Coluna.Algorithm.update_form_from_presolve!(master_form, new_restricted_master) - Coluna.Algorithm.propagate_local_bounds!(sp_presolve_form, new_restricted_master, spform, master_form) - Coluna.Algorithm.propagate_global_bounds!(master_presolve_form, master_form, sp_presolve_form, spform) - Coluna.Algorithm.update_form_from_presolve!(spform, sp_presolve_form) - Coluna.Algorithm.update_form_from_presolve!(master_form, master_presolve_form) + @test presolve_reform.original_master.form.lbs == [-8.0, -28.0] + @test presolve_reform.original_master.form.ubs == [0.0, 0.0] + + @test presolve_reform.dw_sps[2].form.lbs == [-3.0, -10.0] + @test presolve_reform.dw_sps[2].form.ubs == [3.0, -1.0] + + Coluna.Algorithm.presolve_iteration!(presolve_reform, master_form, dw_pricing_sps) + Coluna.Algorithm.update_reform_from_presolve!(master_form, dw_pricing_sps, presolve_reform) + @test presolve_reform.original_master.form.lbs == [-6.0, -20.0] + @test presolve_reform.original_master.form.ubs == [0.0, 0.0] + + @test presolve_reform.dw_sps[2].form.lbs == [-3.0, -10.0] + @test presolve_reform.dw_sps[2].form.ubs == [0.0, -1.0] + + # Original Master + # min x1 + x2 + # s.t. x1 + x2 >= 10 + # -9 <= x1 <= 9 (repr) + # -30 <= x2 <= 0 (repr) + # Fix MC2 [x1 = -1, x2 = -2] - # we should have - # -2 <= x1 <= 0, - # -8 <= x2 <= 0 + # we should following global bounds + # -9 <= x1 <= 0, => -8 <= x1 <= 0 + # -30 <= x2 <= 0 => -28 <= x2 <= 0 + + # and the following local bounds + # -3 <= x1 <= 0 => global lb bound = -9 + # -10 <= x2 <= -1 => global lb bound = -20 # Partial solution: MC3 = 1 @test Coluna.MathProg.get_value_in_partial_sol(master_form, master_name_to_var["MC1"]) ≈ 0 @@ -617,15 +706,15 @@ function test_col_bounds_propagation_from_restricted_master2() # @test Coluna.MathProg.get_value_in_partial_sol(spform, sp_name_to_var["x1"]) ≈ 2 # @test Coluna.MathProg.get_value_in_partial_sol(spform, sp_name_to_var["x2"]) ≈ 2 - @test Coluna.MathProg.getcurlb(spform, sp_name_to_var["x1"]) ≈ -2 + @test Coluna.MathProg.getcurlb(spform, sp_name_to_var["x1"]) ≈ -3 @test Coluna.MathProg.getcurub(spform, sp_name_to_var["x1"]) ≈ 0 - @test Coluna.MathProg.getcurlb(spform, sp_name_to_var["x2"]) ≈ -8 - @test Coluna.MathProg.getcurub(spform, sp_name_to_var["x2"]) ≈ 0 + @test Coluna.MathProg.getcurlb(spform, sp_name_to_var["x2"]) ≈ -10 + @test Coluna.MathProg.getcurub(spform, sp_name_to_var["x2"]) ≈ -1 # Check global bounds (repr bounds) - @test Coluna.MathProg.getcurlb(master_form, master_name_to_var["x1"]) ≈ -4 + @test Coluna.MathProg.getcurlb(master_form, master_name_to_var["x1"]) ≈ -6 @test Coluna.MathProg.getcurub(master_form, master_name_to_var["x1"]) ≈ 0 - @test Coluna.MathProg.getcurlb(master_form, master_name_to_var["x2"]) ≈ -16 + @test Coluna.MathProg.getcurlb(master_form, master_name_to_var["x2"]) ≈ -20 @test Coluna.MathProg.getcurub(master_form, master_name_to_var["x2"]) ≈ 0 return end @@ -671,16 +760,16 @@ function test_var_bound_propagation_from_original_to_subproblem() Coluna.MathProg.Original(), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.OriginalVar, 1.0, 0.0, 0.5, nothing), - ("x2", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing), - ("y1", Coluna.MathProg.OriginalVar, 1.0, 0.0, 0.7, nothing), - ("y2", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing) + ("x1", Coluna.MathProg.OriginalVar, 1.0, 0.0, 0.5, nothing, nothing), + ("x2", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing, nothing), + ("y1", Coluna.MathProg.OriginalVar, 1.0, 0.0, 0.7, nothing, nothing), + ("y2", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.OriginalConstr, 2.0, ClMP.Greater, nothing), - ("c2", Coluna.MathProg.OriginalConstr, 1.0, ClMP.Greater, nothing), - ("c3", Coluna.MathProg.OriginalConstr, 1.0, ClMP.Greater, nothing) + ("c1", Coluna.MathProg.OriginalConstr, 2.0, ClMP.Greater, nothing, nothing), + ("c2", Coluna.MathProg.OriginalConstr, 1.0, ClMP.Greater, nothing, nothing), + ("c3", Coluna.MathProg.OriginalConstr, 1.0, ClMP.Greater, nothing, nothing) ] ) @@ -695,12 +784,12 @@ function test_var_bound_propagation_from_original_to_subproblem() ), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 0.5, Coluna.Algorithm.getid(orig_name_to_var["x1"])) - ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(orig_name_to_var["x2"])) + ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 0.5, Coluna.Algorithm.getid(orig_name_to_var["x1"]), nothing) + ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(orig_name_to_var["x2"]), nothing) ], [ # name, duty, rhs, sense, id - ("c2", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, Coluna.Algorithm.getid(orig_name_to_constr["c2"])) + ("c2", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, Coluna.Algorithm.getid(orig_name_to_constr["c2"]), nothing) ] ) @@ -715,12 +804,12 @@ function test_var_bound_propagation_from_original_to_subproblem() ), [ # name, duty, cost, lb, ub, id - ("y1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 0.7, Coluna.Algorithm.getid(orig_name_to_var["y1"])) - ("y2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(orig_name_to_var["y2"])) + ("y1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 0.7, Coluna.Algorithm.getid(orig_name_to_var["y1"]), nothing) + ("y2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(orig_name_to_var["y2"]), nothing) ], [ # name, duty, rhs, sense, id - ("c3", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, Coluna.Algorithm.getid(orig_name_to_constr["c3"])) + ("c3", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, Coluna.Algorithm.getid(orig_name_to_constr["c3"]), nothing) ] ) @@ -760,12 +849,12 @@ function test_var_bound_propagation_from_original_to_master() Coluna.MathProg.Original(), [ # name, duty, cost, lb, ub, id - ("x", Coluna.MathProg.OriginalVar, 1.0, 0.0, 0.5, nothing), - ("y", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing) + ("x", Coluna.MathProg.OriginalVar, 1.0, 0.0, 0.5, nothing, nothing), + ("y", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.OriginalConstr, 1.0, ClMP.Less, nothing) + ("c1", Coluna.MathProg.OriginalConstr, 1.0, ClMP.Less, nothing, nothing) ] ) @@ -778,14 +867,14 @@ function test_var_bound_propagation_from_original_to_master() Coluna.MathProg.DwMaster(), [ # name, duty, cost, lb, ub, id - ("_x", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.5, Coluna.Algorithm.getid(orig_name_to_var["x"])), - ("_y", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(orig_name_to_var["y"])), - ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("a", Coluna.MathProg.MasterArtVar, 1000.0, 0.0, Inf, nothing) + ("_x", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.5, Coluna.Algorithm.getid(orig_name_to_var["x"]), nothing), + ("_y", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(orig_name_to_var["y"]), nothing), + ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("a", Coluna.MathProg.MasterArtVar, 1000.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, lb, ub, id - ("c1", Coluna.MathProg.MasterPureConstr, 1.0, ClMP.Less, Coluna.Algorithm.getid(orig_name_to_constr["c1"])) + ("c1", Coluna.MathProg.MasterPureConstr, 1.0, ClMP.Less, Coluna.Algorithm.getid(orig_name_to_constr["c1"]), nothing) ], ) @@ -828,17 +917,17 @@ function test_var_bound_propagation_from_master_to_subproblem() Coluna.MathProg.DwMaster(), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.5, nothing), - ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.5, nothing), - ("y1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.7, nothing), - ("y2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, Inf, nothing), - ("MC1", Coluna.MathProg.MasterCol, 2.0, 0.0, 1.0, nothing), - ("MC2", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("a", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing) + ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.5, nothing, nothing), + ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.5, nothing, nothing), + ("y1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.7, nothing, nothing), + ("y2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, Inf, nothing, nothing), + ("MC1", Coluna.MathProg.MasterCol, 2.0, 0.0, 1.0, nothing, nothing), + ("MC2", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("a", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, lb, ub, id - ("c1", Coluna.MathProg.MasterPureConstr, 2.0, ClMP.Greater, nothing) + ("c1", Coluna.MathProg.MasterPureConstr, 2.0, ClMP.Greater, nothing, nothing) ] ) @@ -857,12 +946,12 @@ function test_var_bound_propagation_from_master_to_subproblem() ), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 0.5, Coluna.Algorithm.getid(master_name_to_var["x1"])) - ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(master_name_to_var["x2"])) + ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 0.5, Coluna.Algorithm.getid(master_name_to_var["x1"]), nothing) + ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(master_name_to_var["x2"]), nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, Coluna.Algorithm.getid(master_constr_to_var["c1"])) + ("c1", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, Coluna.Algorithm.getid(master_constr_to_var["c1"]), nothing) ], ) @@ -877,12 +966,12 @@ function test_var_bound_propagation_from_master_to_subproblem() ), [ # name, duty, cost, lb, ub, id - ("y1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 0.7, Coluna.Algorithm.getid(master_name_to_var["y1"])) - ("y2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(master_name_to_var["y2"])) + ("y1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 0.7, Coluna.Algorithm.getid(master_name_to_var["y1"]), nothing) + ("y2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(master_name_to_var["y2"]), nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, Coluna.Algorithm.getid(master_constr_to_var["c1"])) + ("c1", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, Coluna.Algorithm.getid(master_constr_to_var["c1"]), nothing) ], ) @@ -930,12 +1019,12 @@ function test_var_bound_propagation_from_subproblem_to_master() ), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 0.5, nothing) - ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, Inf, nothing) + ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 0.5, nothing, nothing) + ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, nothing) + ("c1", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, nothing, nothing) ] ) @@ -950,12 +1039,12 @@ function test_var_bound_propagation_from_subproblem_to_master() ), [ # name, duty, cost, lb, ub, id - ("y1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 0.7, nothing) - ("y2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, Inf, nothing) + ("y1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 0.7, nothing, nothing) + ("y2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, nothing) + ("c1", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, nothing, nothing) ] ) @@ -968,17 +1057,17 @@ function test_var_bound_propagation_from_subproblem_to_master() Coluna.MathProg.DwMaster(), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.5, Coluna.Algorithm.getid(sp1_name_to_var["x1"])), - ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(sp1_name_to_var["x2"])), - ("y1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.7, Coluna.Algorithm.getid(sp2_name_to_var["y1"])), - ("y2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(sp2_name_to_var["y2"])), - ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC2", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("a", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing) + ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.5, Coluna.Algorithm.getid(sp1_name_to_var["x1"]), nothing), + ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(sp1_name_to_var["x2"]), nothing), + ("y1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.7, Coluna.Algorithm.getid(sp2_name_to_var["y1"]), nothing), + ("y2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(sp2_name_to_var["y2"]), nothing), + ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC2", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("a", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, lb, ub, id - ("c1", Coluna.MathProg.MasterPureConstr, 2.0, ClMP.Greater, nothing) + ("c1", Coluna.MathProg.MasterPureConstr, 2.0, ClMP.Greater, nothing, nothing) ] ) @@ -1010,7 +1099,6 @@ function test_var_fixing_propagation_within_formulation1() # x == 2 # y >= 0 # z >= 0 - env = Coluna.Env{Coluna.MathProg.VarId}(Coluna.Params()) orig_form, orig_name_to_var, orig_name_to_constr = _mathprog_formulation!( @@ -1018,13 +1106,13 @@ function test_var_fixing_propagation_within_formulation1() Coluna.MathProg.Original(), [ # name, duty, cost, lb, ub, id - ("x", Coluna.MathProg.OriginalVar, 1.0, 2.0, 2.0, nothing), - ("y", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing), - ("z", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing) + ("x", Coluna.MathProg.OriginalVar, 1.0, 2.0, 2.0, nothing, nothing), + ("y", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing, nothing), + ("z", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.OriginalConstr, 15.0, ClMP.Less, nothing) + ("c1", Coluna.MathProg.OriginalConstr, 15.0, ClMP.Less, nothing, nothing) ], ) @@ -1039,7 +1127,8 @@ function test_var_fixing_propagation_within_formulation1() new_form = Coluna.Algorithm.propagate_in_presolve_form( orig_presolve_form, Int[], - bounds_result + bounds_result; + store_unpropagated_partial_sol = false ) @test new_form.form.col_major_coef_matrix == [1 1;] @@ -1080,13 +1169,13 @@ function test_var_fixing_propagation_within_formulation2() Coluna.MathProg.Original(), [ # name, duty, cost, lb, ub, id - ("x", Coluna.MathProg.OriginalVar, 1.0, 4.0, 4.0, nothing), - ("y", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing), - ("z", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing) + ("x", Coluna.MathProg.OriginalVar, 1.0, 4.0, 4.0, nothing, nothing), + ("y", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing, nothing), + ("z", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.OriginalConstr, 15.0, ClMP.Greater, nothing) + ("c1", Coluna.MathProg.OriginalConstr, 15.0, ClMP.Greater, nothing, nothing) ], ) @@ -1100,8 +1189,8 @@ function test_var_fixing_propagation_within_formulation2() new_form = Coluna.Algorithm.propagate_in_presolve_form( orig_presolve_form, Int[], - #result, - bounds_result + bounds_result; + store_unpropagated_partial_sol = false ) @test new_form.form.col_major_coef_matrix == [1 1;] @@ -1143,14 +1232,14 @@ function test_var_fixing_propagation_within_formulation3() Coluna.MathProg.Original(), [ # name, duty, cost, lb, ub, id - ("x", Coluna.MathProg.OriginalVar, 1.0, 10.0, 10.0, nothing), - ("y", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing), - ("z", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing) + ("x", Coluna.MathProg.OriginalVar, 1.0, 10.0, 10.0, nothing, nothing), + ("y", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing, nothing), + ("z", Coluna.MathProg.OriginalVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.OriginalConstr, 150.0, ClMP.Greater, nothing), - ("c2", Coluna.MathProg.OriginalConstr, 600.0, ClMP.Less, nothing) + ("c1", Coluna.MathProg.OriginalConstr, 150.0, ClMP.Greater, nothing, nothing), + ("c2", Coluna.MathProg.OriginalConstr, 600.0, ClMP.Less, nothing, nothing) ], ) @@ -1166,7 +1255,8 @@ function test_var_fixing_propagation_within_formulation3() new_form = Coluna.Algorithm.propagate_in_presolve_form( orig_presolve_form, Int[], - bounds_result + bounds_result; + store_unpropagated_partial_sol = false ) @test new_form.form.col_major_coef_matrix == [1 1; 1 1;] @@ -1235,12 +1325,12 @@ function test_var_fixing_propagation_from_original_to_master() Coluna.MathProg.Original(), [ # name, duty, cost, lb, ub, id - ("x", Coluna.MathProg.OriginalVar, 1.0, 0.0, 0.5, nothing), - ("y", Coluna.MathProg.OriginalVar, 1.0, 1.0, 1.0, nothing) + ("x", Coluna.MathProg.OriginalVar, 1.0, 0.0, 0.5, nothing, nothing), + ("y", Coluna.MathProg.OriginalVar, 1.0, 1.0, 1.0, nothing, nothing) ], [ # name, duty, rhs, sense, id - ("c1", Coluna.MathProg.OriginalConstr, 1.0, ClMP.Less, nothing) + ("c1", Coluna.MathProg.OriginalConstr, 1.0, ClMP.Less, nothing, nothing) ], ) @@ -1252,16 +1342,16 @@ function test_var_fixing_propagation_from_original_to_master() env, Coluna.MathProg.DwMaster(), [ - ("_x", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.5, Coluna.Algorithm.getid(orig_name_to_var["x"])), - ("_y", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(orig_name_to_var["y"])), - ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC2", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC3", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC4", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("a", Coluna.MathProg.MasterArtVar, 10000.0, 0.0, Inf, nothing) + ("_x", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.5, Coluna.Algorithm.getid(orig_name_to_var["x"]), nothing), + ("_y", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, Inf, Coluna.Algorithm.getid(orig_name_to_var["y"]), nothing), + ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC2", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC3", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC4", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("a", Coluna.MathProg.MasterArtVar, 10000.0, 0.0, Inf, nothing, nothing) ], [ - ("c1", Coluna.MathProg.MasterPureConstr, 1.0, ClMP.Less, nothing) + ("c1", Coluna.MathProg.MasterPureConstr, 1.0, ClMP.Less, nothing, nothing) ] ) @@ -1324,19 +1414,19 @@ function test_var_fixing_propagation_from_master_to_subproblem1() Coluna.MathProg.DwMaster(), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.0, nothing), - ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("y1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("y2", Coluna.MathProg.MasterRepPricingVar, 1.0, 1.0, 1.0, nothing), - ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC2", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC3", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC4", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("a", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing) + ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.0, nothing, nothing), + ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("y1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("y2", Coluna.MathProg.MasterRepPricingVar, 1.0, 1.0, 1.0, nothing, nothing), + ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC2", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC3", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC4", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("a", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, sense , id - ("c1", Coluna.MathProg.MasterMixedConstr, 4.0, ClMP.Greater, nothing) + ("c1", Coluna.MathProg.MasterMixedConstr, 4.0, ClMP.Greater, nothing, nothing) ] ) @@ -1355,12 +1445,12 @@ function test_var_fixing_propagation_from_master_to_subproblem1() ), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["x1"])), - ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["x2"])) + ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["x1"]), nothing), + ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["x2"]), nothing) ], [ # name, duty, rhs, sense, id - ("c3", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, nothing) + ("c3", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, nothing, nothing) ] ) @@ -1375,12 +1465,12 @@ function test_var_fixing_propagation_from_master_to_subproblem1() ), [ # name, duty, cost, lb, ub, id - ("y1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["y1"])), - ("y2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["y2"])) + ("y1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["y1"]), nothing), + ("y2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["y2"]), nothing) ], [ # name, duty, rhs, sense, id - ("c4", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, nothing) + ("c4", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, nothing, nothing) ] ) @@ -1437,19 +1527,19 @@ function test_var_fixing_propagation_from_master_to_subproblem2() Coluna.MathProg.DwMaster(), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.0, nothing), - ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("y1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("y2", Coluna.MathProg.MasterRepPricingVar, 1.0, 1.0, 1.0, nothing), - ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC2", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC3", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC4", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("a", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing) + ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 0.0, nothing, nothing), + ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("y1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("y2", Coluna.MathProg.MasterRepPricingVar, 1.0, 1.0, 1.0, nothing, nothing), + ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC2", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC3", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC4", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("a", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, sense , id - ("c1", Coluna.MathProg.MasterMixedConstr, 4.0, ClMP.Greater, nothing) + ("c1", Coluna.MathProg.MasterMixedConstr, 4.0, ClMP.Greater, nothing, nothing) ] ) @@ -1468,12 +1558,12 @@ function test_var_fixing_propagation_from_master_to_subproblem2() ), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["x1"])), - ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["x2"])) + ("x1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["x1"]), nothing), + ("x2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["x2"]), nothing) ], [ # name, duty, rhs, sense, id - ("c3", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, nothing) + ("c3", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, nothing, nothing) ] ) @@ -1488,12 +1578,12 @@ function test_var_fixing_propagation_from_master_to_subproblem2() ), [ # name, duty, cost, lb, ub, id - ("y1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["y1"])), - ("y2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["y2"])) + ("y1", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["y1"]), nothing), + ("y2", Coluna.MathProg.DwSpPricingVar, 1.0, 0.0, 1.0, Coluna.Algorithm.getid(master_name_to_var["y2"]), nothing) ], [ # name, duty, rhs, sense, id - ("c4", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, nothing) + ("c4", Coluna.MathProg.DwSpPureConstr, 1.0, ClMP.Greater, nothing, nothing) ] ) @@ -1508,7 +1598,8 @@ function test_var_fixing_propagation_from_master_to_subproblem2() new_master_repr_presolve_form = Coluna.Algorithm.propagate_in_presolve_form( master_repr_presolve_form, Int[], - bounds_result + bounds_result; + store_unpropagated_partial_sol = false ) # Propagate bounds in subproblems @@ -1576,21 +1667,21 @@ function update_master_repr_formulation() Coluna.MathProg.DwMaster(), [ # name, duty, cost, lb, ub, id - ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("y1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("y2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing), - ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC2", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC3", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("MC4", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing), - ("a1", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing), - ("a2", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing) + ("x1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("x2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("y1", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("y2", Coluna.MathProg.MasterRepPricingVar, 1.0, 0.0, 1.0, nothing, nothing), + ("MC1", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC2", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC3", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("MC4", Coluna.MathProg.MasterCol, 1.0, 0.0, 1.0, nothing, nothing), + ("a1", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing, nothing), + ("a2", Coluna.MathProg.MasterArtVar, 1.0, 0.0, Inf, nothing, nothing) ], [ # name, duty, rhs, sense , id - ("c1", Coluna.MathProg.MasterMixedConstr, 4.0, ClMP.Greater, nothing), - ("c2", Coluna.MathProg.MasterMixedConstr, 4.0, ClMP.Greater, nothing) + ("c1", Coluna.MathProg.MasterMixedConstr, 4.0, ClMP.Greater, nothing, nothing), + ("c2", Coluna.MathProg.MasterMixedConstr, 4.0, ClMP.Greater, nothing, nothing) ] ) @@ -1633,7 +1724,8 @@ function update_master_repr_formulation() updated_master_repr_presolve_form = Coluna.Algorithm.propagate_in_presolve_form( master_repr_presolve_form, Int[2], - Dict(1 => (1.0, true, 1.0, false), 2 => (0.1, true, 0.5, true)) + Dict(1 => (1.0, true, 1.0, false), 2 => (0.1, true, 0.5, true)); + store_unpropagated_partial_sol = false ) @test updated_master_repr_presolve_form.form.col_major_coef_matrix == [1 1 1;]