7.4 Conic Exponential Optimization

Conic optimization is a generalization of linear optimization, allowing constraints of the type

\[x^t \in \K_t,\]

where \(x^t\) is a subset of the problem variables and \(\K_t\) is a convex cone. Since the set \(\real^n\) of real numbers is also a convex cone, we can simply write a compound conic constraint \(x\in \K\) where \(\K=\K_1\times\cdots\times\K_l\) is a product of smaller cones and \(x\) is the full problem variable.

MOSEK can solve conic optimization problems of the form

\[\begin{split}\begin{array}{lccccl} \mbox{minimize} & & & c^T x + c^f & & \\ \mbox{subject to} & l^c & \leq & A x & \leq & u^c, \\ & l^x & \leq & x & \leq & u^x, \\ & & & x \in \K, & & \end{array}\end{split}\]

where the domain restriction, \(x \in \K\), implies that all variables are partitioned into convex cones

\[x = (x^0, x^1, \ldots , x^{p-1}),\quad \mbox{with } x^t \in \K_t \subseteq \real^{n_t}.\]

In this tutorial we describe how to use the primal exponential cone defined as:

\[\EXP = \left\lbrace x \in \real^3: x_0 \geq x_1 \exp(x_2/x_1),\ x_0,x_1\geq 0 \right\rbrace.\]

MOSEK also supports the dual exponential cone:

\[\EXP^* = \left\lbrace s \in \real^3: s_0 \geq -s_2 e^{-1} \exp(s_1/s_2),\ s_2\leq 0,s_0\geq 0 \right\rbrace.\]

For other types of cones supported by MOSEK see Sec. 7.2 (Conic Quadratic Optimization), Sec. 7.3 (Power Cone Optimization), Sec. 7.5 (Semidefinite Optimization). See Domain for a list and definitions of available cone types. Different cone types can appear together in one optimization problem.

For example, the following constraint:

\[(x_4, x_0, x_2) \in \EXP\]

describes a convex cone in \(\real^3\) given by the inequalities:

\[x_4 \geq x_0\exp(x_2/x_0),\ x_0,x_4\geq 0.\]

In Fusion the coordinates of a cone are not restricted to single variables. They can be arbitrary linear expressions, and an auxiliary variable will be substituted by Fusion in a way transparent to the user.

7.4.1 Example CEO1

Consider the following basic conic exponential problem which involves some linear constraints and an exponential inequality:

(7.5)\[\begin{split}\begin{array} {lrcl} \mbox{minimize} & x_0 + x_1 & & \\ \mbox{subject to} & x_0+x_1+x_2 & = & 1, \\ & x_0 & \geq & x_1\exp(x_2/x_1), \\ & x_0, x_1 & \geq & 0. \end{array}\end{split}\]

The conic form of (7.5) is:

(7.6)\[\begin{split}\begin{array} {lrcl} \mbox{minimize} & x_0 + x_1 & & \\ \mbox{subject to} & x_0+x_1+x_2 & = & 1, \\ & (x_0,x_1,x_2) & \in & \EXP, \\ & x & \in & \real^3. \end{array}\end{split}\]

We start by creating the optimization model:

  Model::t M = new Model("ceo1"); auto _M = finally([&]() { M->dispose(); });

We then define the variable x.

  Variable::t x  = M->variable("x", 3, Domain::unbounded());

The linear constraint is defined using the sum operator Expr.sum:

  // Create the constraint
  //      x[0] + x[1] + x[2] = 1.0
  M->constraint("lc", Expr::sum(x), Domain::equalsTo(1.0));

The conic exponential constraint in this case is very simple as it involves just the variable x. The primal exponential cone is referred to via Domain.inPExpCone, and it must be applied to a variable of length 3 or an array of such variables. Note that this is a basic way of defining conic constraints, and that in practice they would have more complicated structure.

  // Create the exponential conic constraint
  Constraint::t expc = M->constraint("expc", x, Domain::inPExpCone());

We only need the objective function:

  // Set the objective function to (x[0] + x[1])
  M->objective("obj", ObjectiveSense::Minimize, Expr::sum(x->slice(0,2)));

Calling the Model.solve method invokes the solver:

  M->solve();

The primal and dual solution values can be retrieved using Variable.level, Constraint.level and Variable.dual, Constraint.dual, respectively:

  // Get the linear solution values
  ndarray<double, 1> xlvl   = *(x->level());
  // Get conic solution of expc1
  ndarray<double, 1> expclvl = *(expc->level());
  ndarray<double, 1> expcdl  = *(expc->dual());
Listing 7.4 Fusion implementation of model (7.5). Click here to download.
#include <iostream>
#include "fusion.h"

using namespace mosek::fusion;
using namespace monty;

int main(int argc, char ** argv)
{
  Model::t M = new Model("ceo1"); auto _M = finally([&]() { M->dispose(); });

  Variable::t x  = M->variable("x", 3, Domain::unbounded());

  // Create the constraint
  //      x[0] + x[1] + x[2] = 1.0
  M->constraint("lc", Expr::sum(x), Domain::equalsTo(1.0));

  // Create the exponential conic constraint
  Constraint::t expc = M->constraint("expc", x, Domain::inPExpCone());

  // Set the objective function to (x[0] + x[1])
  M->objective("obj", ObjectiveSense::Minimize, Expr::sum(x->slice(0,2)));

  // Solve the problem
  M->solve();

  // Get the linear solution values
  ndarray<double, 1> xlvl   = *(x->level());
  // Get conic solution of expc1
  ndarray<double, 1> expclvl = *(expc->level());
  ndarray<double, 1> expcdl  = *(expc->dual());

  std::cout << "x1,x2,x3 = " << xlvl << std::endl;
  std::cout << "expc levels = " << expclvl << std::endl;
  std::cout << "expc dual conic var levels = " << expcdl << std::endl;
}