Skip to content

Commit

Permalink
finishing column generation doc
Browse files Browse the repository at this point in the history
  • Loading branch information
guimarqu committed Jun 27, 2023
1 parent 9fa6ca9 commit 126bfcb
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 84 deletions.
174 changes: 143 additions & 31 deletions docs/src/api/colgen.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,24 @@ generation algorithm together with a default implementation of this algorithm.
In this section, we are first going to present the generic functions, the implementation
with some theory backgrounds and then give the references of the interface.

You can find the generic functions and the interface at `src/ColGen` and the default
implementation at `src/Algorithm/colgen`.
You can find the generic functions and the interface in the `ColGen` submodule and the default
implementation in the `Algorithm` submodule at `src/Algorithm/colgen`.

## Context

The `ColGen` submodule provides an interface and generic functions to implement a column generation algorithm. The implementation depends on
an object called `context`.

```@docs
Coluna.ColGen.AbstractColGenContext
```

Coluna provides two types of context:

```@docs
Coluna.Algorithm.ColGenContext
Coluna.Algorithm.ColGenPrinterContext
```

## Generic functions

Expand All @@ -20,14 +36,23 @@ There are three generic functions:

```@docs
Coluna.ColGen.run!
```
See the [main loop](#Main-loop) section for more details.

```@docs
Coluna.ColGen.run_colgen_phase!
```
See the [phase loop](#Phase-loop) section for more details.

```@docs
Coluna.ColGen.run_colgen_iteration!
```
See the [column generation iteration](#Column-generation-iteration) section for more details.

They are independent of any other submodule of Coluna.
You can use them to implement your own column generation algorithm.

## Default implementation
## Reformulation

The default implementation works with a reformulated problem contained in
`MathProg.Reformulation` where master and subproblems are `MathProg.Formulation` objects.
Expand Down Expand Up @@ -76,22 +101,62 @@ Coluna.ColGen.get_pricing_subprobs
Coluna.ColGen.is_minimization
```

### Main loop
## Main loop

Lorem ipsum
This is a description of how the `Coluna.ColGen.run!` generic function behaves in the default
implementation.

The main loop stops when the `Coluna.Colgen.stop_colgen` method returns `true`. This is the case when one of the following conditions holds:
- the master or a pricing subproblem is infeasible
- the time limit is reached
- the maximum number of iterations is reached

Otherwise, the main loop runs until there is no more phase or stage to execute.

The method returns:

```@docs
Coluna.ColGen.ColGenOutput
```

**References**:

```@docs
Coluna.ColGen.before_colgen_iteration
Coluna.ColGen.after_colgen_iteration
Coluna.ColGen.is_better_dual_bound
Coluna.ColGen.stop_colgen
Coluna.ColGen.setup_reformulation!
Coluna.ColGen.setup_context!
Coluna.ColGen.AbstractColGenOutput
Coluna.ColGen.colgen_output_type
Coluna.ColGen.new_output
```

### Phases
## Phase loop

This is a description of how the `Coluna.ColGen.run_colgen_phase!` generic function behaves in the default implementation.

This function is responsible for maintaining the incumbent dual bound and the incumbent master IP primal solution.

The phase loop stops when the `Coluna.ColGen.stop_colgen_phase` method returns `true`. This is the case when one of the following conditions holds:
- the maximum number of iterations is reached
- the time limit is reached
- the master is infeasible
- the master is unbounded
- a pricing subproblem is infeasible
- a pricing subproblem is unbounded
- there is no new column generated at the last iteration
- there is a new constraint or valid inequality in the master
- the incumbent dual bound and the primal master LP solution value converged

**References**:

```@docs
Coluna.ColGen.stop_colgen_phase
Coluna.ColGen.before_colgen_iteration
Coluna.ColGen.after_colgen_iteration
Coluna.ColGen.is_better_dual_bound
```

### Phase iterator

In the first iterations, the restricted master LP contains a few columns and may be infeasible.
To prevent this, we introduced artificial variables $v$ and we activate/deactivate these variables
Expand All @@ -106,13 +171,40 @@ Coluna.Algorithm.ColGenPhase3
```

Column generation always starts with Phase 3.
The cost of artificial variables in Phase 3 can be changed using the following methods:

The default implementation of the phase iterator belongs to the following type:

```@docs
missing
Coluna.Algorithm.ColunaColGenPhaseIterator
```

#### Phase Iterator
Transitions between the phases depend on four conditions:
- (A) the presence of artificial variables in the master LP solution
- (B) the generation of new essential constraints (may happen when a new master IP solution is found)
- (C) the current stage is exact
- (D) column generation converged

Transitions are the following:

```mermaid
flowchart TB;
id1(Phase 3)
id2(Phase 1)
id3(Phase 2)
id4(end)
id5(error)
id1 --A & !B & C--> id2
id1 --!A & !B & C & D--> id4
id1 -- otherwise --> id1
id2 --!A & !B--> id3
id2 --A & C & D--> id4
id2 -- otherwise --> id2
id3 -- !B & C & D --> id4
id3 -- otherwise --> id3
id3 -- B --> id2
id3 -- A --> id5
style id5 stroke:#f66
```

**References**:
```@docs
Expand All @@ -122,26 +214,18 @@ Coluna.ColGen.new_phase_iterator
Coluna.ColGen.initial_phase
Coluna.ColGen.decrease_stage
Coluna.ColGen.next_phase
Coluna.ColGen.setup_reformulation!
Coluna.ColGen.setup_context!
Coluna.ColGen.stop_colgen_phase
```

#### Phase output
### Phase output

```@docs
Coluna.ColGen.AbstractColGenPhaseOutput
Coluna.ColGen.colgen_phase_output_type
Coluna.ColGen.new_phase_output
Coluna.ColGen.get_master_ip_primal_sol
Coluna.ColGen.get_best_ip_primal_master_sol_found
Coluna.ColGen.get_final_lp_primal_master_sol_found
Coluna.ColGen.get_final_db
Coluna.ColGen.stop_colgen
```


### Stages
## Stages

A stage is a set of consecutive iterations in which we use a given pricing solver.
The aim is to speed up the resolution of the pricing problem by first using an approximate but fast pricing algorithm and then switching to increasingly less heuristic algorithms until the last stage where an exact solver is used.
Expand Down Expand Up @@ -169,7 +253,9 @@ Coluna.ColGen.stage_id
Coluna.ColGen.is_exact_stage
```

### Column generation iteration
## Column generation iteration

This is a description of how the `Coluna.ColGen.run_colgen_iteration!` generic function behaves in the default implementation.

These are the main steps of a column generation iteration without stabilization.
Click on the step to go to the relevant section.
Expand All @@ -194,7 +280,7 @@ flowchart TB;
id5 --subproblem--> id6
id6 --> id7
id7 --> id5
id5 --nothing--> id8
id5 --end--> id8
id8 --> id9
id9 --> id10
click id1 href "#Optimize-master-LP" "Link to doc"
Expand Down Expand Up @@ -279,6 +365,12 @@ Reduced costs calculation is written as a math operation in the `run_colgen_iter
generic function. As a consequence, the dual solution to the master LP and the
implementation of the two following methods must return data structures that support math operations.

To speed up this operation, we cache data in the following data structure:

```@docs
Coluna.Algorithm.ReducedCostsCalculationHelper
```

Reduced costs calculation also requires the implementation of the two following methods:

```@docs
Expand Down Expand Up @@ -419,22 +511,21 @@ Go back to the [column generation iteration overview](#Column-generation-iterati

#### Iteration output

Lorem ipsum.
```@docs
Coluna.ColGen.ColGenIterationOutput
```

**References**:

```@docs
Coluna.ColGen.AbstractColGenIterationOutput
Coluna.ColGen.colgen_iteration_output_type
Coluna.ColGen.new_iteration_output
Coluna.ColGen.get_nb_new_cols
Coluna.ColGen.get_master_ip_primal_sol
```


Go back to the [column generation iteration overview](#Column-generation-iteration).

### Result data structures
### Getters for Result data structures

| Method name | Master | Pricing |
| ---------------- | ------ | ---------- |
Expand All @@ -448,7 +539,7 @@ Go back to the [column generation iteration overview](#Column-generation-iterati
| `get_dual_bound` | | X |


**References**
**References**:

```@docs
Coluna.ColGen.is_unbounded
Expand All @@ -461,6 +552,20 @@ Coluna.ColGen.get_primal_bound
Coluna.ColGen.get_dual_bound
```

### Getters for Output data structures

| Method name | ColGen | Phase | Iteration |
| ---------------- | ------ | ----- | --------- |
| `get_nb_new_cols` | | | X |
| `get_master_ip_primal_sol` | | X | X |

**References**:

```@docs
Coluna.ColGen.get_nb_new_cols
Coluna.ColGen.get_master_ip_primal_sol
```

### Stabilization

Coluna provides a default implementation of the smoothing stabilization with a self-adjusted $\alpha$ parameter, $0 \leq \alpha < 1$.
Expand All @@ -481,7 +586,14 @@ Some elements of the column generation change when using stabilization.
- The pseudo bound is computed using the smoothed dual solution $\pi^{\text{sep}}$.
- The smoothed dual bound can result in the generation of no improving columns. This is called a **misprice**. In that case, we need to move away from the stabilization center $\pi^{\text{in}}$ by decreasing $\alpha$.

**Reference**:
When using self-adjusted stabilization, the smoothing coefficient $\alpha$ is adjusted to make the smoothed dual solution $\pi^{\text{sep}}$ closer to the best possible dual solution on the line between $\pi^{\text{in}}$ and $\pi^{\text{out}}$ (i.e. where the subgradient of the current primal solution is perpendicular to the latter line).
To compute the subgradient, we use the following data structure:

```@docs
Coluna.Algorithm.SubgradientCalculationHelper
```

**References**:

```@docs
Coluna.ColGen.setup_stabilization!
Expand Down
1 change: 1 addition & 0 deletions src/Algorithm/colgen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ function _colgen_optstate_output(result, master)
end

function run!(algo::ColumnGeneration, env::Env, reform::Reformulation, input::OptimizationState)
# We buid
C = _colgen_context(algo)
ctx = _new_context(C, reform, algo)
result = ColGen.run!(ctx, env, get_best_ip_primal_sol(input))
Expand Down
13 changes: 10 additions & 3 deletions src/Algorithm/colgen/default.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
"""
ColGenContext(reformulation, algo_params) -> ColGenContext
Creates a context to run the default implementation of the column generation algorithm.
"""
mutable struct ColGenContext <: ColGen.AbstractColGenContext
reform::Reformulation
optim_sense
Expand Down Expand Up @@ -98,6 +103,7 @@ struct ColGenPhaseOutput <: ColGen.AbstractColGenPhaseOutput
min_sense::Bool
end

"Output of the default implementation of the column generation algorithm."
struct ColGenOutput <: ColGen.AbstractColGenOutput
master_lp_primal_sol::Union{Nothing,PrimalSolution}
master_ip_primal_sol::Union{Nothing,PrimalSolution}
Expand Down Expand Up @@ -136,6 +142,9 @@ end
###############################################################################
# Sequence of phases
###############################################################################
"""
Type for the default implementation of the sequence of phases.
"""
struct ColunaColGenPhaseIterator <: ColGen.AbstractColGenPhaseIterator end

ColGen.new_phase_iterator(::ColGenContext) = ColunaColGenPhaseIterator()
Expand Down Expand Up @@ -775,6 +784,7 @@ end

# Iteration output

"Object for the output of an iteration of the column generation default implementation."
struct ColGenIterationOutput <: ColGen.AbstractColGenIterationOutput
min_sense::Bool
mlp::Union{Nothing, Float64}
Expand Down Expand Up @@ -896,9 +906,6 @@ end

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

ColGen.get_best_ip_primal_master_sol_found(output::ColGenPhaseOutput) = output.master_lp_primal_sol
ColGen.get_final_lp_primal_master_sol_found(output::ColGenPhaseOutput) = output.master_ip_primal_sol
ColGen.get_final_db(output::ColGenPhaseOutput) = output.db

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)
Expand Down
6 changes: 6 additions & 0 deletions src/Algorithm/colgen/printer.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
"""
ColGenPrinterContext(reformulation, algo_params) -> ColGenPrinterContext
Creates a context to run the default implementation of the column generation algorithm
together with a printer that prints information about the algorithm execution.
"""
mutable struct ColGenPrinterContext <: ColGen.AbstractColGenContext
inner::ColGenContext
phase::Int
Expand Down
6 changes: 6 additions & 0 deletions src/ColGen/ColGen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ module ColGen
include("../MustImplement/MustImplement.jl")
using .MustImplement

"""
Supertype for the objects to which belongs the implementation of the column generation and
that stores any kind of information during the execution of the column generation algorithm.
**IMPORTANT**: implementation of the column generation mainly depends on the context type.
"""
abstract type AbstractColGenContext end

include("stages.jl")
Expand Down
Loading

0 comments on commit 126bfcb

Please sign in to comment.