Skip to content

Commit

Permalink
fix Benders doc + add more info in Decomposition doc (#969)
Browse files Browse the repository at this point in the history
  • Loading branch information
guimarqu authored Jun 28, 2023
1 parent 6b1b357 commit 89a7e9d
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 31 deletions.
2 changes: 1 addition & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Literate.markdown(TUTORIAL_STORAGE_API, OUTPUT_STORAGE_API, documenter=true)
makedocs(
modules = [Coluna, BlockDecomposition],
checkdocs = :exports,
sitename = "Coluna User Guide",
sitename = "Coluna.jl",
authors = "Atoptima & contributors",
format = Documenter.HTML(
prettyurls = get(ENV, "CI", nothing) == "true",
Expand Down
3 changes: 1 addition & 2 deletions docs/src/api/benders.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ The default implementation returns:

```@docs
Coluna.Algorithm.BendersOutput
```

**References**:

Expand All @@ -127,7 +127,6 @@ Coluna.Benders.new_output

## Benders cut generation iteration


```mermaid
flowchart TB;
id1(Optimize master)
Expand Down
62 changes: 34 additions & 28 deletions docs/src/man/decomposition.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
# Dantzig-Wolfe and Benders decompositions

Coluna is a framework to optimize mixed-integer programs that you can decompose.
In other words, if you remove the linking constraints or linking variables from you
In other words, if you remove the linking constraints or linking variables from your
program, you'll get sets of constraints (blocks) that you can solve independently.

Decompositions are typically used on programs whose constraints or variables can be divided into a set of "easy" constraints (respectively easy variables) and a set of "hard" constraints (respectively hard variables). Decomposing on constraints leads to Dantzig-Wolfe tranformation while decomposing on variables leads to Benders transformation. Both of these decompositions are implemented in Coluna.
Decompositions are typically used on programs whose constraints or variables can be divided into a set of "easy" constraints (respectively easy variables) and a set of "hard" constraints (respectively hard variables). Decomposing on constraints leads to Dantzig-Wolfe transformation while decomposing on variables leads to the Benders transformation. Both of these decompositions are implemented in Coluna.

## Dantzig-Wolfe

### Classic Dantzig-Wolfe decomposition

Let's consider the following coefficient matrix that has a block diagonal structure
in gray and some linking constraints in blue :

Expand All @@ -34,54 +32,62 @@ two vectors $x_1$ and $x_2$ :
\end{aligned}
```

- $x_1$ and $x_2$ are the original variables of the problem
- $(1)$ are the linking constraints
- $(2)$ is the first subproblem
- $(3)$ is the second subproblem
- variables $x_1$ and $x_2$ are the original variables of the problem (duty: `OriginalVar`)
- constraints $(1)$ are the linking constraints (duty: `OriginalConstr`)
- constraints $(2)$ shapes the first subproblem (duty: `OriginalConstr`)
- constraints $(3)$ shapes the second subproblem (duty: `OriginalConstr`)

When you apply a Dantzig-Wofe decomposition to this formulation,
Coluna reformulates it into the following master problem :

```math
\begin{aligned}
\min \quad& \sum\limits_{q \in Q_1} c_1' \tilde{x_1}^q \lambda_q + \sum\limits_{q \in Q_2} c_2' \tilde{x_2}^q \lambda_q\\
\text{s.t.} \quad& \sum\limits_{q \in Q_1} A_1 \tilde{x_1}^q \lambda_q + \sum\limits_{q \in Q_2} A_2 \tilde{x_2}^q \lambda_q \geq b & (1)\\
& L_1 \leq \sum\limits_{q \in Q_1} \lambda_q \leq U_1 & (2)\\
& L_2 \leq \sum\limits_{q \in Q_2} \lambda_q \leq U_2 & (3)\\
\min \quad& \sum\limits_{q \in Q_1} c_1' \tilde{x_1}^q \lambda_q + \sum\limits_{q \in Q_2} c_2' \tilde{x_2}^q \lambda_q + f'a \\
\text{s.t.} \quad& \sum\limits_{q \in Q_1} A_1 \tilde{x_1}^q \lambda_q + \sum\limits_{q \in Q_2} A_2 \tilde{x_2}^q \lambda_q + a \geq b & (1)\\
& L_1 \leq \sum\limits_{q \in Q_1} \tilde{z}_1\lambda_q \leq U_1 & (2)\\
& L_2 \leq \sum\limits_{q \in Q_2} \tilde{z}_2\lambda_q \leq U_2 & (3)\\
& \lambda_q \geq 0, \quad q \in Q_1 \cup Q_2
\end{aligned}
```

where $Q_1$ is the index-set of the solutions to the first subproblem and
$Q_2$ is the index-set of the solutions to the second subproblem.
The set of the solutions to the first and the second subproblems are $\{\tilde{x}^q_1\}_{q \in Q_1}$ and $\{\tilde{x}^q_2\}_{q \in Q_2}$ respectively. These solutions are expressed
in terms of the original variables.
The multiplicity of the subproblems is defined in the convexity constraints $(2)$ and $(3)$. $(1)$ is called the Master mixed constraint.
Lower and upper multiplicity are $1$ by default.
where:
- set $Q_1$ is the index set of the solutions to the first subproblem
- set $Q_2$ is the index set of the solutions to the second subproblem
- set of the solutions to the first is $\{\tilde{x}^q_1\}_{q \in Q_1}$ (duty: ` MasterRepPricingVar`)
- set of the solutions to the second subproblem is $\{\tilde{x}^q_2\}_{q \in Q_2}$ respectively (duty: ` MasterRepPricingVar`)
- constraint $(1)$ is the reformulation of the linking constraints (duty: `MasterMixedConstr`)
- constraint $(2)$ is the convexity constraint of the first subproblem and involves the lower $L_1$ and upper $U_1$ multiplicity of the subproblem (duty: `MasterConvexityConstr`)
- constraint $(3)$ is the convexity constraint of the second subproblem and involves the lower $L_2$ and upper $U_2$ multiplicity of the subproblem (duty: `MasterConvexityConstr`)
- variables $\tilde{z}_1$ and $\tilde{z}_2$ are representative of pricing setup variables in the master (always equal to $1$) (duty: `MasterRepPricingVar`)
- variables $\lambda_q$ are the columns (duty: `MasterCol`)
- variable $a$ is the artificial variable (duty: `MasterArtVar`)

At the beginning of the column generation algorithm, the master formulation does
not have any master columns. Therefore, the master may be infeasible.
To prevent this, Coluna adds a local artifical variable specific to each constraint of the master and a global artificial variable.
Costs of articial and global artificial variables can be defined in [Coluna.Params](@ref).
To prevent this, Coluna adds a local artificial variable $a$ specific to each constraint of the master and a global artificial variable.
Costs $f$ of artificial and global artificial variables can be defined in [Coluna.Params](@ref).

Subproblems take the following form (here, it's the first subproblem) :

```math
\begin{aligned}
\min \quad& \bar{c_1}' x_1\\
\min \quad& \bar{c_1}' x_1 + z_1\\
\text{s.t.} \quad& D_1x_1 \geq d_1 & (1)\\
& \quad x_1 \geq 0
\end{aligned}
```

where $\bar{c}$ is the reduced cost of the original variables computed by the column generation algorithm. $(1)$ is called the Dantzig-Wolfe subproblem "pure constraint".
where:
- vector $\bar{c}$ is the reduced cost of the subproblem variables computed by the column generation algorithm.
- variables $x_1$ are the subproblem variables (duty: `DwSpPricingVar`)
- constraint $(1)$ is the subproblem constraint (duty: `DwSpPureConstr`)
- variable $z_1$ is the pricing setup variable (always equal to $1$) (duty: `DwSpSetupVar`)

### Dantzig-Wolfe with identical subproblems (alpha)

When some subproblems are identical (same coefficient matrix and right-hand side),
Lower and upper multiplicities of subproblems are $1$ by default.
However, when some subproblems are identical (same coefficient matrix and right-hand side),
you can avoid solving all of them at each iteration by defining only one subproblem and
setting its multiplicity to the number of time it appears. See this [tutorial](@ref tuto_identical_sp) to get an example of Dantzig-Wolfe decomposition with identical subproblems.
setting its multiplicity to the number of times it appears. See this [tutorial](@ref tuto_identical_sp) to get an example of Dantzig-Wolfe decomposition with identical subproblems.


## Benders (alpha)
Expand All @@ -94,7 +100,7 @@ in gray and some linking variables in blue :
The intuition behind Benders decomposition is that some hard problems can become much easier with some of their variables fixed.
Benders aims to divide the variables of the problem into two "levels": the 1st level variables which, once fixed, make it easier to find a solution for the remaining variables, the so-called 2nd-level variables.

The question is how to set the 1st level variables. Benders' theory proceeds by successive generation of cuts: given a 1st-level solution, we ask the following questions:
The question is how to set the 1st level variables. Benders' theory proceeds by the successive generation of cuts: given a 1st-level solution, we ask the following questions:

- Is the subproblem infeasible? If so, then the 1st-level solution is not correct and must be eliminated. A feasibility cut will be derived from the dual subproblem and added to the master.
- Does the aggregation of the master and subproblem solutions give rise to an optimal solution to the problem? It depends on a criterion that can be computed. If it is the case, we are done, else, we derive an optimality cut from the dual subproblem and add it into the master.
Expand Down Expand Up @@ -136,7 +142,7 @@ and a subproblem:
```
with $\bar{x}$ a fixed solution for the master problem (i.e. valuations of the 1st-level variables)

Note that in the special case where the master problem is unbounded, the shape of the subproblem is slightly modified. See the [API](@ref api_benders) section to get more informations.
Note that in the special case where the master problem is unbounded, the shape of the subproblem is slightly modified. See the [API](@ref api_benders) section to get more information.


This decomposition is an alpha feature.
Expand Down

0 comments on commit 89a7e9d

Please sign in to comment.