From e47a881367ca4520af03e3c21842e2e7e977f526 Mon Sep 17 00:00:00 2001 From: odow Date: Tue, 3 Jun 2025 11:28:07 +1200 Subject: [PATCH 1/4] [docs] overhaul the docs * Update to Documenter@1 * Clarify the API reference * Move all exports to src/Dualization.jl * Split mathematical background into a separate page --- docs/Project.toml | 2 +- docs/make.jl | 25 +- docs/src/index.md | 32 +- docs/src/manual.md | 1164 +-------------------------- docs/src/mathematical_background.md | 1070 ++++++++++++++++++++++++ docs/src/reference.md | 63 +- src/Dualization.jl | 5 + src/MOI_wrapper.jl | 24 +- src/dual_names.jl | 2 - src/dualize.jl | 4 +- 10 files changed, 1238 insertions(+), 1153 deletions(-) create mode 100644 docs/src/mathematical_background.md diff --git a/docs/Project.toml b/docs/Project.toml index 481efa7c..351c741c 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -3,4 +3,4 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Dualization = "191a621a-6537-11e9-281d-650236a99e60" [compat] -Documenter = "0.24" +Documenter = "1" diff --git a/docs/make.jl b/docs/make.jl index 160b15d9..ad6bc625 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -3,21 +3,28 @@ # Use of this source code is governed by an MIT-style license that can be found # in the LICENSE.md file or at https://opensource.org/licenses/MIT. -using Documenter, Dualization +import Documenter +import Dualization -makedocs( - modules = [Dualization], - doctest = false, - clean = true, - # See https://github.com/JuliaDocs/Documenter.jl/issues/868 +Documenter.makedocs( + sitename = "Dualization.jl", + authors = "Guilherme Bodin, and contributors", format = Documenter.HTML( assets = ["assets/favicon.ico"], mathengine = Documenter.MathJax(), prettyurls = get(ENV, "CI", nothing) == "true", ), - sitename = "Dualization.jl", - authors = "Guilherme Bodin, and contributors", - pages = ["Home" => "index.md", "manual.md", "examples.md", "reference.md"], + pages = [ + "Home" => "index.md", + "manual.md", + "mathematical_background.md", + "examples.md", + "reference.md", + ], + modules = [Dualization], + checkdocs = :exports, + doctest = true, + clean = true, ) Documenter.deploydocs(; diff --git a/docs/src/index.md b/docs/src/index.md index 9a5987a5..59e70b45 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,17 +1,35 @@ -# Dualization.jl Documentation +# Dualization.jl -Dualization.jl is a package written on top of MathOptInterface that allows users to write the dual of a JuMP model automatically. -This package has two main features: the `dualize` function, which enables users to get a dualized JuMP model, and the `DualOptimizer`, which enables users to solve a problem by providing the solver the dual of the problem. +[Dualization.jl](https://github.com/jump-dev/Dualization.jl) is an extension +package for [MathOptInterface.jl](https://github.com/jump-dev/MathOptInterface.jl) +that formulates the dual of conic optimization problems. + +Dualization.jl has two main features: + + * The [`dualize`](@ref) function that computes the dual formulation of either + a [MathOptInterface.jl](https://github.com/jump-dev/MathOptInterface.jl) or a + [JuMP](https://github.com/jump-dev/JuMP.jl) model. + * The [`dual_optimizer`](@ref) function that creates a MathOptInterface-compatible + optimizer that solves the dual of the problem instead of the primal. + +## License + +[Dualization.jl](https://github.com/jump-dev/Dualization.jl) is licensed under +the [MIT License](https://github.com/jump-dev/Dualization.jl/blob/master/LICENSE.md). ## Installation -To install the package you can use `Pkg.add` as follows: +Install Dualization using `Pkg.add`: ```julia -pkg> add Dualization +import Pkg +Pkg.add("Dualization") ``` ## Contributing -Contributions to this package are more than welcome, if you find a bug or have any suggestions for the documentation please post it on the [github issue tracker](https://github.com/jump-dev/Dualization.jl/issues). +Contributions to this package are more than welcome, if you find a bug or have +any suggestions for the documentation please post it on the +[GitHub issue tracker](https://github.com/jump-dev/Dualization.jl/issues). -When contributing please note that the package follows the [JuMP style guide](https://jump.dev/JuMP.jl/stable/developers/style/). +When contributing, please note that the package follows the +[JuMP style guide](https://jump.dev/JuMP.jl/stable/developers/style/). diff --git a/docs/src/manual.md b/docs/src/manual.md index 831bbd67..98947191 100644 --- a/docs/src/manual.md +++ b/docs/src/manual.md @@ -1,313 +1,46 @@ # Manual -!!! note - - This package only works for optimization models that can be written in the conic-form. - -## Conic Duality - -### MOI standard form and duality - -Conic duality is the starting point for MOI's duality conventions. When all functions are affine (or coordinate projections), and all constraint sets are closed convex cones, the model may be called a conic optimization problem. - -The following formulations follow strictly MOI´s definition of duality we shall refer to them as *MOI standard form*. - -For minimization problems, the primal is: - -```math -\begin{align} -& \min_{x \in \mathbb{R}^n} & a_0^T x + b_0 -\\ -& \;\;\text{s.t.} & A_i x + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\end{align} -``` - -and the dual is: - -```math -\begin{align} -& \max_{y_1, \ldots, y_m} & -\sum_{i=1}^m b_i^T y_i + b_0 -\\ -& \;\;\text{s.t.} & a_0 - \sum_{i=1}^m A_i^T y_i & = 0 -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` -where each ``\mathcal{C}_i`` is a closed convex cone and ``\mathcal{C}_i^*`` is its dual cone. - -For maximization problems, the primal is: -```math -\begin{align} -& \max_{x \in \mathbb{R}^n} & a_0^T x + b_0 -\\ -& \;\;\text{s.t.} & A_i x + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\end{align} -``` - -and the dual is: - -```math -\begin{align} -& \min_{y_1, \ldots, y_m} & \sum_{i=1}^m b_i^T y_i + b_0 -\\ -& \;\;\text{s.t.} & - a_0 - \sum_{i=1}^m A_i^T y_i & = 0 -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -Note that the equality constraints have minus signs that could be flipped for -simplicity. However, for generality, we keep the minus signs so that the models -displayed here precisely match the outputs of the package. - -A linear inequality constraint ``a^T x + b \ge c`` should be interpreted as -``a^T x + b - c \in \mathbb{R}_+``, and similarly ``a^T x + b \le c`` should be -interpreted as ``a^T x + b - c \in \mathbb{R}_-``. -Variable-wise constraints should be interpreted as affine constraints with the -appropriate identity mapping in place of ``A_i``. - -We will always present the maximization forms after the minimization form for -completeness. However, it is possible to obtain the maximizatio dual by flipping -the objective signs of a maximization problem, converting it in a minimization -problem, then apply minimization duality and flip the signs again to obtain -the dual as a minimization problem. - -For the special case of minimization LPs, the MOI primal form can be stated as -```math -\begin{align} -& \min_{x \in \mathbb{R}^n} & a_0^T x &+ b_0 -\\ -& \;\;\text{s.t.} -&A_1 x & \ge b_1\\ -&& A_2 x & \le b_2\\ -&& A_3 x & = b_3 -\end{align} -``` - -By applying the stated transformations to conic form, taking the dual, and transforming back into linear inequality form, one obtains the following dual: - -```math -\begin{align} -& \max_{y_1,y_2,y_3} & b_1^Ty_1 + b_2^Ty_2 + b_3^Ty_3 &+ b_0 -\\ -& \;\;\text{s.t.} -& -A_1^Ty_1 -A_2^Ty_2 -A_3^Ty_3 & = -a_0\\ -&& y_1 &\ge 0\\ -&& y_2 &\le 0 -\end{align} -``` - -For maximization LPs, the MOI primal form can be stated as: -```math -\begin{align} -& \max_{x \in \mathbb{R}^n} & a_0^T x &+ b_0 -\\ -& \;\;\text{s.t.} -&A_1 x & \ge b_1\\ -&& A_2 x & \le b_2\\ -&& A_3 x & = b_3 -\end{align} -``` - -and similarly, the dual is: -```math -\begin{align} -& \min_{y_1,y_2,y_3} & -b_1^Ty_1 - b_2^Ty_2 - b_3^Ty_3 &+ b_0 -\\ -& \;\;\text{s.t.} -& -A_1^Ty_1 - A_2^Ty_2 - A_3^Ty_3 & = a_0\\ -&& y_1 &\ge 0\\ -&& y_2 &\le 0 -\end{align} -``` - -### MOI compact form and duality - -An equivalent formulation for conic duality explicitly constrains variables into cones. The implicit version can be achieved with the above formulation (MOI standard form) by considering the `A_i` that are projections onto some of the canonical axis. - -The explicit constraints on variables convey additional structural information that can be exploited by some solver. Therefore, MOI includes the method `add_constrained_variables` for such purpose. These constraints are special because they are created together with the corresponding constrained variables. Hence, each variable can only belong to one of such. - -Next, we precisely define the *MOI compact form* and present their respective dual problems. The reader will notice that the models are more verbose than the MOI standard form, but actually the solvers receives fewer constraints and slack variables are avoided. Consequently, the dual will have fewer variables and fewer constraints. - -#### Minimization problem in MOI compact form - -The primal is: - -```math -\begin{align} -& \min_{x_1, \dots, x_n} & \sum_{j=1}^n a_j^T x_j + b_0 -\\ -& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\\ -& & x_j & \in \mathcal{V}_j & j = 1 \ldots n -\end{align} -``` - -and the dual is: - -```math -\begin{align} -& \max_{y_1, \ldots, y_m} & -\sum_{i=1}^m b_i^T y_i + b_0 -\\ -& \;\;\text{s.t.} & - \sum_{i=1}^m A_{ij}^T y_i + a_j & \in \mathcal{V}_j^* & j = 1 \ldots n -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` -where each ``\mathcal{C}_i`` and ``\mathcal{V}_j`` are closed convex cones and ``\mathcal{C}_i^*`` and ``\mathcal{V}_j^*`` the respective dual cones. - -#### Maximization problem in MOI compact form - -The primal is: - -```math -\begin{align} -& \max_{x_1, \dots, x_n} & \sum_{j=1}^n a_j^T x_j + b_0 -\\ -& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\\ -& & x_j & \in \mathcal{V}_j & j = 1 \ldots n -\end{align} -``` - -and the dual is: - -```math -\begin{align} -& \min_{y_1, \ldots, y_m} & \sum_{i=1}^m b_i^T y_i + b_0 -\\ -& \;\;\text{s.t.} & - \sum_{i=1}^m A_{ij}^T y_i - a_j & \in \mathcal{V}_j^* & j = 1 \ldots n -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -Note that signs changed in the constraints of the dual compared to the standard form. This is because the standard form would have negative signs in all terms in a equality constraint, which were inverted for simplicity. However, in the compact form, this operation is not allowed because it would change a nontrivial cone ``\mathcal{C}_i``. - -##### Linear Programming - -###### Minimization - -###### Primal - -```math -\begin{align} -& \min_{x_{I}, x_{II}, x_{III}} & a_{I}^T x_{I} + a_{II}^T x_{II} + a_{III}^T x_{III} &+ b_0 -\\ -& \;\;\text{s.t.} -& A_{1,I} x_{I} +A_{1,II} x_{II} + A_{1,III} x_{III} & \ge b_1\\ -&&A_{2,I} x_{I} +A_{2,II} x_{II} + A_{2,III} x_{III} & \le b_2\\ -&&A_{3,I} x_{I} +A_{3,II} x_{II} + A_{3,III} x_{III} & = b_3\\ -&& x_{I} & \ge 0\\ -&& x_{II} & \le 0 -\end{align} -``` - -###### Dual - -```math -\begin{align} -& \max_{y_1, y_2, y_3} & b_1^T y_1 + b_2^T y_2 + b_3^T y_3 &+ b_0 -\\ -& \;\;\text{s.t.} -& - A_{1,I}^T y_1 -A_{2,I}^T y_2 - A_{3,I}^T y_3 & \ge - a_{I}\\ -&& - A_{1,II}^T y_1 -A_{2,II}^T y_2 - A_{3,II}^T y_3 & \le - a_{II}\\ -&& - A_{1,III}^T y_1 -A_{2,III}^T y_2 - A_{3,III}^T y_3 & = - a_{III}\\ -&& y_1 & \ge 0\\ -&& y_2 & \le 0 -\end{align} -``` - -###### Maximization - -###### Primal - -```math -\begin{align} -& \max_{x_{I}, x_{II}, x_{III}} & a_{I}^T x_{I} + a_{II}^T x_{II} + a_{III}^T x_{III} &+ b_0 -\\ -& \;\;\text{s.t.} -& A_{1,I} x_{I} +A_{1,II} x_{II} + A_{1,III} x_{III} & \ge b_1\\ -&&A_{2,I} x_{I} +A_{2,II} x_{II} + A_{2,III} x_{III} & \le b_2\\ -&&A_{3,I} x_{I} +A_{3,II} x_{II} + A_{3,III} x_{III} & = b_3\\ -&& x_{I} & \ge 0\\ -&& x_{II} & \le 0 -\end{align} -``` - -###### Dual - -```math -\begin{align} -& \min_{y_1, y_2, y_3} & -b_1^T y_1 - b_2^T y_2 - b_3^T y_3 &+ b_0 -\\ -& \;\;\text{s.t.} -& -A_{1,I}^T y_1 - A_{2,I}^T y_2 - A_{3,I}^T y_3 & \ge a_{I}\\ -&& -A_{1,II}^T y_1 - A_{2,II}^T y_2 - A_{3,II}^T y_3 & \le a_{II}\\ -&& -A_{1,III}^T y_1 - A_{2,III}^T y_2 - A_{3,III}^T y_3 & = a_{III}\\ -&& y_1 & \ge 0\\ -&& y_2 & \le 0 -\end{align} -``` - -## Supported constraints - -This is the list of supported `Function-in-Set` constraints of the package. If you try to dualize -a constraint not listed here, it will return an unsupported error. - -| MOI Function | MOI Set | -|:-------|:---------------| -| `VariableIndex` | `GreaterThan` | -| `VariableIndex` | `LessThan` | -| `VariableIndex` | `EqualTo` | -| `ScalarAffineFunction` | `GreaterThan` | -| `ScalarAffineFunction` | `LessThan` | -| `ScalarAffineFunction` | `EqualTo` | -| `VectorOfVariables` | `Nonnegatives` | -| `VectorOfVariables` | `Nonpositives` | -| `VectorOfVariables` | `Zeros` | -| `VectorOfVariables` | `SecondOrderCone` | -| `VectorOfVariables` | `RotatedSecondOrderCone` | -| `VectorOfVariables` | `PositiveSemidefiniteConeTriangle` | -| `VectorOfVariables` | `ExponentialCone` | -| `VectorOfVariables` | `DualExponentialCone` | -| `VectorOfVariables` | `PowerCone` | -| `VectorOfVariables` | `DualPowerCone` | -| `VectorAffineFunction` | `Nonnegatives` | -| `VectorAffineFunction` | `Nonpositives` | -| `VectorAffineFunction` | `Zeros` | -| `VectorAffineFunction` | `SecondOrderCone` | -| `VectorAffineFunction` | `RotatedSecondOrderCone` | -| `VectorAffineFunction` | `PositiveSemidefiniteConeTriangle` | -| `VectorAffineFunction` | `ExponentialCone` | -| `VectorAffineFunction` | `DualExponentialCone` | -| `VectorAffineFunction` | `PowerCone` | -| `VectorAffineFunction` | `DualPowerCone` | +## Supported problem types + +Dualization.jl works only for optimization models that can be written in conic +form, and that are composed of the following constraints and objectives. + +If you try to dualize an unsupported model, and error will be thrown. + +### Constraints + +| Function | Set | +|:-------------------------- |:-------------------------------------- | +| `MOI.VariableIndex` or `MOI.ScalarAffineFunction` | `MOI.GreaterThan` | +| `MOI.VariableIndex` or `MOI.ScalarAffineFunction` | `MOI.LessThan` | +| `MOI.VariableIndex` or `MOI.ScalarAffineFunction` | `MOI.EqualTo` | +| `MOI.VectorOfVariables` or `MOI.VectorAffineFunction` | `MOI.Nonnegatives` | +| `MOI.VectorOfVariables` or `MOI.VectorAffineFunction` | `MOI.Nonpositives` | +| `MOI.VectorOfVariables` or `MOI.VectorAffineFunction` | `MOI.Zeros` | +| `MOI.VectorOfVariables` or `MOI.VectorAffineFunction` | `MOI.SecondOrderCone` | +| `MOI.VectorOfVariables` or `MOI.VectorAffineFunction` | `MOI.RotatedSecondOrderCone` | +| `MOI.VectorOfVariables` or `MOI.VectorAffineFunction` | `MOI.PositiveSemidefiniteConeTriangle` | +| `MOI.VectorOfVariables` or `MOI.VectorAffineFunction` | `MOI.ExponentialCone` | +| `MOI.VectorOfVariables` or `MOI.VectorAffineFunction` | `MOI.DualExponentialCone` | +| `MOI.VectorOfVariables` or `MOI.VectorAffineFunction` | `MOI.PowerCone` | +| `MOI.VectorOfVariables` or `MOI.VectorAffineFunction` | `MOI.DualPowerCone` | Note that some of MOI constraints can be bridged, see [Bridges](http://jump.dev/MathOptInterface.jl/stable/apireference/#Bridges-1), to constraints in this list. -## Supported objective functions +### Objective functions -| MOI Function | -|:-------:| -| `VariableIndex` | -| `ScalarAffineFunction` | -| `ScalarQuadraticFunction` | +| Function | +|:----------------------------- | +| `MOI.VariableIndex` | +| `MOI.ScalarAffineFunction` | +| `MOI.ScalarQuadraticFunction` | ## Dualize a model -```@docs -dualize -``` - ## DualOptimizer You can solve a primal problem by using its dual formulation using the `DualOptimizer`. -```@docs -DualOptimizer -``` - Solving an optimization problem via its dual representation can be useful because some conic solvers assume the model is in the standard form and others use the geometric form. Geometric form has affine expressions in cones @@ -340,12 +73,11 @@ Standard form has variables in cones | SDPA | SeDuMi | | Mosek v9 | -!!! note - - Mosek v10 now supports both affine constraints in cones and variables in cones hence both the standard and geometric form at the same time. - -!!! note +!!! note + Mosek v10 now supports both affine constraints in cones and variables in + cones hence both the standard and geometric form at the same time. +!!! note MOI standard form is the Geometric form and not the "textbook" Standard form. ## Adding new sets @@ -354,7 +86,7 @@ Dualization.jl can automatically dualize models with custom sets. To do this, the user needs to define the set and its dual set and provide the functions: * `supported_constraint` -* `dual_set` +* `dual_set` If the custom set has some special scalar product (see the [link](https://jump.dev/MathOptInterface.jl/stable/apireference/#MathOptInterface.AbstractSymmetricMatrixSetTriangle)), the user also needs to provide a `set_dot` function. @@ -409,7 +141,7 @@ MOI.Utilities.set_dot(x::Vector, y::Vector, set::FakeCone) = 2dot(x, y) dual_model = dualize(model) ``` -The resulting dual model is +The resulting dual model is ```math \begin{align} @@ -455,7 +187,7 @@ The resulting dual model is ```math \begin{align} - & \max_{con} & - 3con_1& - 3con_2 - 3con_3 + & \max_{con} & - 3con_1& - 3con_2 - 3con_3 \\ & \;\;\text{s.t.} &2con_1 & = 1\\ @@ -464,825 +196,3 @@ The resulting dual model is && con & \in FakeDualCone(3)\\ \end{align} ``` - -## Advanced - -### KKT Conditions - -The KKT conditions are a set of inequalities for which the feasible solution is equivalent to the optimal solution of an optimization problem, as long as strong duality holds and constraint qualification rules such as Slater's are valid. The KKT is used in many branches of optimization and it might be interesting to write them programmatically. - -#### MOI standard form - -##### Minimization - -The KKT conditions of the minimization problem of the first section are the following: - -* Primal Feasibility: - -```math -A_i x + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m -``` - -* Complementary slackness: - -```math -y_i^T (A_i x + b_i) = 0, \ \ i = 1 \ldots m -``` - -* Stationarity: - -```math -a_0 - \sum_{i=1}^m A_i^T y_i = 0 -``` - -Note that "Dual Feasibility" and "Stationarity" correspond to the two constraints of the dual problem. Therefore, after writing the primal problem, Dualization.jl can obtain the dual problem automatically and then we simply have to write the "Complementary slackness" to complete the KKT conditions. - -One important use case is Bilevel optimization, see [BilevelJuMP.jl](https://github.com/joaquimg/BilevelJuMP.jl). In this case, variables of an upstream model are considered as parameters in a lower level model. One classical solution method for bilevel programs is to write the KKT conditions of the lower (or inner) problem and consider them as (non-linear) constraints of the upper (or outer) problem. Dualization can be used to derive parts of KKT conditions. - -##### Maximization - -* Primal Feasibility: - -```math -A_i x + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m -``` - -* Complementary slackness: - -```math -y_i^T (A_i x + b_i) = 0, \ \ i = 1 \ldots m -``` - -* Stationarity: - -```math -- a_0 - \sum_{i=1}^m A_i^T y_i = 0 -``` - -#### MOI compact form - -##### Minimization - -* Primal Feasibility: - -```math -\sum_{j=1}^n A_{ij} x_j + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ -x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ -u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n -``` - -* Complementary slackness: - -```math -y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i) = 0, \ \ i = 1 \ldots m \\ -u_j^T x_j = 0, \ \ j = 1 \ldots n -``` - -* Stationarity: - -```math - - \sum_{i=1}^m A_{ij}^T y_i + a_j = u_j, \ \ j = 1 \ldots n -``` - -We keep the ``u_j`` variable explicit to make Dual Feasibility and Complementary -Slackness very clear. However, in the final model it is possible to replace the -latter using the stationarity constraint. - -##### Maximization - -* Primal Feasibility: - -```math -\sum_{j=1}^n A_{ij} x_j + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ -x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ -u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n -``` - -* Complementary slackness: - -```math -y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i) = 0, \ \ i = 1 \ldots m \\ -u_j^T x_j = 0, \ \ j = 1 \ldots n -``` - -* Stationarity: - -```math - - \sum_{i=1}^m A_{ij}^T y_i - a_j = u_j, \ \ j = 1 \ldots n -``` - -### Parametric problems - -It is also possible to deal with parametric models. In regular optimization problems we only have a single (vector) variable represented by ``x`` in the duality section, there are many use cases in which we can represent parameters that will not be considered in the optimization, these are treated as constants and, hence, not "dualized". - -In the following, we will use ``x`` to denote primal optimization variables, ``y`` for dual optimization variables and ``z`` for parameters. - -#### MOI standard form - -##### Minimization - -###### Primal - -```math -\begin{align} -& \min_{x \in \mathbb{R}^n} & a_0^T x + b_0 + d_0^Tz -\\ -& \;\;\text{s.t.} & A_i x + b_i + D_i z & \in \mathcal{C}_i & i = 1 \ldots m -\end{align} -``` - -###### Dual - -```math -\begin{align} -& \max_{y_1, \ldots, y_m} & -\sum_{i=1}^m (b_i + D_iz)^T y_i + b_0 + d_0^Tz -\\ -& \;\;\; \text{s.t.} & a_0 - \sum_{i=1}^m A_i^T y_i & = 0 -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -###### KKT - -* Primal Feasibility: - -```math -A_i x + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m -``` - -* Complementary slackness: - -```math -y_i^T (A_i x + b_i + D_i z) = 0, \ \ i = 1 \ldots m -``` - -* Stationarity: - -```math -a_0 - \sum_{i=1}^m A_i^T y_i = 0 -``` - -##### Maximization - -###### Primal - -```math -\begin{align} -& \max_{x \in \mathbb{R}^n} & a_0^T x + b_0 + d_0^Tz -\\ -& \;\;\text{s.t.} & A_i x + b_i + D_i z & \in \mathcal{C}_i & i = 1 \ldots m -\end{align} -``` - -###### Dual - -```math -\begin{align} -& \min_{y_1, \ldots, y_m} & \sum_{i=1}^m (b_i + D_iz)^T y_i + b_0 + d_0^Tz -\\ -& \;\;\; \text{s.t.} & - a_0 - \sum_{i=1}^m A_i^T y_i & = 0 -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -###### KKT - -* Primal Feasibility: - -```math -A_i x + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m -``` - -* Complementary slackness: - -```math -y_i^T (A_i x + b_i + D_i z) = 0, \ \ i = 1 \ldots m -``` - -* Stationarity: - -```math -- a_0 - \sum_{i=1}^m A_i^T y_i = 0 -``` - -#### MOI compact form - -##### Minimization - -###### Primal - -```math -\begin{align} -& \min_{x_1, \dots, x_n} & \sum_{j=1}^n a_j^T x_j + d^T z + b_0 -\\ -& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + D_i z + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\\ -& & x_j & \in \mathcal{V}_j & j = 1 \ldots n -\end{align} -``` - -###### Dual - -```math -\begin{align} -& \max_{y_1, \ldots, y_m} & - \sum_{i=1}^m (D_i z + b_i)^T y_i + d^T z + b_0 -\\ -& \;\;\text{s.t.} & - \sum_{i=1}^m A_{ij}^T y_i + a_j & \in \mathcal{V}_j^* & j = 1 \ldots n -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -###### KKT - - -* Primal Feasibility: - -```math -\sum_{j=1}^n A_{ij} x_j + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ -x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ -u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n -``` - -* Complementary slackness: - -```math -y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i + D_i z) = 0, \ \ i = 1 \ldots m \\ -u_j^T x_j = 0, \ \ j = 1 \ldots n -``` - -* Stationarity: - -```math -- \sum_{i=1}^m A_{ij}^T y_i + a_j = u_j, \ \ j = 1 \ldots n -``` - -##### Maximization - -###### Primal - -```math -\begin{align} -& \max_{x_1, \dots, x_n} & \sum_{j=1}^n a_j^T x_j + d^T z + b_0 -\\ -& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + D_i z + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\\ -& & x_j & \in \mathcal{V}_j & j = 1 \ldots n -\end{align} -``` - -###### Dual - -```math -\begin{align} -& \min_{y_1, \ldots, y_m} & \sum_{i=1}^m (D_i z + b_i)^T y_i + d^T z + b_0 -\\ -& \;\;\text{s.t.} & - \sum_{i=1}^m A_{ij}^T y_i - a_j & \in \mathcal{V}_j^* & j = 1 \ldots n -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -###### KKT - - -* Primal Feasibility: - -```math -\sum_{j=1}^n A_{ij} x_j + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ -x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ -u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n -``` - -* Complementary slackness: - -```math -y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i + D_i z) = 0, \ \ i = 1 \ldots m \\ -u_j^T x_j = 0, \ \ j = 1 \ldots n -``` - -* Stationarity: - -```math -- \sum_{i=1}^m A_{ij}^T y_i - a_j = u_j, \ \ j = 1 \ldots n -``` - -### Quadratic problems - -Optimization problems with conic constraints and quadratic objective are straightforward extensions to the conic problems with linear constraints usually defined in MOI. More information [here](http://www.seas.ucla.edu/~vandenbe/publications/coneprog.pdf). - -#### MOI standard form - -##### Minimization - -###### Primal - -```math -\begin{align} -& \min_{x \in \mathbb{R}^n} & \frac{1}{2} x^T P x + a_0^T x + b_0 -\\ -& \;\;\text{s.t.} & A_i x + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\end{align} -``` - -Where `P` is a positive semidefinite matrix. - -###### Dual - -A compact formulation for the dual problem requires pseudo-inverses, however, we can add an extra slack variable `w` to the dual problem and obtain the following dual problem: - -```math -\begin{align} -& \max_{y_1, \ldots, y_m} & - \frac{1}{2} w^T P w - \sum_{i=1}^m b_i^T y_i + b_0 -\\ -& \;\;\text{s.t.} & a_0 - \sum_{i=1}^m A_i^T y_i + P w & = 0 -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -note that, in the constraint, the sign in front of the `P` matrix can be changed because `w` is free and the only other term depending in `w` is quadratic and symmetric. -The sign choice is interesting to keep the dual problem closer to the KKT conditions that reads as follows. - -###### KKT - -* Primal Feasibility: - -```math -A_i x + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m -``` - -* Complementary slackness: - -```math -y_i^T (A_i x + b_i) = 0, \ \ i = 1 \ldots m -``` - -* Stationarity: - -```math -P x + a_0 - \sum_{i=1}^m A_i^T y_i = 0 -``` - -##### Maximization - -###### Primal - -```math -\begin{align} -& \max_{x \in \mathbb{R}^n} & \frac{1}{2} x^T N x + a_0^T x + b_0 -\\ -& \;\;\text{s.t.} & A_i x + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\end{align} -``` - -Where `N` is negative semidefinite, i.e., `-N` is a positive semidefinite matrix. - -###### Dual - -Just like in the minimization case we can add an extra slack variable `w` to -the dual problem and obtain the following dual problem: - -```math -\begin{align} -& \min_{y_1, \ldots, y_m} & - \frac{1}{2} w^T N w + \sum_{i=1}^m b_i^T y_i + b_0 -\\ -& \;\;\text{s.t.} & - a_0 - \sum_{i=1}^m A_i^T y_i - N w & = 0 -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -note that, in the constraint, the sign in front of the `N` matrix can be changed because `w` is free and the only other term depending in `w` is quadratic and symmetric. -The sign choice is interesting to keep the dual problem closer to the KKT conditions that reads as follows. - -###### KKT - -* Primal Feasibility: - -```math -A_i x + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m -``` - -* Complementary slackness: - -```math -y_i^T (A_i x + b_i) = 0, \ \ i = 1 \ldots m -``` - -* Stationarity: - -```math -- N x - a_0 - \sum_{i=1}^m A_i^T y_i = 0 -``` - -#### MOI compact form - -##### Minimization - -###### Primal - -```math -\begin{align} -& \min_{x_1, \dots, x_n} & \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n x_j^T P_{j,k} x_k + \sum_{j=1}^n a_j^T x_j + b_0 -\\ -& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\\ -& & x_j & \in \mathcal{V}_j & j = 1 \ldots n -\end{align} -``` - -###### Dual - -```math -\begin{align} -& \max_{y_1, \ldots, y_m, w_1, \ldots, w_n} & - \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n w_j^T P_{j,k} w_k - \sum_{i=1}^m b_i^T y_i + b_0 -\\ -& \;\;\text{s.t.} & \sum_{k=1}^n P_{j,k} w_k - \sum_{i=1}^m A_{ij}^T y_i + a_j & \in \mathcal{V}_j^* & j = 1 \ldots n -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -###### KKT - - -* Primal Feasibility: - -```math -\sum_{j=1}^n A_{ij} x_j + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ -x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ -u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n -``` - -* Complementary slackness: - -```math -y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i) = 0, \ \ i = 1 \ldots m \\ -u_j^T x_j = 0, \ \ j = 1 \ldots n -``` - -* Stationarity: - -```math -\sum_{k=1}^n P_{j,k} x_k - \sum_{i=1}^m A_{ij}^T y_i + a_j = u_j, \ \ j = 1 \ldots n -``` - -##### Maximization - -###### Primal - -```math -\begin{align} -& \max_{x_1, \dots, x_n} & \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n x_j^T N_{j,k} x_k + \sum_{j=1}^n a_j^T x_j + b_0 -\\ -& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\\ -& & x_j & \in \mathcal{V}_j & j = 1 \ldots n -\end{align} -``` - -###### Dual - -```math -\begin{align} -& \min_{y_1, \ldots, y_m, w_1, \ldots, w_n} & - \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n w_j^T N_{j,k} w_k + \sum_{i=1}^m b_i^T y_i + b_0 -\\ -& \;\;\text{s.t.} & - \sum_{k=1}^n N_{j,k} w_k - \sum_{i=1}^m A_{ij}^T y_i - a_j & \in \mathcal{V}_j^* & j = 1 \ldots n -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -###### KKT - - -* Primal Feasibility: - -```math -\sum_{j=1}^n A_{ij} x_j + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ -x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ -u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n -``` - -* Complementary slackness: - -```math -y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i) = 0, \ \ i = 1 \ldots m \\ -u_j^T x_j = 0, \ \ j = 1 \ldots n -``` - -* Stationarity: - -```math -- \sum_{k=1}^n N_{j,k} x_k - \sum_{i=1}^m A_{ij}^T y_i - a_j = u_j, \ \ j = 1 \ldots n -``` - -### Parametric quadratic problems - -Just like the conic linear problems, these quadratic programs can be parametric. - -#### MOI standard form - -##### Minimization - -###### Primal - -```math -\begin{align} -& \min_{x \in \mathbb{R}^n} & + \frac{1}{2} x^T P_1 x + x^T P_2 z + \frac{1}{2} z^T P_3 z -\\ -& & + a_0^T x + b_0 + d_0^T z \notag -\\ -& \;\;\text{s.t.} & A_i x + b_i + D_i z & \in \mathcal{C}_i & i = 1 \ldots m -\end{align} -``` - -###### Dual - -```math -\begin{align} -& \max_{y_1, \ldots, y_m} & - \frac{1}{2} w^T P_1 w + \frac{1}{2} z^T P_3 z -\\ -& & -\sum_{i=1}^m (b_i + D_i z)^T y_i + d_0^T z + b_0 \notag -\\ -& \;\;\text{s.t.} & a_0 + P_2 z - \sum_{i=1}^m A_i^T y_i + P_1 w & = 0 -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -###### KKT - - -* Primal Feasibility: - -```math -A_i x + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m -``` - -* Complementary slackness: - -```math -y_i^T (A_i x + b_i + D_i z) = 0, \ \ i = 1 \ldots m -``` - -* Stationarity: - -```math -P_1 x + P_2 z + a_0 - \sum_{i=1}^m A_i^T y_i = 0 -``` - -##### Maximization - -###### Primal - -```math -\begin{align} -& \max_{x \in \mathbb{R}^n} & + \frac{1}{2} x^T N_1 x + x^T N_2 z + \frac{1}{2} z^T N_3 z -\\ -& & + a_0^T x + b_0 + d_0^T z \notag -\\ -& \;\;\text{s.t.} & A_i x + b_i + D_i z & \in \mathcal{C}_i & i = 1 \ldots m -\end{align} -``` - -###### Dual - -```math -\begin{align} -& \min_{y_1, \ldots, y_m} & - \frac{1}{2} w^T N_1 w + \frac{1}{2} z^T N_3 z -\\ -& & +\sum_{i=1}^m (b_i + D_i z)^T y_i + d_0^T z + b_0 \notag -\\ -& \;\;\text{s.t.} & - a_0 - N_2 z - \sum_{i=1}^m A_i^T y_i - N_1 w & = 0 -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -###### KKT - - -* Primal Feasibility: - -```math -A_i x + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m -``` - -* Complementary slackness: - -```math -y_i^T (A_i x + b_i + D_i z) = 0, \ \ i = 1 \ldots m -``` - -* Stationarity: - -```math -- N_1 x - N_2 z - a_0 - \sum_{i=1}^m A_i^T y_i = 0 -``` - - -#### MOI compact form - -##### Minimization - -###### Primal - -```math -\begin{align} -& \min_{x_1, \dots, x_n} & \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n x_j^T P_{j,k} x_k + \sum_{j=1}^n x_j^T P_{j,0} z \\ -& & + \frac{1}{2} z^T P_{0,0} z + \sum_{j=1}^n a_j^T x_j + d^T z + b_0 -\\ -& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + D_i z + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\\ -& & x_j & \in \mathcal{V}_j & j = 1 \ldots n -\end{align} -``` - -###### Dual - -```math -\begin{align} -& \max_{y_1, \ldots, y_m, w_1, \ldots, w_n} & - \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n w_j^T P_{j,k} w_k - \sum_{i=1}^m (D_i z + b_i)^T y_i\\ -& & + \frac{1}{2} z^T P_{0,0} z + d^T z + b_0 -\\ -& \;\;\text{s.t.} & \sum_{k=1}^n P_{j,k} w_k - \sum_{i=1}^m A_{ij}^T y_i + a_j + P_{j,0} z & \in \mathcal{V}_j^* & j = 1 \ldots n -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -###### KKT - - -* Primal Feasibility: - -```math -\sum_{j=1}^n A_{ij} x_j + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ -x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ -u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n -``` - -* Complementary slackness: - -```math -y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i + D_i z) = 0, \ \ i = 1 \ldots m \\ -u_j^T x_j = 0, \ \ j = 1 \ldots n -``` - -* Stationarity: - -```math -\sum_{k=1}^n P_{j,k} x_k - \sum_{i=1}^m A_{ij}^T y_i + a_j + P_{j,0} z = u_j, \ \ j = 1 \ldots n -``` - -##### Maximization - -###### Primal - -```math -\begin{align} -& \max_{x_1, \dots, x_n} & \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n x_j^T N_{j,k} x_k + \sum_{j=1}^n x_j^T N_{j,0} z \\ -& & + \frac{1}{2} z^T N_{0,0} z + \sum_{j=1}^n a_j^T x_j + d^T z + b_0 -\\ -& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + D_i z + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\\ -& & x_j & \in \mathcal{V}_j & j = 1 \ldots n -\end{align} -``` - -###### Dual - -```math -\begin{align} -& \min_{y_1, \ldots, y_m, w_1, \ldots, w_n} & - \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n w_j^T N_{j,k} w_k + \sum_{i=1}^m (D_i z + b_i)^T y_i\\ -& & + \frac{1}{2} z^T N_{0,0} z + d^T z + b_0 -\\ -& \;\;\text{s.t.} & - \sum_{k=1}^n N_{j,k} w_k - \sum_{i=1}^m A_{ij}^T y_i - a_j - N_{j,0} z & \in \mathcal{V}_j^* & j = 1 \ldots n -\\ -& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m -\end{align} -``` - -###### KKT - - -* Primal Feasibility: - -```math -\sum_{j=1}^n A_{ij} x_j + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ -x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n -``` - -* Dual Feasibility: - -```math -y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ -u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n -``` - -* Complementary slackness: - -```math -y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i + D_i z) = 0, \ \ i = 1 \ldots m \\ -u_j^T x_j = 0, \ \ j = 1 \ldots n -``` - -* Stationarity: - -```math -- \sum_{k=1}^n N_{j,k} x_k - \sum_{i=1}^m A_{ij}^T y_i - a_j - N_{j,0} z = u_j, \ \ j = 1 \ldots n -``` diff --git a/docs/src/mathematical_background.md b/docs/src/mathematical_background.md new file mode 100644 index 00000000..ae6401ee --- /dev/null +++ b/docs/src/mathematical_background.md @@ -0,0 +1,1070 @@ +# Mathematical background + +## MOI standard form and duality + +Conic duality is the starting point for MOI's duality conventions. When all +functions are affine (or coordinate projections), and all constraint sets are +closed convex cones, the model may be called a conic optimization problem. + +The following formulations follow strictly MOI´s definition of duality we shall +refer to them as *MOI standard form*. + +For minimization problems, the primal is: + +```math +\begin{align} +& \min_{x \in \mathbb{R}^n} & a_0^T x + b_0 +\\ +& \;\;\text{s.t.} & A_i x + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\end{align} +``` + +and the dual is: + +```math +\begin{align} +& \max_{y_1, \ldots, y_m} & -\sum_{i=1}^m b_i^T y_i + b_0 +\\ +& \;\;\text{s.t.} & a_0 - \sum_{i=1}^m A_i^T y_i & = 0 +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` +where each ``\mathcal{C}_i`` is a closed convex cone and ``\mathcal{C}_i^*`` is its dual cone. + +For maximization problems, the primal is: +```math +\begin{align} +& \max_{x \in \mathbb{R}^n} & a_0^T x + b_0 +\\ +& \;\;\text{s.t.} & A_i x + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\end{align} +``` + +and the dual is: + +```math +\begin{align} +& \min_{y_1, \ldots, y_m} & \sum_{i=1}^m b_i^T y_i + b_0 +\\ +& \;\;\text{s.t.} & - a_0 - \sum_{i=1}^m A_i^T y_i & = 0 +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +Note that the equality constraints have minus signs that could be flipped for +simplicity. However, for generality, we keep the minus signs so that the models +displayed here precisely match the outputs of the package. + +A linear inequality constraint ``a^T x + b \ge c`` should be interpreted as +``a^T x + b - c \in \mathbb{R}_+``, and similarly ``a^T x + b \le c`` should be +interpreted as ``a^T x + b - c \in \mathbb{R}_-``. +Variable-wise constraints should be interpreted as affine constraints with the +appropriate identity mapping in place of ``A_i``. + +We will always present the maximization forms after the minimization form for +completeness. However, it is possible to obtain the maximizatio dual by flipping +the objective signs of a maximization problem, converting it in a minimization +problem, then apply minimization duality and flip the signs again to obtain +the dual as a minimization problem. + +For the special case of minimization LPs, the MOI primal form can be stated as +```math +\begin{align} +& \min_{x \in \mathbb{R}^n} & a_0^T x &+ b_0 +\\ +& \;\;\text{s.t.} +&A_1 x & \ge b_1\\ +&& A_2 x & \le b_2\\ +&& A_3 x & = b_3 +\end{align} +``` + +By applying the stated transformations to conic form, taking the dual, and transforming back into linear inequality form, one obtains the following dual: + +```math +\begin{align} +& \max_{y_1,y_2,y_3} & b_1^Ty_1 + b_2^Ty_2 + b_3^Ty_3 &+ b_0 +\\ +& \;\;\text{s.t.} +& -A_1^Ty_1 -A_2^Ty_2 -A_3^Ty_3 & = -a_0\\ +&& y_1 &\ge 0\\ +&& y_2 &\le 0 +\end{align} +``` + +For maximization LPs, the MOI primal form can be stated as: +```math +\begin{align} +& \max_{x \in \mathbb{R}^n} & a_0^T x &+ b_0 +\\ +& \;\;\text{s.t.} +&A_1 x & \ge b_1\\ +&& A_2 x & \le b_2\\ +&& A_3 x & = b_3 +\end{align} +``` + +and similarly, the dual is: +```math +\begin{align} +& \min_{y_1,y_2,y_3} & -b_1^Ty_1 - b_2^Ty_2 - b_3^Ty_3 &+ b_0 +\\ +& \;\;\text{s.t.} +& -A_1^Ty_1 - A_2^Ty_2 - A_3^Ty_3 & = a_0\\ +&& y_1 &\ge 0\\ +&& y_2 &\le 0 +\end{align} +``` + +### MOI compact form and duality + +An equivalent formulation for conic duality explicitly constrains variables into cones. The implicit version can be achieved with the above formulation (MOI standard form) by considering the `A_i` that are projections onto some of the canonical axis. + +The explicit constraints on variables convey additional structural information that can be exploited by some solver. Therefore, MOI includes the method `add_constrained_variables` for such purpose. These constraints are special because they are created together with the corresponding constrained variables. Hence, each variable can only belong to one of such. + +Next, we precisely define the *MOI compact form* and present their respective dual problems. The reader will notice that the models are more verbose than the MOI standard form, but actually the solvers receives fewer constraints and slack variables are avoided. Consequently, the dual will have fewer variables and fewer constraints. + +#### Minimization problem in MOI compact form + +The primal is: + +```math +\begin{align} +& \min_{x_1, \dots, x_n} & \sum_{j=1}^n a_j^T x_j + b_0 +\\ +& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\\ +& & x_j & \in \mathcal{V}_j & j = 1 \ldots n +\end{align} +``` + +and the dual is: + +```math +\begin{align} +& \max_{y_1, \ldots, y_m} & -\sum_{i=1}^m b_i^T y_i + b_0 +\\ +& \;\;\text{s.t.} & - \sum_{i=1}^m A_{ij}^T y_i + a_j & \in \mathcal{V}_j^* & j = 1 \ldots n +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` +where each ``\mathcal{C}_i`` and ``\mathcal{V}_j`` are closed convex cones and ``\mathcal{C}_i^*`` and ``\mathcal{V}_j^*`` the respective dual cones. + +#### Maximization problem in MOI compact form + +The primal is: + +```math +\begin{align} +& \max_{x_1, \dots, x_n} & \sum_{j=1}^n a_j^T x_j + b_0 +\\ +& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\\ +& & x_j & \in \mathcal{V}_j & j = 1 \ldots n +\end{align} +``` + +and the dual is: + +```math +\begin{align} +& \min_{y_1, \ldots, y_m} & \sum_{i=1}^m b_i^T y_i + b_0 +\\ +& \;\;\text{s.t.} & - \sum_{i=1}^m A_{ij}^T y_i - a_j & \in \mathcal{V}_j^* & j = 1 \ldots n +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +Note that signs changed in the constraints of the dual compared to the standard form. This is because the standard form would have negative signs in all terms in a equality constraint, which were inverted for simplicity. However, in the compact form, this operation is not allowed because it would change a nontrivial cone ``\mathcal{C}_i``. + +##### Linear Programming + +###### Minimization + +###### Primal + +```math +\begin{align} +& \min_{x_{I}, x_{II}, x_{III}} & a_{I}^T x_{I} + a_{II}^T x_{II} + a_{III}^T x_{III} &+ b_0 +\\ +& \;\;\text{s.t.} +& A_{1,I} x_{I} +A_{1,II} x_{II} + A_{1,III} x_{III} & \ge b_1\\ +&&A_{2,I} x_{I} +A_{2,II} x_{II} + A_{2,III} x_{III} & \le b_2\\ +&&A_{3,I} x_{I} +A_{3,II} x_{II} + A_{3,III} x_{III} & = b_3\\ +&& x_{I} & \ge 0\\ +&& x_{II} & \le 0 +\end{align} +``` + +###### Dual + +```math +\begin{align} +& \max_{y_1, y_2, y_3} & b_1^T y_1 + b_2^T y_2 + b_3^T y_3 &+ b_0 +\\ +& \;\;\text{s.t.} +& - A_{1,I}^T y_1 -A_{2,I}^T y_2 - A_{3,I}^T y_3 & \ge - a_{I}\\ +&& - A_{1,II}^T y_1 -A_{2,II}^T y_2 - A_{3,II}^T y_3 & \le - a_{II}\\ +&& - A_{1,III}^T y_1 -A_{2,III}^T y_2 - A_{3,III}^T y_3 & = - a_{III}\\ +&& y_1 & \ge 0\\ +&& y_2 & \le 0 +\end{align} +``` + +###### Maximization + +###### Primal + +```math +\begin{align} +& \max_{x_{I}, x_{II}, x_{III}} & a_{I}^T x_{I} + a_{II}^T x_{II} + a_{III}^T x_{III} &+ b_0 +\\ +& \;\;\text{s.t.} +& A_{1,I} x_{I} +A_{1,II} x_{II} + A_{1,III} x_{III} & \ge b_1\\ +&&A_{2,I} x_{I} +A_{2,II} x_{II} + A_{2,III} x_{III} & \le b_2\\ +&&A_{3,I} x_{I} +A_{3,II} x_{II} + A_{3,III} x_{III} & = b_3\\ +&& x_{I} & \ge 0\\ +&& x_{II} & \le 0 +\end{align} +``` + +###### Dual + +```math +\begin{align} +& \min_{y_1, y_2, y_3} & -b_1^T y_1 - b_2^T y_2 - b_3^T y_3 &+ b_0 +\\ +& \;\;\text{s.t.} +& -A_{1,I}^T y_1 - A_{2,I}^T y_2 - A_{3,I}^T y_3 & \ge a_{I}\\ +&& -A_{1,II}^T y_1 - A_{2,II}^T y_2 - A_{3,II}^T y_3 & \le a_{II}\\ +&& -A_{1,III}^T y_1 - A_{2,III}^T y_2 - A_{3,III}^T y_3 & = a_{III}\\ +&& y_1 & \ge 0\\ +&& y_2 & \le 0 +\end{align} +``` + +## Advanced + +### KKT Conditions + +The KKT conditions are a set of inequalities for which the feasible solution is equivalent to the optimal solution of an optimization problem, as long as strong duality holds and constraint qualification rules such as Slater's are valid. The KKT is used in many branches of optimization and it might be interesting to write them programmatically. + +#### MOI standard form + +##### Minimization + +The KKT conditions of the minimization problem of the first section are the following: + +* Primal Feasibility: + +```math +A_i x + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m +``` + +* Complementary slackness: + +```math +y_i^T (A_i x + b_i) = 0, \ \ i = 1 \ldots m +``` + +* Stationarity: + +```math +a_0 - \sum_{i=1}^m A_i^T y_i = 0 +``` + +Note that "Dual Feasibility" and "Stationarity" correspond to the two constraints of the dual problem. Therefore, after writing the primal problem, Dualization.jl can obtain the dual problem automatically and then we simply have to write the "Complementary slackness" to complete the KKT conditions. + +One important use case is Bilevel optimization, see [BilevelJuMP.jl](https://github.com/joaquimg/BilevelJuMP.jl). In this case, variables of an upstream model are considered as parameters in a lower level model. One classical solution method for bilevel programs is to write the KKT conditions of the lower (or inner) problem and consider them as (non-linear) constraints of the upper (or outer) problem. Dualization can be used to derive parts of KKT conditions. + +##### Maximization + +* Primal Feasibility: + +```math +A_i x + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m +``` + +* Complementary slackness: + +```math +y_i^T (A_i x + b_i) = 0, \ \ i = 1 \ldots m +``` + +* Stationarity: + +```math +- a_0 - \sum_{i=1}^m A_i^T y_i = 0 +``` + +#### MOI compact form + +##### Minimization + +* Primal Feasibility: + +```math +\sum_{j=1}^n A_{ij} x_j + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ +x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ +u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n +``` + +* Complementary slackness: + +```math +y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i) = 0, \ \ i = 1 \ldots m \\ +u_j^T x_j = 0, \ \ j = 1 \ldots n +``` + +* Stationarity: + +```math + - \sum_{i=1}^m A_{ij}^T y_i + a_j = u_j, \ \ j = 1 \ldots n +``` + +We keep the ``u_j`` variable explicit to make Dual Feasibility and Complementary +Slackness very clear. However, in the final model it is possible to replace the +latter using the stationarity constraint. + +##### Maximization + +* Primal Feasibility: + +```math +\sum_{j=1}^n A_{ij} x_j + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ +x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ +u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n +``` + +* Complementary slackness: + +```math +y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i) = 0, \ \ i = 1 \ldots m \\ +u_j^T x_j = 0, \ \ j = 1 \ldots n +``` + +* Stationarity: + +```math + - \sum_{i=1}^m A_{ij}^T y_i - a_j = u_j, \ \ j = 1 \ldots n +``` + +### Parametric problems + +It is also possible to deal with parametric models. In regular optimization problems we only have a single (vector) variable represented by ``x`` in the duality section, there are many use cases in which we can represent parameters that will not be considered in the optimization, these are treated as constants and, hence, not "dualized". + +In the following, we will use ``x`` to denote primal optimization variables, ``y`` for dual optimization variables and ``z`` for parameters. + +#### MOI standard form + +##### Minimization + +###### Primal + +```math +\begin{align} +& \min_{x \in \mathbb{R}^n} & a_0^T x + b_0 + d_0^Tz +\\ +& \;\;\text{s.t.} & A_i x + b_i + D_i z & \in \mathcal{C}_i & i = 1 \ldots m +\end{align} +``` + +###### Dual + +```math +\begin{align} +& \max_{y_1, \ldots, y_m} & -\sum_{i=1}^m (b_i + D_iz)^T y_i + b_0 + d_0^Tz +\\ +& \;\;\; \text{s.t.} & a_0 - \sum_{i=1}^m A_i^T y_i & = 0 +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +###### KKT + +* Primal Feasibility: + +```math +A_i x + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m +``` + +* Complementary slackness: + +```math +y_i^T (A_i x + b_i + D_i z) = 0, \ \ i = 1 \ldots m +``` + +* Stationarity: + +```math +a_0 - \sum_{i=1}^m A_i^T y_i = 0 +``` + +##### Maximization + +###### Primal + +```math +\begin{align} +& \max_{x \in \mathbb{R}^n} & a_0^T x + b_0 + d_0^Tz +\\ +& \;\;\text{s.t.} & A_i x + b_i + D_i z & \in \mathcal{C}_i & i = 1 \ldots m +\end{align} +``` + +###### Dual + +```math +\begin{align} +& \min_{y_1, \ldots, y_m} & \sum_{i=1}^m (b_i + D_iz)^T y_i + b_0 + d_0^Tz +\\ +& \;\;\; \text{s.t.} & - a_0 - \sum_{i=1}^m A_i^T y_i & = 0 +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +###### KKT + +* Primal Feasibility: + +```math +A_i x + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m +``` + +* Complementary slackness: + +```math +y_i^T (A_i x + b_i + D_i z) = 0, \ \ i = 1 \ldots m +``` + +* Stationarity: + +```math +- a_0 - \sum_{i=1}^m A_i^T y_i = 0 +``` + +#### MOI compact form + +##### Minimization + +###### Primal + +```math +\begin{align} +& \min_{x_1, \dots, x_n} & \sum_{j=1}^n a_j^T x_j + d^T z + b_0 +\\ +& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + D_i z + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\\ +& & x_j & \in \mathcal{V}_j & j = 1 \ldots n +\end{align} +``` + +###### Dual + +```math +\begin{align} +& \max_{y_1, \ldots, y_m} & - \sum_{i=1}^m (D_i z + b_i)^T y_i + d^T z + b_0 +\\ +& \;\;\text{s.t.} & - \sum_{i=1}^m A_{ij}^T y_i + a_j & \in \mathcal{V}_j^* & j = 1 \ldots n +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +###### KKT + + +* Primal Feasibility: + +```math +\sum_{j=1}^n A_{ij} x_j + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ +x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ +u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n +``` + +* Complementary slackness: + +```math +y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i + D_i z) = 0, \ \ i = 1 \ldots m \\ +u_j^T x_j = 0, \ \ j = 1 \ldots n +``` + +* Stationarity: + +```math +- \sum_{i=1}^m A_{ij}^T y_i + a_j = u_j, \ \ j = 1 \ldots n +``` + +##### Maximization + +###### Primal + +```math +\begin{align} +& \max_{x_1, \dots, x_n} & \sum_{j=1}^n a_j^T x_j + d^T z + b_0 +\\ +& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + D_i z + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\\ +& & x_j & \in \mathcal{V}_j & j = 1 \ldots n +\end{align} +``` + +###### Dual + +```math +\begin{align} +& \min_{y_1, \ldots, y_m} & \sum_{i=1}^m (D_i z + b_i)^T y_i + d^T z + b_0 +\\ +& \;\;\text{s.t.} & - \sum_{i=1}^m A_{ij}^T y_i - a_j & \in \mathcal{V}_j^* & j = 1 \ldots n +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +###### KKT + + +* Primal Feasibility: + +```math +\sum_{j=1}^n A_{ij} x_j + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ +x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ +u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n +``` + +* Complementary slackness: + +```math +y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i + D_i z) = 0, \ \ i = 1 \ldots m \\ +u_j^T x_j = 0, \ \ j = 1 \ldots n +``` + +* Stationarity: + +```math +- \sum_{i=1}^m A_{ij}^T y_i - a_j = u_j, \ \ j = 1 \ldots n +``` + +### Quadratic problems + +Optimization problems with conic constraints and quadratic objective are straightforward extensions to the conic problems with linear constraints usually defined in MOI. More information [here](http://www.seas.ucla.edu/~vandenbe/publications/coneprog.pdf). + +#### MOI standard form + +##### Minimization + +###### Primal + +```math +\begin{align} +& \min_{x \in \mathbb{R}^n} & \frac{1}{2} x^T P x + a_0^T x + b_0 +\\ +& \;\;\text{s.t.} & A_i x + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\end{align} +``` + +Where `P` is a positive semidefinite matrix. + +###### Dual + +A compact formulation for the dual problem requires pseudo-inverses, however, we can add an extra slack variable `w` to the dual problem and obtain the following dual problem: + +```math +\begin{align} +& \max_{y_1, \ldots, y_m} & - \frac{1}{2} w^T P w - \sum_{i=1}^m b_i^T y_i + b_0 +\\ +& \;\;\text{s.t.} & a_0 - \sum_{i=1}^m A_i^T y_i + P w & = 0 +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +note that, in the constraint, the sign in front of the `P` matrix can be changed because `w` is free and the only other term depending in `w` is quadratic and symmetric. +The sign choice is interesting to keep the dual problem closer to the KKT conditions that reads as follows. + +###### KKT + +* Primal Feasibility: + +```math +A_i x + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m +``` + +* Complementary slackness: + +```math +y_i^T (A_i x + b_i) = 0, \ \ i = 1 \ldots m +``` + +* Stationarity: + +```math +P x + a_0 - \sum_{i=1}^m A_i^T y_i = 0 +``` + +##### Maximization + +###### Primal + +```math +\begin{align} +& \max_{x \in \mathbb{R}^n} & \frac{1}{2} x^T N x + a_0^T x + b_0 +\\ +& \;\;\text{s.t.} & A_i x + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\end{align} +``` + +Where `N` is negative semidefinite, i.e., `-N` is a positive semidefinite matrix. + +###### Dual + +Just like in the minimization case we can add an extra slack variable `w` to +the dual problem and obtain the following dual problem: + +```math +\begin{align} +& \min_{y_1, \ldots, y_m} & - \frac{1}{2} w^T N w + \sum_{i=1}^m b_i^T y_i + b_0 +\\ +& \;\;\text{s.t.} & - a_0 - \sum_{i=1}^m A_i^T y_i - N w & = 0 +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +note that, in the constraint, the sign in front of the `N` matrix can be changed because `w` is free and the only other term depending in `w` is quadratic and symmetric. +The sign choice is interesting to keep the dual problem closer to the KKT conditions that reads as follows. + +###### KKT + +* Primal Feasibility: + +```math +A_i x + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m +``` + +* Complementary slackness: + +```math +y_i^T (A_i x + b_i) = 0, \ \ i = 1 \ldots m +``` + +* Stationarity: + +```math +- N x - a_0 - \sum_{i=1}^m A_i^T y_i = 0 +``` + +#### MOI compact form + +##### Minimization + +###### Primal + +```math +\begin{align} +& \min_{x_1, \dots, x_n} & \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n x_j^T P_{j,k} x_k + \sum_{j=1}^n a_j^T x_j + b_0 +\\ +& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\\ +& & x_j & \in \mathcal{V}_j & j = 1 \ldots n +\end{align} +``` + +###### Dual + +```math +\begin{align} +& \max_{y_1, \ldots, y_m, w_1, \ldots, w_n} & - \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n w_j^T P_{j,k} w_k - \sum_{i=1}^m b_i^T y_i + b_0 +\\ +& \;\;\text{s.t.} & \sum_{k=1}^n P_{j,k} w_k - \sum_{i=1}^m A_{ij}^T y_i + a_j & \in \mathcal{V}_j^* & j = 1 \ldots n +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +###### KKT + + +* Primal Feasibility: + +```math +\sum_{j=1}^n A_{ij} x_j + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ +x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ +u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n +``` + +* Complementary slackness: + +```math +y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i) = 0, \ \ i = 1 \ldots m \\ +u_j^T x_j = 0, \ \ j = 1 \ldots n +``` + +* Stationarity: + +```math +\sum_{k=1}^n P_{j,k} x_k - \sum_{i=1}^m A_{ij}^T y_i + a_j = u_j, \ \ j = 1 \ldots n +``` + +##### Maximization + +###### Primal + +```math +\begin{align} +& \max_{x_1, \dots, x_n} & \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n x_j^T N_{j,k} x_k + \sum_{j=1}^n a_j^T x_j + b_0 +\\ +& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\\ +& & x_j & \in \mathcal{V}_j & j = 1 \ldots n +\end{align} +``` + +###### Dual + +```math +\begin{align} +& \min_{y_1, \ldots, y_m, w_1, \ldots, w_n} & - \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n w_j^T N_{j,k} w_k + \sum_{i=1}^m b_i^T y_i + b_0 +\\ +& \;\;\text{s.t.} & - \sum_{k=1}^n N_{j,k} w_k - \sum_{i=1}^m A_{ij}^T y_i - a_j & \in \mathcal{V}_j^* & j = 1 \ldots n +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +###### KKT + + +* Primal Feasibility: + +```math +\sum_{j=1}^n A_{ij} x_j + b_i \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ +x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ +u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n +``` + +* Complementary slackness: + +```math +y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i) = 0, \ \ i = 1 \ldots m \\ +u_j^T x_j = 0, \ \ j = 1 \ldots n +``` + +* Stationarity: + +```math +- \sum_{k=1}^n N_{j,k} x_k - \sum_{i=1}^m A_{ij}^T y_i - a_j = u_j, \ \ j = 1 \ldots n +``` + +### Parametric quadratic problems + +Just like the conic linear problems, these quadratic programs can be parametric. + +#### MOI standard form + +##### Minimization + +###### Primal + +```math +\begin{align} +& \min_{x \in \mathbb{R}^n} & + \frac{1}{2} x^T P_1 x + x^T P_2 z + \frac{1}{2} z^T P_3 z +\\ +& & + a_0^T x + b_0 + d_0^T z \notag +\\ +& \;\;\text{s.t.} & A_i x + b_i + D_i z & \in \mathcal{C}_i & i = 1 \ldots m +\end{align} +``` + +###### Dual + +```math +\begin{align} +& \max_{y_1, \ldots, y_m} & - \frac{1}{2} w^T P_1 w + \frac{1}{2} z^T P_3 z +\\ +& & -\sum_{i=1}^m (b_i + D_i z)^T y_i + d_0^T z + b_0 \notag +\\ +& \;\;\text{s.t.} & a_0 + P_2 z - \sum_{i=1}^m A_i^T y_i + P_1 w & = 0 +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +###### KKT + + +* Primal Feasibility: + +```math +A_i x + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m +``` + +* Complementary slackness: + +```math +y_i^T (A_i x + b_i + D_i z) = 0, \ \ i = 1 \ldots m +``` + +* Stationarity: + +```math +P_1 x + P_2 z + a_0 - \sum_{i=1}^m A_i^T y_i = 0 +``` + +##### Maximization + +###### Primal + +```math +\begin{align} +& \max_{x \in \mathbb{R}^n} & + \frac{1}{2} x^T N_1 x + x^T N_2 z + \frac{1}{2} z^T N_3 z +\\ +& & + a_0^T x + b_0 + d_0^T z \notag +\\ +& \;\;\text{s.t.} & A_i x + b_i + D_i z & \in \mathcal{C}_i & i = 1 \ldots m +\end{align} +``` + +###### Dual + +```math +\begin{align} +& \min_{y_1, \ldots, y_m} & - \frac{1}{2} w^T N_1 w + \frac{1}{2} z^T N_3 z +\\ +& & +\sum_{i=1}^m (b_i + D_i z)^T y_i + d_0^T z + b_0 \notag +\\ +& \;\;\text{s.t.} & - a_0 - N_2 z - \sum_{i=1}^m A_i^T y_i - N_1 w & = 0 +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +###### KKT + + +* Primal Feasibility: + +```math +A_i x + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m +``` + +* Complementary slackness: + +```math +y_i^T (A_i x + b_i + D_i z) = 0, \ \ i = 1 \ldots m +``` + +* Stationarity: + +```math +- N_1 x - N_2 z - a_0 - \sum_{i=1}^m A_i^T y_i = 0 +``` + + +#### MOI compact form + +##### Minimization + +###### Primal + +```math +\begin{align} +& \min_{x_1, \dots, x_n} & \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n x_j^T P_{j,k} x_k + \sum_{j=1}^n x_j^T P_{j,0} z \\ +& & + \frac{1}{2} z^T P_{0,0} z + \sum_{j=1}^n a_j^T x_j + d^T z + b_0 +\\ +& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + D_i z + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\\ +& & x_j & \in \mathcal{V}_j & j = 1 \ldots n +\end{align} +``` + +###### Dual + +```math +\begin{align} +& \max_{y_1, \ldots, y_m, w_1, \ldots, w_n} & - \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n w_j^T P_{j,k} w_k - \sum_{i=1}^m (D_i z + b_i)^T y_i\\ +& & + \frac{1}{2} z^T P_{0,0} z + d^T z + b_0 +\\ +& \;\;\text{s.t.} & \sum_{k=1}^n P_{j,k} w_k - \sum_{i=1}^m A_{ij}^T y_i + a_j + P_{j,0} z & \in \mathcal{V}_j^* & j = 1 \ldots n +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +###### KKT + + +* Primal Feasibility: + +```math +\sum_{j=1}^n A_{ij} x_j + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ +x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ +u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n +``` + +* Complementary slackness: + +```math +y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i + D_i z) = 0, \ \ i = 1 \ldots m \\ +u_j^T x_j = 0, \ \ j = 1 \ldots n +``` + +* Stationarity: + +```math +\sum_{k=1}^n P_{j,k} x_k - \sum_{i=1}^m A_{ij}^T y_i + a_j + P_{j,0} z = u_j, \ \ j = 1 \ldots n +``` + +##### Maximization + +###### Primal + +```math +\begin{align} +& \max_{x_1, \dots, x_n} & \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n x_j^T N_{j,k} x_k + \sum_{j=1}^n x_j^T N_{j,0} z \\ +& & + \frac{1}{2} z^T N_{0,0} z + \sum_{j=1}^n a_j^T x_j + d^T z + b_0 +\\ +& \;\;\text{s.t.} & \sum_{j=1}^n A_{ij} x_j + D_i z + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\\ +& & x_j & \in \mathcal{V}_j & j = 1 \ldots n +\end{align} +``` + +###### Dual + +```math +\begin{align} +& \min_{y_1, \ldots, y_m, w_1, \ldots, w_n} & - \frac{1}{2} \sum_{k=1}^n\sum_{j=1}^n w_j^T N_{j,k} w_k + \sum_{i=1}^m (D_i z + b_i)^T y_i\\ +& & + \frac{1}{2} z^T N_{0,0} z + d^T z + b_0 +\\ +& \;\;\text{s.t.} & - \sum_{k=1}^n N_{j,k} w_k - \sum_{i=1}^m A_{ij}^T y_i - a_j - N_{j,0} z & \in \mathcal{V}_j^* & j = 1 \ldots n +\\ +& & y_i & \in \mathcal{C}_i^* & i = 1 \ldots m +\end{align} +``` + +###### KKT + + +* Primal Feasibility: + +```math +\sum_{j=1}^n A_{ij} x_j + b_i + D_i z \in \mathcal{C}_i , \ \ i = 1 \ldots m \\ +x_j \in \mathcal{V}_j , \ \ j = 1 \ldots n +``` + +* Dual Feasibility: + +```math +y_i \in \mathcal{C}_i^*, \ \ i = 1 \ldots m \\ +u_j \in \mathcal{V}_j^*, \ \ j = 1 \ldots n +``` + +* Complementary slackness: + +```math +y_i^T (\sum_{j=1}^n A_{ij} x_j + b_i + D_i z) = 0, \ \ i = 1 \ldots m \\ +u_j^T x_j = 0, \ \ j = 1 \ldots n +``` + +* Stationarity: + +```math +- \sum_{k=1}^n N_{j,k} x_k - \sum_{i=1}^m A_{ij}^T y_i - a_j - N_{j,0} z = u_j, \ \ j = 1 \ldots n +``` diff --git a/docs/src/reference.md b/docs/src/reference.md index efd7b5cc..27e093d5 100644 --- a/docs/src/reference.md +++ b/docs/src/reference.md @@ -1,10 +1,67 @@ -# Reference +```@meta +CurrentModule = Dualization +``` +# API Reference + +This page lists the public API of `Dualization`. + +!!! info + This page is an unstructured list of the Dualization API. For a more + structured overview, read the Manual or Tutorial parts of this + documentation. + +Load all of the public the API into the current scope with: +```julia +using Dualization +``` +Alternatively, load only the module with: +```julia +import Dualization +``` +and then prefix all calls with `Dualization.` to create `Dualization.`. + +## `dualize` +```@docs +dualize +``` + +## `dual_optimizer` +```@docs +dual_optimizer +``` + +## `DualOptimizer` +```@docs +DualOptimizer +``` + +## `DualNames` +```@docs +DualNames +``` + +## `Dualization.supported_constraints` ```@docs Dualization.supported_constraints +``` + +## `Dualization.supported_objective` +```@docs Dualization.supported_objective -Dualization.DualNames +``` + +## `Dualization.PrimalVariableData` +```@docs Dualization.PrimalVariableData +``` + +## `Dualization.PrimalConstraintData` +```@docs Dualization.PrimalConstraintData +``` + +## `Dualization.PrimalDualMap` +```@docs Dualization.PrimalDualMap -``` \ No newline at end of file +``` diff --git a/src/Dualization.jl b/src/Dualization.jl index 9d56396c..de273649 100644 --- a/src/Dualization.jl +++ b/src/Dualization.jl @@ -21,4 +21,9 @@ include("dual_equality_constraints.jl") include("dualize.jl") include("MOI_wrapper.jl") +export dualize +export dual_optimizer +export DualOptimizer +export DualNames + end # module diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index da4cc7a1..7517887a 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -3,8 +3,30 @@ # Use of this source code is governed by an MIT-style license that can be found # in the LICENSE.md file or at https://opensource.org/licenses/MIT. -export DualOptimizer, dual_optimizer +""" + dual_optimizer( + optimizer_constructor; + coefficient_type::Type{T} = Float64, + kwargs..., + ) where {T<:Number} + +A user-friendly constructor for [`DualOptimizer`](@ref) that can be passed +directly to the JuMP `Model` constructor. + +## Example +```julia +julia> using Dualization, JuMP, HiGHS + +julia> model = Model(dual_optimizer(HiGHS.Optimizer)) +A JuMP Model +Feasibility problem with: +Variables: 0 +Model mode: AUTOMATIC +CachingOptimizer state: EMPTY_OPTIMIZER +Solver name: Dual model with HiGHS attached +``` +""" function dual_optimizer( optimizer_constructor; coefficient_type::Type{T} = Float64, diff --git a/src/dual_names.jl b/src/dual_names.jl index 780de76e..af0cd7ff 100644 --- a/src/dual_names.jl +++ b/src/dual_names.jl @@ -3,8 +3,6 @@ # Use of this source code is governed by an MIT-style license that can be found # in the LICENSE.md file or at https://opensource.org/licenses/MIT. -export DualNames - """ DualNames diff --git a/src/dualize.jl b/src/dualize.jl index 843a9b26..f14a5db6 100644 --- a/src/dualize.jl +++ b/src/dualize.jl @@ -3,8 +3,6 @@ # Use of this source code is governed by an MIT-style license that can be found # in the LICENSE.md file or at https://opensource.org/licenses/MIT. -export dualize - """ dualize(args...; kwargs...) @@ -45,7 +43,7 @@ On each of these methods, the user can provide the following keyword arguments: added to the dual model. This is also useful for bi-level modelling, where the second level model is represented as a KKT in the upper level model. - * `assume_min_if_feasibility`: a boolean indicating if the objective function + * `assume_min_if_feasibility`: a boolean indicating if the objective function is of type `MOI.FEASIBILITY_SENSE` then the objective is treated as `MOI.MIN_SENSE`. Therefore, the dual will have a `MOI.MAX_SENSE` objective. This is set to false by default, to warn users about the outcome. From 34d1c7643ac9af182055ad4c366a84738679f584 Mon Sep 17 00:00:00 2001 From: odow Date: Tue, 3 Jun 2025 13:30:35 +1200 Subject: [PATCH 2/4] Update --- docs/Project.toml | 2 + docs/src/examples.md | 88 ++++++++++++++++++-------------------------- 2 files changed, 37 insertions(+), 53 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index 351c741c..fe899df8 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,6 +1,8 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" Dualization = "191a621a-6537-11e9-281d-650236a99e60" +ECOS = "e2685f51-7e38-5353-a97d-a921fd2c8199" +JuMP = "4076af6c-e467-56ae-b986-b466b2749572" [compat] Documenter = "1" diff --git a/docs/src/examples.md b/docs/src/examples.md index feff4d66..8841c20f 100644 --- a/docs/src/examples.md +++ b/docs/src/examples.md @@ -8,18 +8,15 @@ Let us dualize the following Second Order Cone program ```math \begin{align} - & \min_{x, y, z} & y + z & - \\ - & \;\;\text{s.t.} - &x & = 1\\ - && x & = 1\\ - &&x & \geq ||(y,z)||_2\\ + & \min_{x, y, z} & y + z & \\ + & \;\;\text{s.t.} & x & = 1 \\ + & &x & \geq ||(y, z)||_2 \\ \end{align} ``` -The corresponding code in JuMP is +The corresponding code in JuMP is: -```julia +```@repl dualize_model using JuMP, Dualization model = Model() @variable(model, x) @@ -31,27 +28,18 @@ model = Model() ``` You can dualize the model by doing -```julia +```@repl dualize_model dual_model = dualize(model) +print(dual_model) ``` -And you should get the model -```math -\begin{align} - & \max_{eqcon, soccon} & eqcon & - \\ - & \;\;\text{s.t.} - &eqcon + soccon_1 & = 0\\ - && soccon_2 & = 1\\ - && soccon_3 & = 1\\ - &&soccon_1 & \geq ||(soccon_2,soccon_3)||_2\\ -\end{align} -``` +Note that if you declare the model with an optimizer attached you will lose the +optimizer during the dualization. -Note that if you declare the model with an optimizer attached you will lose the optimizer during the dualization. -To dualize the model and attach the optimizer to the dual model you should do `dualize(dual_model, SolverName.Optimizer)` +To dualize the model and attach the optimizer to the dual model you should do +`dualize(dual_model, SolverName.Optimizer)` -```julia +```@repl using JuMP, Dualization, ECOS model = Model(ECOS.Optimizer) @variable(model, x) @@ -60,19 +48,22 @@ model = Model(ECOS.Optimizer) @constraint(model, soccon, [x; y; z] in SecondOrderCone()) @constraint(model, eqcon, x == 1) @objective(model, Min, y + z) - dual_model = dualize(model, ECOS.Optimizer) ``` ## Naming the dual variables and dual constraints -You can provide prefixes for the name of the variables and the name of the constraints using the a `DualNames` variable. -Every time you use the dualize function you can provide a `DualNames` as keyword argument. Consider the following example. +You can provide prefixes for the name of the variables and the name of the +constraints using the a `DualNames` variable. -You want to dualize this JuMP problem and add a prefix to the name of each constraint to be more clear on what the variables -represent. For instance you want to put `"dual"` before the name of the constraint. +Every time you use the dualize function you can provide a `DualNames` as keyword +argument. Consider the following example. -```julia +You want to dualize this JuMP problem and add a prefix to the name of each +constraint to be more clear on what the variables represent. For instance you +want to put `"dual"` before the name of the constraint. + +```@repl using JuMP, Dualization model = Model() @variable(model, x) @@ -81,36 +72,18 @@ model = Model() @constraint(model, soccon, [x; y; z] in SecondOrderCone()) @constraint(model, eqcon, x == 1) @objective(model, Min, y + z) - -# The first field of DualNames is the prefix of the dual variables -# and the second field is the prefix of the dual constraint dual_model = dualize(model; dual_names = DualNames("dual", "")) +print(dual_model) ``` -The dual_model will be registered as - -```math -\begin{align} - & \max_{dualeqcon, dualsoccon} & dualeqcon & - \\ - & \;\;\text{s.t.} - &dualeqcon + dualsoccon_1 & = 0\\ - && dualsoccon_2 & = 1\\ - && dualsoccon_3 & = 1\\ - &&dualsoccon_1 & \geq ||(dualsoccon_2, dualsoccon_3)||_2\\ -\end{align} -``` - - ## Solving a problem using its dual formulation Depending on the solver and on the type of formulation, solving the dual problem could be faster than solving the primal. To solve the problem via its dual formulation can be done using the `DualOptimizer`. -```julia +Solving a problem the standard way: +```@repl using JuMP, Dualization, ECOS - -# Solving a problem the standard way model = Model(ECOS.Optimizer) @variable(model, x) @variable(model, y) @@ -118,8 +91,12 @@ model = Model(ECOS.Optimizer) @constraint(model, soccon, [x; y; z] in SecondOrderCone()) @constraint(model, eqcon, x == 1) @objective(model, Min, y + z) +optimize!(model) +``` -# Solving a problem by providing its dual representation +Solving a problem by providing its dual representation: +```@repl +using JuMP, Dualization, ECOS model = Model(dual_optimizer(ECOS.Optimizer)) @variable(model, x) @variable(model, y) @@ -127,8 +104,12 @@ model = Model(dual_optimizer(ECOS.Optimizer)) @constraint(model, soccon, [x; y; z] in SecondOrderCone()) @constraint(model, eqcon, x == 1) @objective(model, Min, y + z) +optimize!(model) +``` -# You can pass arguments to the solver by attaching them to the solver constructor. +You can pass arguments to the solver by attaching them to the solver constructor: +```@repl +using JuMP, Dualization, ECOS model = Model(dual_optimizer(optimizer_with_attributes(ECOS.Optimizer, "maxit" => 5))) @variable(model, x) @variable(model, y) @@ -136,4 +117,5 @@ model = Model(dual_optimizer(optimizer_with_attributes(ECOS.Optimizer, "maxit" = @constraint(model, soccon, [x; y; z] in SecondOrderCone()) @constraint(model, eqcon, x == 1) @objective(model, Min, y + z) +optimize!(model) ``` From 382add47e60af4707f67162fbce81bc7ff8ac1cc Mon Sep 17 00:00:00 2001 From: odow Date: Tue, 3 Jun 2025 14:46:02 +1200 Subject: [PATCH 3/4] Update --- docs/make.jl | 1 - docs/src/examples.md | 121 ---------------------------------- docs/src/manual.md | 152 ++++++++++++++++++++++++++++++------------- 3 files changed, 107 insertions(+), 167 deletions(-) delete mode 100644 docs/src/examples.md diff --git a/docs/make.jl b/docs/make.jl index ad6bc625..be10b7b4 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -18,7 +18,6 @@ Documenter.makedocs( "Home" => "index.md", "manual.md", "mathematical_background.md", - "examples.md", "reference.md", ], modules = [Dualization], diff --git a/docs/src/examples.md b/docs/src/examples.md deleted file mode 100644 index 8841c20f..00000000 --- a/docs/src/examples.md +++ /dev/null @@ -1,121 +0,0 @@ -# Examples - -Here we discuss some useful examples of usage. - -## Dualize a JuMP model - -Let us dualize the following Second Order Cone program - -```math -\begin{align} - & \min_{x, y, z} & y + z & \\ - & \;\;\text{s.t.} & x & = 1 \\ - & &x & \geq ||(y, z)||_2 \\ -\end{align} -``` - -The corresponding code in JuMP is: - -```@repl dualize_model -using JuMP, Dualization -model = Model() -@variable(model, x) -@variable(model, y) -@variable(model, z) -@constraint(model, soccon, [x; y; z] in SecondOrderCone()) -@constraint(model, eqcon, x == 1) -@objective(model, Min, y + z) -``` -You can dualize the model by doing - -```@repl dualize_model -dual_model = dualize(model) -print(dual_model) -``` - -Note that if you declare the model with an optimizer attached you will lose the -optimizer during the dualization. - -To dualize the model and attach the optimizer to the dual model you should do -`dualize(dual_model, SolverName.Optimizer)` - -```@repl -using JuMP, Dualization, ECOS -model = Model(ECOS.Optimizer) -@variable(model, x) -@variable(model, y) -@variable(model, z) -@constraint(model, soccon, [x; y; z] in SecondOrderCone()) -@constraint(model, eqcon, x == 1) -@objective(model, Min, y + z) -dual_model = dualize(model, ECOS.Optimizer) -``` - -## Naming the dual variables and dual constraints - -You can provide prefixes for the name of the variables and the name of the -constraints using the a `DualNames` variable. - -Every time you use the dualize function you can provide a `DualNames` as keyword -argument. Consider the following example. - -You want to dualize this JuMP problem and add a prefix to the name of each -constraint to be more clear on what the variables represent. For instance you -want to put `"dual"` before the name of the constraint. - -```@repl -using JuMP, Dualization -model = Model() -@variable(model, x) -@variable(model, y) -@variable(model, z) -@constraint(model, soccon, [x; y; z] in SecondOrderCone()) -@constraint(model, eqcon, x == 1) -@objective(model, Min, y + z) -dual_model = dualize(model; dual_names = DualNames("dual", "")) -print(dual_model) -``` - -## Solving a problem using its dual formulation - -Depending on the solver and on the type of formulation, solving the dual problem could be faster than solving the primal. -To solve the problem via its dual formulation can be done using the `DualOptimizer`. - -Solving a problem the standard way: -```@repl -using JuMP, Dualization, ECOS -model = Model(ECOS.Optimizer) -@variable(model, x) -@variable(model, y) -@variable(model, z) -@constraint(model, soccon, [x; y; z] in SecondOrderCone()) -@constraint(model, eqcon, x == 1) -@objective(model, Min, y + z) -optimize!(model) -``` - -Solving a problem by providing its dual representation: -```@repl -using JuMP, Dualization, ECOS -model = Model(dual_optimizer(ECOS.Optimizer)) -@variable(model, x) -@variable(model, y) -@variable(model, z) -@constraint(model, soccon, [x; y; z] in SecondOrderCone()) -@constraint(model, eqcon, x == 1) -@objective(model, Min, y + z) -optimize!(model) -``` - -You can pass arguments to the solver by attaching them to the solver constructor: -```@repl -using JuMP, Dualization, ECOS -model = Model(dual_optimizer(optimizer_with_attributes(ECOS.Optimizer, "maxit" => 5))) -@variable(model, x) -@variable(model, y) -@variable(model, z) -@constraint(model, soccon, [x; y; z] in SecondOrderCone()) -@constraint(model, eqcon, x == 1) -@objective(model, Min, y + z) -optimize!(model) -``` diff --git a/docs/src/manual.md b/docs/src/manual.md index 98947191..93e10657 100644 --- a/docs/src/manual.md +++ b/docs/src/manual.md @@ -1,5 +1,112 @@ # Manual +## Dualize a JuMP model + +Use [`dualize`](@ref) to formulat the dual of a JuMP model. + +For example, consider this problem: + +```@repl dualize_model +using JuMP, Dualization +begin + model = Model() + @variable(model, x) + @variable(model, y >= 0) + @variable(model, z) + @constraint(model, soccon, [1.0 * x + 2.0, y, z] in SecondOrderCone()) + @constraint(model, eqcon, x == 1) + @constraint(model, con_le, x + y >= 1) + @objective(model, Min, y + z) + print(model) +end +``` +You can dualize the model by doing + +```@repl dualize_model +dual_model = dualize(model) +print(dual_model) +``` + +Note that if you declare the model with an optimizer attached you will lose the +optimizer during the dualization. To dualize the model and attach the optimizer +to the dual model you should do `dualize(model, optimizer)` + +```@repl dualize_model +using ECOS +dual_model = dualize(model, ECOS.Optimizer) +``` + +## Name the dual variables and dual constraints + +Provide prefixes for the names of the variables and constraints using +[`DualNames`](@ref). + +```@repl dualize_model +dual_model = dualize(model; dual_names = DualNames("dual_var_", "dual_con_")) +print(dual_model) +``` + +## Solve a problem using its dual formulation + +Wrap an optimizer with [`dual_optimizer`](@ref) to solve the dual of the problem +instead of the primal: +```@repl +using JuMP, Dualization, ECOS +model = Model(dual_optimizer(ECOS.Optimizer)) +@variable(model, x) +@variable(model, y) +@variable(model, z) +@constraint(model, soccon, [x; y; z] in SecondOrderCone()) +@constraint(model, eqcon, x == 1) +@objective(model, Min, y + z) +optimize!(model) +``` + +Pass arguments to the solver by attaching them to the solver constructor: +```@repl +using JuMP, Dualization, ECOS +model = Model(dual_optimizer(optimizer_with_attributes(ECOS.Optimizer, "maxit" => 5))) +``` +or by using `JuMP.set_attribute`: +```@repl +using JuMP, Dualization, ECOS +model = Model(dual_optimizer(ECOS.Optimizer)) +set_attribute(model, "maxit", 5) +``` + +## The benefit of solving the dual formulation + +Solving an optimization problem via its dual representation can be useful +because some conic solvers assume the model is in the standard form and others +use the geometric form. + +The geometric conic form has affine expressions in cones: + +```math +\begin{align} +& \min_{x \in \mathbb{R}^n} & c^T x +\\ +& \;\;\text{s.t.} & A_i x + b_i & \in \mathcal{C}_i & i = 1 \ldots m +\end{align} +``` + +The standard form has variables in cones: + +```math +\begin{align} +& \min_{x \in \mathbb{R}^n} & c^T x +\\ +& \;\;\text{s.t.} & A x + s & = b +\\ +& & s & \in \mathcal{C} +\end{align} +``` + +Solvers which use the geometric conic form include CDCS, SCS, ECOS, and SeDuMi. +Solvers which use the standard conic form include SDPT3, SDPNAL, CSDP, and SDPA. +Mosek v10 supports both affine constraints in cones and variables in cones, +hence both the standard and geometric form at the same time. + ## Supported problem types Dualization.jl works only for optimization models that can be written in conic @@ -35,51 +142,6 @@ Note that some of MOI constraints can be bridged, see [Bridges](http://jump.dev/ | `MOI.ScalarAffineFunction` | | `MOI.ScalarQuadraticFunction` | -## Dualize a model - -## DualOptimizer - -You can solve a primal problem by using its dual formulation using the `DualOptimizer`. - -Solving an optimization problem via its dual representation can be useful because some conic solvers assume the model is in the standard form and others use the geometric form. - -Geometric form has affine expressions in cones - -```math -\begin{align} -& \min_{x \in \mathbb{R}^n} & c^T x -\\ -& \;\;\text{s.t.} & A_i x + b_i & \in \mathcal{C}_i & i = 1 \ldots m -\end{align} -``` - -Standard form has variables in cones - -```math -\begin{align} -& \min_{x \in \mathbb{R}^n} & c^T x -\\ -& \;\;\text{s.t.} & A x + s & = b -\\ -& & s & \in \mathcal{C} -\end{align} -``` - -| Standard form | Geometric form | -|:-------:|:-------:| -| SDPT3 | CDCS | -| SDPNAL | SCS | -| CSDP | ECOS | -| SDPA | SeDuMi | -| Mosek v9 | - -!!! note - Mosek v10 now supports both affine constraints in cones and variables in - cones hence both the standard and geometric form at the same time. - -!!! note - MOI standard form is the Geometric form and not the "textbook" Standard form. - ## Adding new sets Dualization.jl can automatically dualize models with custom sets. From 5444b52d4c1445e573df349f1d7d31e11cf45e76 Mon Sep 17 00:00:00 2001 From: odow Date: Tue, 3 Jun 2025 15:55:13 +1200 Subject: [PATCH 4/4] Update --- docs/src/manual.md | 174 ++++++++++++++---------------------------- docs/src/reference.md | 5 ++ src/dual_names.jl | 31 +++++++- src/supported.jl | 5 ++ 4 files changed, 96 insertions(+), 119 deletions(-) diff --git a/docs/src/manual.md b/docs/src/manual.md index 93e10657..38f942e7 100644 --- a/docs/src/manual.md +++ b/docs/src/manual.md @@ -2,7 +2,7 @@ ## Dualize a JuMP model -Use [`dualize`](@ref) to formulat the dual of a JuMP model. +Use [`dualize`](@ref) to formulate the dual of a JuMP model. For example, consider this problem: @@ -17,25 +17,12 @@ begin @constraint(model, eqcon, x == 1) @constraint(model, con_le, x + y >= 1) @objective(model, Min, y + z) - print(model) -end -``` -You can dualize the model by doing - -```@repl dualize_model +end; +print(model) dual_model = dualize(model) print(dual_model) ``` -Note that if you declare the model with an optimizer attached you will lose the -optimizer during the dualization. To dualize the model and attach the optimizer -to the dual model you should do `dualize(model, optimizer)` - -```@repl dualize_model -using ECOS -dual_model = dualize(model, ECOS.Optimizer) -``` - ## Name the dual variables and dual constraints Provide prefixes for the names of the variables and constraints using @@ -46,6 +33,17 @@ dual_model = dualize(model; dual_names = DualNames("dual_var_", "dual_con_")) print(dual_model) ``` +## Pass a new optimizer + +If the primal model has an optimizer attached you will lose the optimizer during +the dualization. To dualize the model and attach the optimizer to the dual model +you should do `dualize(model, optimizer)`: + +```@repl dualize_model +import ECOS +dual_model = dualize(model, ECOS.Optimizer) +``` + ## Solve a problem using its dual formulation Wrap an optimizer with [`dual_optimizer`](@ref) to solve the dual of the problem @@ -53,13 +51,12 @@ instead of the primal: ```@repl using JuMP, Dualization, ECOS model = Model(dual_optimizer(ECOS.Optimizer)) -@variable(model, x) -@variable(model, y) -@variable(model, z) -@constraint(model, soccon, [x; y; z] in SecondOrderCone()) -@constraint(model, eqcon, x == 1) -@objective(model, Min, y + z) -optimize!(model) +``` +You can also set the optimizer after the model is created: +```@repl +using JuMP, Dualization, ECOS +model = Model() +set_optimizer(model, dual_optimizer(ECOS.Optimizer)) ``` Pass arguments to the solver by attaching them to the solver constructor: @@ -142,119 +139,66 @@ Note that some of MOI constraints can be bridged, see [Bridges](http://jump.dev/ | `MOI.ScalarAffineFunction` | | `MOI.ScalarQuadraticFunction` | -## Adding new sets +## Advanced: add support for new sets Dualization.jl can automatically dualize models with custom sets. -To do this, the user needs to define the set and its dual set and provide the functions: -* `supported_constraint` -* `dual_set` +To do this, the user needs to define the set and its dual set and provide the +functions: -If the custom set has some special scalar product (see the [link](https://jump.dev/MathOptInterface.jl/stable/apireference/#MathOptInterface.AbstractSymmetricMatrixSetTriangle)), the user also needs -to provide a `set_dot` function. +* [`Dualization.supported_constraint`](@ref) +* `MathOptInterface.dual_set` -For example, let us define a fake cone and its dual, the fake dual cone. We will write a JuMP model -with the fake cone and dualize it. +If the custom set has some special scalar product (see the [link](https://jump.dev/MathOptInterface.jl/stable/apireference/#MathOptInterface.AbstractSymmetricMatrixSetTriangle)), +the user also needs to provide the `MathOptInterface.Utilities.set_dot` function. -```julia -using Dualization, JuMP, MathOptInterface, LinearAlgebra +For example, let us define a fake cone and its dual, the fake dual cone. We will +write a JuMP model with the fake cone and dualize it. -# Rename MathOptInterface to simplify the code -const MOI = MathOptInterface - -# Define the custom cone and its dual +```@repl repl_example_new_set +using Dualization, JuMP struct FakeCone <: MOI.AbstractVectorSet dimension::Int end - struct FakeDualCone <: MOI.AbstractVectorSet dimension::Int end - -# Define a model with your FakeCone -model = Model() -@variable(model, x[1:3]) -@constraint(model, con, x in FakeCone(3)) # Note that the constraint name is "con" +model = Model(); +@variable(model, x[1:3] >= 0) +@constraint(model, con, 1.0 * x in FakeCone(3)) @objective(model, Min, sum(x)) -``` -The resulting JuMP model is - -```math -\begin{align} - & \min_{x} & x_1 + x_2 + x_3 & - \\ - & \;\;\text{s.t.} - &x \in FakeCone(3)\\ -\end{align} +print(model) ``` Now in order to dualize we must overload the methods as described above. -```julia -# Overload the methods dual_set and supported_constraints -Dualization.dual_set(s::FakeCone) = FakeDualCone(MOI.dimension(s)) -Dualization.supported_constraint(::Type{MOI.VectorOfVariables}, ::Type{<:FakeCone}) = true - -# If your set has some specific scalar product you also need to define a new set_dot function -# Our FakeCone has this weird scalar product -MOI.Utilities.set_dot(x::Vector, y::Vector, set::FakeCone) = 2dot(x, y) - -# Dualize the model -dual_model = dualize(model) -``` - -The resulting dual model is - -```math -\begin{align} - & \max_{con} & 0 & - \\ - & \;\;\text{s.t.} - &2con_1 & = 1\\ - &&2con_2 & = 1\\ - &&2con_3 & = 1\\ - && con & \in FakeDualCone(3)\\ -\end{align} -``` - -If the model has constraints that are `MOI.VectorAffineFunction` - -```julia -model = Model() -@variable(model, x[1:3]) -@constraint(model, con, x + 3 in FakeCone(3)) -@objective(model, Min, sum(x)) +```@repl repl_example_new_set +MOI.dual_set(s::FakeCone) = FakeDualCone(MOI.dimension(s)) +function Dualization.supported_constraint( + ::Type{MOI.VectorOfVariables}, + ::Type{FakeCone}, +) + return true +end +function Dualization.supported_constraint( + ::Type{<:MOI.VectorAffineFunction}, + ::Type{FakeCone}, +) + return true +end ``` -```math -\begin{align} - & \min_{x} & x_1 + x_2 + x_3 & - \\ - & \;\;\text{s.t.} - &[x_1 + 3, x_2 + 3, x_3 + 3] & \in FakeCone(3)\\ -\end{align} +If your set has some specific scalar product you also need to define a new +`set_dot` function. Assume that our FakeCone has this weird scalar product: +```@repl repl_example_new_set +import LinearAlgebra +function MOI.Utilities.set_dot(x::Vector, y::Vector, ::FakeCone) + return 2 * LinearAlgebra.dot(x, y) +end ``` -the user only needs to extend the `supported_constraints` function. - -```julia -# Overload the supported_constraints for VectorAffineFunction -Dualization.supported_constraint(::Type{<:MOI.VectorAffineFunction}, ::Type{<:FakeCone}) = true - -# Dualize the model +Dualize the model +```@repl repl_example_new_set dual_model = dualize(model) -``` - -The resulting dual model is - -```math -\begin{align} - & \max_{con} & - 3con_1& - 3con_2 - 3con_3 - \\ - & \;\;\text{s.t.} - &2con_1 & = 1\\ - &&2con_2 & = 1\\ - &&2con_3 & = 1\\ - && con & \in FakeDualCone(3)\\ -\end{align} +print(dual_model) ``` diff --git a/docs/src/reference.md b/docs/src/reference.md index 27e093d5..9938cb8c 100644 --- a/docs/src/reference.md +++ b/docs/src/reference.md @@ -41,6 +41,11 @@ DualOptimizer DualNames ``` +## `Dualization.supported_constraint` +```@docs +Dualization.supported_constraint +``` + ## `Dualization.supported_constraints` ```@docs Dualization.supported_constraints diff --git a/src/dual_names.jl b/src/dual_names.jl index af0cd7ff..153f2689 100644 --- a/src/dual_names.jl +++ b/src/dual_names.jl @@ -4,12 +4,35 @@ # in the LICENSE.md file or at https://opensource.org/licenses/MIT. """ - DualNames + DualNames(dual_variable_name_prefix, dual_constraint_name_prefix) -DualNames is a struct to pass the prefix of dual variables and dual constraints -names. +A struct to pass the prefix of dual variables and dual constraints names to +the `dual_names` keyword argument of [`dualize`](@ref). -See more on naming the variables. +## Example + +```jldoctest +julia> using JuMP, Dualization + +julia> begin + model = Model() + @variable(model, x) + @constraint(model, c, x >= 1) + @objective(model, Min, x) + dual_model = dualize(model; dual_names = DualNames("dual_var_", "dual_con_")) + end; + +julia> print(model) +Min x +Subject to + c : x ≥ 1 + +julia> print(dual_model) +Max dual_var_c +Subject to + dual_con_x : dual_var_c = 1 + dual_var_c ≥ 0 +``` """ mutable struct DualNames dual_variable_name_prefix::String diff --git a/src/supported.jl b/src/supported.jl index f87ca006..e55781d1 100644 --- a/src/supported.jl +++ b/src/supported.jl @@ -26,6 +26,11 @@ function supported_constraints(con_types::Vector{Tuple{Type,Type}}) return true end +""" + supported_constraint(::Type{F}, ::Type{S}) + +Return `true` if Dualization supports dualizing the constraint type `F`-in-`S`. +""" supported_constraint(::Type, ::Type) = false function supported_constraint(