Manual

Manual

Note

This package only works for optimization models that can be written in the conic-form.

Conic 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. For conic-form minimization problems, the primal is:

\[\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:

\[\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 conic-form maximization problems, the primal is:

\[\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:

\[\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}\]

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$.

For the special case of minimization LPs, the MOI primal form can be stated as

\[\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:

\[\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:

\[\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:

\[\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}\]

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 FunctionMOI Set
SingleVariableGreaterThan
SingleVariableLessThan
SingleVariableEqualTo
ScalarAffineFunctionGreaterThan
ScalarAffineFunctionLessThan
ScalarAffineFunctionEqualTo
VectorOfVariablesNonnegatives
VectorOfVariablesNonpositives
VectorOfVariablesZeros
VectorOfVariablesSecondOrderCone
VectorOfVariablesRotatedSecondOrderCone
VectorOfVariablesPositiveSemidefiniteConeTriangle
VectorOfVariablesExponentialCone
VectorOfVariablesDualExponentialCone
VectorOfVariablesPowerCone
VectorOfVariablesDualPowerCone
VectorAffineFunctionNonnegatives
VectorAffineFunctionNonpositives
VectorAffineFunctionZeros
VectorAffineFunctionSecondOrderCone
VectorAffineFunctionRotatedSecondOrderCone
VectorAffineFunctionPositiveSemidefiniteConeTriangle
VectorAffineFunctionExponentialCone
VectorAffineFunctionDualExponentialCone
VectorAffineFunctionPowerCone
VectorAffineFunctionDualPowerCone

Note that some of MOI constraints can be bridged, see Bridges, to constraints in this list.

Supported objective functions

MOI Function
SingleVariable
ScalarAffineFunction

Dualize a model

Dualization.dualize โ€” Function.
dualize(args...; kwargs...)

The dualize function works in three different ways. The user can provide:

  • A MathOptInterface.ModelLike

The function will return a DualProblem struct that has the dualized model and PrimalDualMap{Float64} for users to identify the links between primal and dual model.

  • A MathOptInterface.ModelLike and a DualProblem{T}

  • A JuMP.Model

The function will return a JuMP model with the dual representation of the problem.

  • A JuMP.Model and an optimizer factory

The function will return a JuMP model with the dual representation of the problem with the OptimizerFactory attached. The OptimizerFactory is the solver and its key arguments that users provide in JuMP models, i.e. with_optimizer(GLPK.Optimizer).

On each of these methods, the user can provide the keyword argument dual_names. dual_names must be a DualNames struct. It allows users to set more intuitive names for the dual variables and dual constraints created.

source

DualOptimizer

You can solve a primal problem by using its dual formulation using the DualOptimizer.

DualOptimizer(dual_optimizer::OT) where {OT <: MOI.ModelLike}

The DualOptimizer finds the solution for a problem solving its dual representation. It builds the dual model and solve it using the dual_optimizer as solver.

The user can define the model providing the DualOptimizer and the solver of its choice

julia> using Dualization, JuMP, GLPK

julia> model = Model(with_optimizer(DualOptimizer, GLPK.Optimizer()))
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: EMPTY_OPTIMIZER
Solver name: Dual model with GLPK attached
source

Adding 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:

If the custom set has some special scalar product (see the link), the user also needs to provide a set_dot function.

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.

using Dualization, JuMP, MathOptInterface, LinearAlgebra

# Rename MathOptInterface to simplify the code
const MOI = MathOptInterface

# Define the custom cone and its dual
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"
@objective(model, Min, sum(x))

The resulting JuMP model is

\[\begin{align} & \min_{x} & x_1 + x_2 + x_3 & \\ & \;\;\text{s.t.} &x \in FakeCone(3)\\ \end{align}\]

Now in order to dualize we must overload the methods as described above.

# 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

\[\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

model = Model()
@variable(model, x[1:3])
@constraint(model, con, x + 3 in FakeCone(3))
@objective(model, Min, sum(x))
\[\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}\]

the user only needs to extend the supported_constraints function.

# Overload the supported_constraints for VectorAffineFunction
Dualization.supported_constraint(::Type{<:MOI.VectorAffineFunction}, ::Type{<:FakeCone}) = true

# Dualize the model
dual_model = dualize(model)

The resulting dual model is

\[\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}\]