Skip to content

Commit

Permalink
Stabilization correction (#1104)
Browse files Browse the repository at this point in the history
* Correction in stabilization: we should use separation point to update stability center instead of Kelley point (corresponding to the master dual solution)

* Stability center should be updated only with the pseudo dual bound

* make tests pass
  • Loading branch information
rrsadykov authored Oct 26, 2023
1 parent 4c37c9a commit aac3f48
Show file tree
Hide file tree
Showing 6 changed files with 17 additions and 21 deletions.
12 changes: 4 additions & 8 deletions src/Algorithm/colgen/default.jl
Original file line number Diff line number Diff line change
Expand Up @@ -949,23 +949,19 @@ end

ColGen.get_master_ip_primal_sol(output::ColGenPhaseOutput) = output.master_ip_primal_sol

ColGen.update_stabilization_after_pricing_optim!(::NoColGenStab, ctx::ColGenContext, generated_columns, master, valid_db, pseudo_db, mast_dual_sol) = nothing
function ColGen.update_stabilization_after_pricing_optim!(stab::ColGenStab, ctx::ColGenContext, generated_columns, master, valid_db, pseudo_db, mast_dual_sol)
ColGen.update_stabilization_after_pricing_optim!(::NoColGenStab, ctx::ColGenContext, generated_columns, master, pseudo_db, smooth_dual_sol) = nothing
function ColGen.update_stabilization_after_pricing_optim!(stab::ColGenStab, ctx::ColGenContext, generated_columns, master, pseudo_db, smooth_dual_sol)
# At each iteration, we always update α after the first pricing optimization.
# We don't update α if we are in a misprice sequence.
if stab.automatic && stab.nb_misprices == 0
is_min = ColGen.is_minimization(ctx)
primal_sol = _primal_solution(master, generated_columns, is_min)
α = _dynamic_alpha_schedule(stab.base_α, mast_dual_sol, stab.cur_stab_center, subgradient_helper(ctx), primal_sol, is_min)
α = _dynamic_alpha_schedule(stab.base_α, smooth_dual_sol, stab.cur_stab_center, subgradient_helper(ctx), primal_sol, is_min)
stab.base_α = α
end

if isbetter(DualBound(master, valid_db), stab.valid_dual_bound)
stab.cur_stab_center = mast_dual_sol
stab.valid_dual_bound = DualBound(master, valid_db)
end
if isbetter(DualBound(master, pseudo_db), stab.pseudo_dual_bound)
stab.stab_center_for_next_iteration = mast_dual_sol
stab.stab_center_for_next_iteration = smooth_dual_sol
stab.pseudo_dual_bound = DualBound(master, pseudo_db)
end
return
Expand Down
4 changes: 2 additions & 2 deletions src/Algorithm/colgen/printer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ ColGen.is_minimization(ctx::ColGenPrinterContext) = ColGen.is_minimization(ctx.i
ColGen.get_pricing_subprobs(ctx::ColGenPrinterContext) = ColGen.get_pricing_subprobs(ctx.inner)

ColGen.setup_stabilization!(ctx::ColGenPrinterContext, master) = ColGen.setup_stabilization!(ctx.inner, master)
function ColGen.update_stabilization_after_pricing_optim!(stab, ctx::ColGenPrinterContext, generated_columns, master, valid_db, pseudo_db, mast_dual_sol)
return ColGen.update_stabilization_after_pricing_optim!(stab, ctx.inner, generated_columns, master, valid_db, pseudo_db, mast_dual_sol)
function ColGen.update_stabilization_after_pricing_optim!(stab, ctx::ColGenPrinterContext, generated_columns, master, pseudo_db, smooth_dual_sol)
return ColGen.update_stabilization_after_pricing_optim!(stab, ctx.inner, generated_columns, master, pseudo_db, smooth_dual_sol)
end

ColGen.new_phase_iterator(ctx::ColGenPrinterContext) = ColGen.new_phase_iterator(ctx.inner)
Expand Down
9 changes: 5 additions & 4 deletions src/ColGen/ColGen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -254,12 +254,13 @@ function run_colgen_iteration!(context, phase, stage, env, ip_primal_sol, stab)
# pseudo dual bound is used for stabilization only.
pseudo_db = compute_dual_bound(context, phase, sps_pb, generated_columns, sep_mast_dual_sol)

update_stabilization_after_pricing_optim!(stab, context, generated_columns, master, valid_db, pseudo_db, mast_dual_sol)
update_stabilization_after_pricing_optim!(stab, context, generated_columns, master, pseudo_db, sep_mast_dual_sol)

# We have finished to solve all pricing subproblems.
# If we have stabilization, we need to check if we have misprice.
# If we have misprice, we need to update the stabilization center and solve again
# the pricing subproblems.
# If we have stabilization, we need to check if we have misprice, i.e. if smoothing is active
# and no negative reduced cost columns are generated
# If we have misprice, we need to update the stabilization center and the smoothed dual solution
# and solve again the pricing subproblems.
# If we don't have misprice, we can stop the pricing loop.
misprice = check_misprice(stab, generated_columns, mast_dual_sol)
if misprice
Expand Down
5 changes: 2 additions & 3 deletions src/ColGen/stabilization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,10 @@ Returns the dual solution used for the pricing in the current column generation
"""
Updates stabilization after pricing optimization where:
- `mast_dual_sol` is the dual solution to the master problem
- `valid_db` is the valid dual bound of the problem after optimization of the pricing problems
- `pseudo_db` is the pseudo dual bound of the problem after optimization of the pricing problems
- `mast_dual_sol` is the dual solution to the master problem
- `smooth_dual_sol` is the current smoothed dual solution
"""
@mustimplement "ColGenStab" update_stabilization_after_pricing_optim!(stab, ctx, generated_columns, master, valid_db, pseudo_db, mast_dual_sol) = nothing
@mustimplement "ColGenStab" update_stabilization_after_pricing_optim!(stab, ctx, generated_columns, master, pseudo_db, smooth_dual_sol) = nothing

"""
Updates stabilization after a misprice.
Expand Down
4 changes: 2 additions & 2 deletions test/unit/ColGen/colgen_iteration.jl
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ function ColGen.compute_dual_bound(::ColGenIterationTestContext, ::ColGenIterati
return 22.5 - 23/4
end

ColGen.update_stabilization_after_pricing_optim!(::Coluna.Algorithm.NoColGenStab, ::ColGenIterationTestContext, _, _, _, _, _) = nothing
ColGen.update_stabilization_after_pricing_optim!(::Coluna.Algorithm.NoColGenStab, ::ColGenIterationTestContext, _, _, _, _) = nothing

struct TestColGenIterationOutput <: ColGen.AbstractColGenIterationOutput
min_sense::Bool
Expand Down Expand Up @@ -274,7 +274,7 @@ function ColGen.new_iteration_output(::Type{<:TestColGenIterationOutput},
)
end

ColGen.update_stabilization_after_pricing_optim!(::Coluna.Algorithm.NoColGenStab, ::TestColGenIterationContext, _, _, _, _, _) = nothing
ColGen.update_stabilization_after_pricing_optim!(::Coluna.Algorithm.NoColGenStab, ::TestColGenIterationContext, _, _, _, _) = nothing

function colgen_iteration_master_ok_pricing_ok()
ctx = ColGenIterationTestContext()
Expand Down
4 changes: 2 additions & 2 deletions test/unit/ColGen/colgen_stabilization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,8 @@ ColGen.get_pricing_strategy(::ColGenStabFlowCtx, phase) = ColGenStabFlowPricingS
ColGen.pricing_strategy_iterate(::ColGenStabFlowPricingStrategy) = nothing
ColGen.compute_dual_bound(ctx::ColGenStabFlowCtx, phase, bounds, generated_columns, mast_dual_sol) = ctx.nb_compute_dual_bound += 1

function ColGen.update_stabilization_after_pricing_optim!(stab::ColGenStabFlowStab, ctx, generated_columns, master, valid_db, pseudo_db, mast_dual_sol)
@test mast_dual_sol == [1.0, 1.0, 1.0] # we need the out point in this method.
function ColGen.update_stabilization_after_pricing_optim!(stab::ColGenStabFlowStab, ctx, generated_columns, master, pseudo_db, smooth_dual_sol)
@test smooth_dual_sol == [0.5, 0.5, 0.5] # we need the out point in this method.
stab.nb_update_stab_after_pricing_done += 1
return true
end
Expand Down

0 comments on commit aac3f48

Please sign in to comment.