\documentclass[11pt]{article}

\usepackage{fullpage, xspace, hyperref, amsmath, multirow}

\def\qcmlver{0.2.0\xspace}
\def\qcml{\texttt{QCML}\xspace}
\def\cvxpy{\texttt{CVXPY}\xspace}
\def\cvx{\texttt{CVX}\xspace}
\def\cvxgen{\texttt{CVXGEN}\xspace}

% for captions
\makeatletter
\long\def\@makecaption#1#2{
   \vskip 9pt
   \begin{small}
   \setbox\@tempboxa\hbox{{\bf #1:} #2}
   \ifdim \wd\@tempboxa > 5.5in
        \begin{center}
        \begin{minipage}[t]{5.5in}
        \addtolength{\baselineskip}{-0.95pt}
        {\bf #1:} #2 \par
        \addtolength{\baselineskip}{0.95pt}
        \end{minipage}
        \end{center}
   \else
	\hbox to\hsize{\hfil\box\@tempboxa\hfil}
   \fi
   \end{small}\par
}
\makeatother

% text abbrevs
\newcommand{\eg}{{\it e.g.}}
\newcommand{\ie}{{\it i.e.}}
\newcommand{\etc}{{\it etc.}}

% math defs
\newcommand{\reals}{{\mbox{\bf R}}}
\newcommand{\dom}{\mathop{\bf dom}}

\title{\qcml version \qcmlver \\
A Python Toolbox for Matrix Stuffing}

\author{
Eric Chu\\\texttt{echu508@stanford.edu}
\and
Stephen Boyd\\\texttt{boyd@stanford.edu}
}

\date{\today}

\begin{document}
  \maketitle

\qcml is a Python module that provides a simple and lightweight domain
specific language (DSL) for describing convex optimization problem families
representable as second-order cone problems (SOCP). It is a code generator
that produces lightweight Python, Matlab, or C code for \emph{matrix
stuffing}. This allows one to extend SOCP solvers in these languages to a
variety of problem classes. It is intended to complement the paper,
\emph{Code Generation for Embedded Second-order Cone Programming} \cite{CPD:13},
although the main ideas in its
implementation are well-documented in \emph{Graph Implementation for Nonsmooth Convex Programs}
\cite{GB:08}.

\qcml comes with a small example library and consists of a single Python
object, \texttt{QCML}, with four methods
\begin{itemize}
\item {\tt parse}, which parses an optimization problem specified as a
string and checks that it is convex,
\item {\tt canonicalize}, which symbolically converts the problem into
a second-order cone program,
\item {\tt codegen}, which produces source code that performs the
transformation from problem-specific data to second-order cone problem data
and back,~and
\item {\tt save}, which saves the resulting source code into a folder for
future use.
\end{itemize}
The \texttt{codegen} method can be used to generate Python, C, and Matlab
source code.

Some important features:
\begin{itemize}
\item \qcml is similar in spirit to \cvx, \cvxgen, and
\cvxpy. Unlike these packages, however, \qcml exposes and generates code
for matrix stuffing, allowing the resulting code to be paired with any solver
that targets a standard SOCP.
\item \qcml is capable of generating fully abstract code with problem data and
dimensions as input to the \emph{generated} code, although it can specialize
the code if given problem dimensions before code is generated.
\item \qcml supports matrix parameters with arbitrary sparsity patterns.
\end{itemize}
That said, there are several important caveats:
\begin{itemize}
\item \qcml is intended for use by \emph{developers} wishing to employ convex
optimization in their source code with little to no overhead from the modeling
layer. Typically, these are users familiar with \cvx or \cvxpy who wish to
do away with modeling overhead in their applications.
\item \qcml is not a full-featured modeling language. Several features are
conspicuously missing and unless specifically requested, will remain missing.
\item For general purpose convex optimization in Python with more flexibility
than \qcml, we recommend \cvxpy
(\url{http://github.com/cvxgrp/cvxpy}).
\item For general purpose convex optimization in Matlab, we recommend
\cvx (\url{http://cvxr.com}).
\end{itemize}
Please send your feedback or report any bugs through our Github repository.

The rest of this document covers the basic use of \qcml and walks through a
full example with a lasso ($\ell_1$-regularized least-squares) problem.
\qcml is licensed under BSD.

\newpage
\tableofcontents
\newpage

\section{Installing \qcml}
\qcml depends on the following:
\begin{itemize}
\item Python 2.7.2+ (no Python 3 support)
\item \href{http://www.dabeaz.com/ply/}{\tt PLY}, the Python Lex-Yacc parsing framework,
  available as the {\tt python-ply} or {\tt py-ply} package in most distributions.
\item {\tt ECOS} (\url{http://github.com/embotech/ecos})
\item {\tt ECOS Python module} (\url{http://github.com/embotech/ecos-python})
\item {\tt NUMPY} (\url{http://numpy.org})
\item {\tt SCIPY} (\url{http://scipy.org})
\end{itemize}
For (some) unit testing, we use Nose (\url{http://nose.readthedocs.org}).

Once these dependencies are installed, typically through a package manager,
\qcml can be installed by typing
{\tt
\begin{tabbing}
  \qquad \= \$ python setup.py install
\end{tabbing}
}
\noindent at the command line. The unit tests can be run with {\tt nosetests}.

\section{Basic usage}
A \qcml problem must be specified following the language described in
\S\ref{s-ug-language}, but we give a basic example of \qcml here. The \qcml
API consists of four main functions, {\tt parse}, {\tt canonicalize},
{\tt codegen}, and {\tt save}. All optimization problems in \qcml are
specified as strings; suppose {\tt prob} is a string that represents a
particular optimization problem, then basic usage is summarized
in the following Python code:
{\tt
\begin{tabbing}
  \qquad \= from qcml import QCML \\
  \> p = QCML() \qquad \qquad \qquad \= \# creates a QCML object \\
  \> p.parse(prob) \> \# verifies that `prob' is a valid QCML string \\
  \> p.canonicalize() \> \# converts the problem into standard form \\
  \> p.codegen("python") \> \# generates Python source code for transforming `prob' \\
  \> p.save("myprob") \> \# saves the source code into a folder called `myprob'
\end{tabbing}
}
\noindent The {\tt parse} step verifies that the optimization problem adheres
to the rules described in \S\ref{s-ug-language}.

The {\tt canonicalize} step converts a \qcml problem into the
standard conic form
\begin{equation}
  \label{e-stdform}
\begin{array}{ll}
  \mbox{minimize} & c^Tx \\
  \mbox{subject to} & Gx + s = h \\
  & Ax = b\\
  & s \in \mathcal{K},
\end{array}
\end{equation}
where $x \in \reals^n$ and $s \in \reals^m$ are the optimization variables,
$c \in \reals^n$, $h \in \reals^m$, $b \in \reals^p$, $G \in \reals^{m\times n}$,
$A \in \reals^{p \times n}$, and the convex cone $\mathcal{K}$ are problem
data. The generated code is thus compatible with any solver that solves
\eqref{e-stdform}. We do not give more detail about canonicalization in this
user guide; for more detail, consult \cite{CVX, GB:08, CPD:13}.

The {\tt codegen} and {\tt save} steps target three different languages,
Python, C, and Matlab. We detail these in \S\ref{s-ug-codegen}.

\section{\qcml language}
\label{s-ug-language}
Optimization problems in \qcml are specified as \emph{strings} which must adhere to
the rules of the \qcml modeling language. The {\tt parse} function checks that
the problem string adheres to these rules. We describe that language and its
rules here.

\subsection{Types}
There are three basic types in \qcml:
\begin{itemize}
\item {\tt dimension} (or {\tt dimensions} for multiple dimension declarations)
\item {\tt parameter} (or {\tt parameters} for multiple parameter declarations)
\item {\tt variable} (or {\tt variables} for multiple variable declarations)
\end{itemize}
Objects named and declared in this fashion are entirely \emph{abstract}.
Numeric literals such as {\tt 2}, {\tt 0.52}, \etc, in \qcml are
\emph{concrete} and can be used directly in the \qcml problem string.

The {\tt dimension} objects are used to specify the (optional) sizes of {\tt
variable}s and {\tt parameter}s. So a single {\tt variable} or {\tt
parameter} object can represent an collection (or array) of scalar variables
or parameters with abstract dimension. (For more detail on abstract
dimensions, consult \S\ref{s-abstract-dims}.) At the moment, {\tt variables}
can represent vectors (one-dimensional arrays), and {\tt parameters} can
represent vectors or matrices (two-dimensional arrays). If a {\tt parameter}
represents a matrix, it is assumed to represent a \emph{sparse} matrix.

A {\tt variable} may also be labeled a \emph{dual} variable via the
{\tt dual} (prefix) keyword. Note that the size of a dual
variable is automatically inferrred when the dual variable is attached
to a constraint.

A {\tt parameter} may optionally take a sign modifier ({\tt positive} or
{\tt negative}). These are shorthand for `nonnegative' and `nonpositive',
respectively.

To declare an object, give its type, followed by its name, and (optionally)
its size: for instance,
{\tt
\begin{tabbing}
  \qquad \= variable x(n)
\end{tabbing}}
\noindent declares a vector variable named {\tt
x} with length {\tt n}.
Integer literals can also be used in place of dimensions. A more involved
example is the following code
{\tt
\begin{tabbing}
  \qquad \= dimensions m n \\
  \> variables x(n) y(m) z(5)\\
  \> dual variables u v \\
  \> parameter A(m,n) positive \\
  \> parameters b c(n)
\end{tabbing}}
\noindent which declares two dimensions, {\tt m} and {\tt n}; three
(primal) variables {\tt x}, {\tt y}, and {\tt z} of length {\tt n},
{\tt m}, and {\tt 5},respectively; two (dual) variables {\tt u} and
{\tt v}; an elementwise positive (sparse) parameter matrix, {\tt A}; the
scalar parameter {\tt b}; and the vector parameter {\tt c} with dimension
{\tt n}.

\subsection{Operators}
\qcml provides a set of operators for use with modeling. These are used in
conjunction with the basic {\tt variable} and {\tt parameter} types to
construct (affine) expressions. The standard (infix) operators are: {\tt +},
{\tt -}, {\tt *}, and {\tt /}. We also provide the (postfix) transpose
operator: {\tt '}, following Matlab convention. The {\tt -}
operator can also be used as a prefix to denote negation.

While the addition, subtraction, transposition, and negation operators
behave as standard linear operators and can act on any objects, the
multiplication and division operators are more restrictive:
\begin{itemize}
\item The division operator {\tt /} has the restriction that both operands
must be numeric constants.
\item The multiplication operator {\tt *} has the restriction that the
\emph{lefthand size} must be a parameter.
\end{itemize}
These restrictions are in place to ensure that expressions are \emph{affine}
(or linear) as a function of the variable objects (\ie, variables).

\subsection{Functions}
\qcml also provides a set of atoms (or functions) which take expressions
constructed from the basic operations as arguments. These functions have
additional properties associated with them:
\begin{itemize}
\item the \emph{sign} of the output expression (either positive, negative, or unknown),
\item the \emph{monotonicity} of the function in each argument
(either increasing, decreasing, or nonmonotone),
\item and the \emph{curvature} of the function (either convex, concave, or affine).
\end{itemize}
Roughly speaking, these can be associated with the sign of the zeroth, first,
and second derivatives of the function, respectively. (Although not all
functions we provide are differentiable.) More importantly, the sign and
monotonicities of a function may change depending on the sign of the input.
For instance, the {\tt square} function has positive sign (its outputs are
always positive) and is typically a nonmonotone function. However, when its
input is restricted to be positive, it is an increasing function. When a
\emph{convex} function has this property, we say that its monotonicity is
\emph{signed}. This means it is increasing if the argument is positive,
decreasing if the argument is negative, and nonmonotone otherwise. When a
\emph{concave} function has a signed monotonicity, it means that it is
decreasing if the argument is positive, increasing if the argument is negative,
and nonmonotone otherwise.

Before listing the atoms, a slight word on notation. We deviate slightly from
standard notation and use $f : \reals^p \to \reals^q$ to mean that a function
$f$ takes as input a real $p$-vector and produces a real $q$-vector as
output. Valid inputs are a \emph{subset} of all possible $p$-vectors,
specifically, its domain which we denote with $\dom f$. In other words, the
notation $f : \reals^p \to \reals^q$ can be thought of in the computer
science way---as a \emph{type signature} for the function $f$. As an example,
the $\log$ function has the following type signature, $\log : \reals \to
\reals$, although $\dom f$ is the set of strictly positive reals.

\subsubsection{Scalar atoms}
A scalar atom is a function with the type signature $f : \reals \to \reals$.
Table~\ref{t-scalar-atoms} lists out all the scalar atoms in our library
and their signs, monotonicity, and curvatures.
\begin{table}
  \small
  \renewcommand{\arraystretch}{1.5}
  \centering
\begin{tabular}{|l|l||l|l|l|} \hline
  Function & Definition & Sign & Monotonicity & Curvature \\ \hline
  {\tt abs(x)} & $f(x) = |x|$ & positive & signed & convex \\ \hline
  {\tt huber(x)} & $f(x) = \begin{cases} x^2 & |x| \leq 1 \\
    2|x| - 1 \leq 1 & |x| > 1 \end{cases}$ & positive & signed & convex \\ \hline
  {\tt inv\_pos(x)} & $f(x) = 1/x, \; x > 0$ & positive & decreasing & convex \\ \hline
  {\tt neg(x)} & $f(x) = \max(-x, 0)$ & positive & increasing & convex \\ \hline
  {\tt pos(x)} & $f(x) = \max(x, 0)$ & positive & increasing & convex \\ \hline
  {\tt pow\_rat(x,p,q)} & $f(x) = x^{p/q}, \; x >0$ & positive & (depends) & (depends) \\ \hline
  {\tt square\_over\_lin(x,y)} & $f(x) = x^2/y, \; y >0$ & positive & signed, decreasing & convex\\ \hline
  {\tt square(x)} & $f(x) = x^2$ & positive & signed & convex\\ \hline
  {\tt geo\_mean(x,y)} & $f(x,y) = \sqrt{xy}, \; x,y >0$ & positive & increasing, increasing & concave \\ \hline
  {\tt sqrt(x)} & $f(x) = \sqrt{x}, \; x >0$ & positive & increasing & concave \\ \hline
\end{tabular}
\caption{A list of the scalar atoms in \qcml. Scalar atoms with multiple arguments
require the same dimension for both arguments; their monotonicities are listed separately.}
\label{t-scalar-atoms}
\end{table}

The {\tt pow\_rat} atom is slightly special in that it takes two \emph{integer
literal} arguments, {\tt p} and {\tt q}, which must be in the set $\{1,2,3,4\}$.
The monotonicity and curvature of the atom depend on the values of {\tt p}
and {\tt q} chosen. If $p > q$, the function is increasing and convex.
If $p < q$, the function is decreasing and concave. If $p = q$, the function
is affine and, moreover, is the identity function.

We can define the \emph{extension}, $\tilde f : \reals^n \to \reals^n$,
of a scalar atom $f$ to a vector argument $x = (x_1, x_2, \ldots, x_n)$ as
\[
\tilde f(x) = \left( f(x_1), f(x_2), \ldots, f(x_n) \right),
\]
\ie, $\tilde f$ is $f$ applied elementwise.
Whenever scalar functions are called with vector arguments, this extension
is automatically applied. For scalar functions with the signature
$f : \reals \times \reals \to \reals$, their extension has the signature
$\tilde f : \reals^n \times \reals^n \to \reals^n$.

\subsubsection{Vector atoms}
A vector atom is a function with the type signature $f : \reals^n \to \reals$.
Table~\ref{t-vector-atoms} lists out all the scalar atoms in our library
and their signs, monotonicity, and curvatures.

\begin{table}
  \centering
  \small
  \renewcommand{\arraystretch}{1.5}
  \centering
\begin{tabular}{|l|l||l|l|l|} \hline
  Function & Definition & Sign & Monotonicity & Curvature \\ \hline
  {\tt quad\_over\_lin(x,y)} & $f(x) = x^Tx/y, \; y >0$ & positive & signed, decreasing & convex \\ \hline
  {\tt norm\_inf(x)} & $f(x) = \|x\|_\infty$ & positive & signed & convex \\ \hline
  {\tt norm1(x)} & $f(x) = \|x\|_1$ & positive & signed & convex \\ \hline
  {\tt norm(x)} or {\tt norm2(x)} & $f(x) = \|x\|_2$ & positive & signed & convex \\ \hline
  {\tt max(x)} & $f(x) = \max_i x_i$ & (depends) & increasing & convex \\ \hline
  {\tt min(x)} & $f(x) = \min_i x_i$ & (depends) & increasing & concave \\ \hline
\end{tabular}
\caption{A list of the vector atoms in \qcml. Vector atoms with multiple arguments
require the same dimension for both arguments; their monotonicities are listed separately.}
\label{t-vector-atoms}
\end{table}

The {\tt quad\_over\_lin} atom is slightly special in that it has a mixed
type signature, $f : \reals^n \times \reals \to \reals$. Its second argument
is \emph{always} scalar. If a nonscalar is provided, an exception will be
raised.

The {\tt max} and {\tt min} atoms have signs which depend on the sign of their
arguments. The rule for the sign of {\tt max} is as follows:
\begin{itemize}
\item if \emph{any} of its arguments are positive {\tt max} is positive,
\item if \emph{all} its arguments are negative {\tt max} is negative,
\item otherwise, {\tt max} has unknown sign.
\end{itemize}
The rule for the sign of {\tt min} is as follows:
\begin{itemize}
\item if \emph{any} of its arguments are negative {\tt min} is negative,
\item if \emph{all} its arguments are positive {\tt min} is positive,
\item otherwise, {\tt min} has unknown sign.
\end{itemize}

With the exception of {\tt quad\_over\_lin}, vector atoms can take variable
arguments. The \emph{extension}, $\tilde f : \reals^n \times \reals^n \to
\reals^n$, of a vector atom $f$ to two vector arguments is
\[
\tilde f(x, y) = \left( f\left(\begin{bmatrix} x_1 \\ y_1 \end{bmatrix}\right),
  f\left(\begin{bmatrix}x_2 \\ y_2 \end{bmatrix}\right), \ldots,
  f\left(\begin{bmatrix}x_n \\ y_n\end{bmatrix}\right) \right).
\]
The extension to an arbitrary number of input arguments can be obtained inductively.
Whenever vector functions are called with variable arguments, this extension
is automatically applied.

As an example, the expression {\tt norm(x,y,z)} forms the vector expression
\[
\left(
  \|(x_1,y_1,z_1)\|_2,
  \|(x_2, y_2, z_2)\|_2
\right),
\]
where $x = (x_1,x_2)$, $y = (y_1, y_2)$, and $z = (z_1, z_2)$. The extension
can be thought of as first performing a horizontal concatenation and applying
the atom \emph{row-wise}.

\subsection{Expressions}
Expressions in \qcml are formed by applying basic operators and functions to
numeric constants and to previously declared {\tt parameters} and {\tt
variables}. Every expression has additional properties:
\begin{itemize}
\item a \emph{shape} (either scalar, vector, or matrix),
\item a \emph{sign} (either positive, negative, or neither),
\item and a \emph{curvature} (either convex, concave, affine, or nonconvex).
\end{itemize}
An expression with \emph{nonconvex} curvature only means that it cannot be
verified as either convex, concave, or affine. The shape and sign of the
expression is inferred starting from the properties of the basic objects and
applying the operators and atoms (as listed in
Table~\ref{t-scalar-atoms} and Table~\ref{t-vector-atoms}). The expression curvature is
inferred in a similar way but using disciplined convex programming (DCP)
rules. We detail the DCP rules in \S\ref{s-ug-dcp}.

% For convenience in the sequel and with a slight abuse of notation, we use
% $\reals$ to refer to the set of all scalar-valued \emph{expressions} and $\reals_+$ to refer to the set of all scalar-valued expressions with positive sign. Similarly, $\reals^n$ and $\reals_-$ refer to the set of all vector-valued expressions of length $n$ and negative expressions, respectively.

%  associate shape scalar, vector, or matrix) and is categorized by its sign: positive, negative, or neither.
%
%
% .. blah blah, must adhere to DCP rules
%
% can use numeric constants....
%
% symbols must have been previously declared (basic types).
%
% have sign and shape (vector or matrix) associated with them.

\subsection{Objectives}
Objectives are optional in \qcml. If no objective is provided, the problem
is assumed to be a feasibility problem. A (nonempty) objective consists of a
\emph{sense}, either {\tt minimize} or {\tt maximize} and a scalar objective
expression.

The objective expression must agree with the objective sense.
If the sense is {\tt minimize}, then the expression must be convex (or affine).
If the sense if {\tt maximize}, then the expression must be concave (or affine).

\subsection{Constraints}
Constraints are formed using the typical relational operators: {\tt <=},
{\tt >=}, and {\tt ==}. The only restriction for these operators is the
curvature of the lefthand and righthand sides. Valid constraints are:
\begin{itemize}
\item affine expression {\tt ==} affine expression
\item convex expression {\tt <=} concave expression
\item concave expression {\tt >=} convex expression
\end{itemize}

Note that affine expressions are both convex and concave, so can be used
in either side of an inequality constraint.

\subsection{Problems}
A \qcml problem consists of a list of basic type declarations, zero or one
objective, and zero or more constraints. Here is a \qcml problem for
completeness:
{\tt
\begin{tabbing}
\qquad
\= dimensions m n \\
\> variable x(n) \\
\> dual variable y \\
\> parameter mu(n)\\
\> parameter gamma positive\\
\> parameter F(n,m) \\
\> parameter D(n,n) \\
\\
\> maximize (mu'*x - gamma*(square(norm(F'*x)) + square(norm(D*x)))) \\
\> subject to \\
\> \qquad \= sum(x) == 1 \\
\> \> y : x >= 0
\end{tabbing}
}
This sample problem has six type declarations, one maximization objective, and
two constraints. The nonnegativity constraint has the dual variable {\tt y}
associated with it. The {\tt subject to} keyword is optional.

\section{Disciplined convex programming}
\label{s-ug-dcp}
Disciplined convex programming describes how to infer the curvature of an
expression using only local information (from the immediate operands of an
operation) \cite{CVX}. We start from the leaves of an expression, which consists
of basic objects, {\tt variable}s, {\tt parameter}s, and numeric constants.

All three of these have \emph{affine} curvature.
We then infer the curvature of the expression by recursively applying the
following composition rule:
$\phi(g_1(x),\ldots, g_n(x))$ is convex if the atom $\phi$ is convex and for each $i$
\begin{itemize}
  \item $g_i$ is affine, or
  \item $\phi$ is increasing in the $i$th argument and $g_i$ is convex, or
  \item $\phi$ is decreasing in the $i$th argument and $g_i$ is
concave.
\end{itemize}
The rule for verifying concavity is similar.  The expression is
affine if $\phi$ is affine and $g_1,\ldots, g_n$ are all affine.
%This extends the basic idea that the sum of two convex functions is convex.

\section{Abstract dimensions}
\label{s-abstract-dims}
Dimensions are initially specified as abstract values and can be left abstract
in \qcml. These abstract values must be converted into concrete values
before the problem can be solved. There are two ways to make dimensions
concrete:
\begin{enumerate}
\item specified prior to code generation
\item specified after code generation by passing a {\tt dims} map (as a
  dictionary or struct) to the generated functions %, e.g. \texttt{prob2socp`, `socp2prob`
\end{enumerate}

Dimensions can be set prior to code generation by supplying
a partial map, \ie, if {\tt problem} contains a \qcml problem with
dimensions \texttt{m} and \texttt{n}, then the Python code
{\tt
\begin{tabbing}
  \qquad \= >>> p = QCML() \\
  \> >>> p.parse(problem) \\
  \> >>> p.dims = \{'m': 5\}
\end{tabbing}
}
\noindent will set the dimension {\tt m} to $5$ in all expressions, but leave
the dimension {\tt n} to be specified later.

Any dimensions specified before code generation will be hard-coded into the
resulting problem formulation functions. Thus all problem data fed into the
generated code must match these prespecified dimensions. In other words, the
generated code is \emph{specialized} to this fixed dimension.

Dimensions that are left abstract allow users to specify problems of
differing size, but the dimensions of the input problem must be supplied at
the same time. A future release may allow some dimensions to be inferred from
the size of the inputs.

\section{Code generation}
\label{s-ug-codegen}
Once a \qcml problem has been parsed and canonicalized, code is generated
to perform the matrix stuffing, converting the parameters in an optimization
problem into the data for a standard cone program. This is done by the
{\tt codegen} function. The {\tt save} function saves the generated code to
a folder or file for use later. The generated code can be used with \qcml as
a dependency and thus can be easily included with any project.

The {\tt codegen} function generates two functions in the desired language:
\begin{itemize}
\item a {\tt prob\_to\_socp} function which maps {\tt parameter}s into the cone
program data, and
\item a {\tt socp\_to\_prob} function which unpacks a solution of the cone program
into the {\tt variable}s of the problem.
\end{itemize}
We describe specifics of these functions in the sequel.

\subsection{Python}
To generate Python code, invoke the {\tt codegen} function with the string
{\tt `python'} as the argument. This will generate two functions
\begin{itemize}
\item {\tt prob\_to\_socp(params, dims)} and
\item {\tt socp\_to\_prob(x, y, z, dims)}.
\end{itemize}
Invoking the {\tt save} function will save the two functions to a folder.

\subsubsection{The {\tt prob\_to\_socp} function}
The {\tt prob\_to\_socp} function takes two dictionary
arguments, a {\tt params} and a {\tt dims} dictionary. If all dimensions are
concrete before {\tt codegen} is invoked, the {\tt dims} argument is optional.
The keys in these
dictionaries correspond to the names of the {\tt parameter}s and the
remaining (abstract)
{\tt dimension}s specified in the problem string.

The {\tt dims} values must be Python integers. Vector {\tt parameter}s are
supplied by Numpy arrays (not matrices), and matrix {\tt parameter}s can be
either Numpy arrays or Scipy sparse matrices.

Any extra parameters or dimensions will be unused.

The function will return a dictionary which contains all the information
necessary for solving a cone program. This consists of the key-value pairs
\begin{itemize}
  \item {\tt c}, a Numpy array,
  \item {\tt G}, a Scipy sparse matrix in column-compressed format,
  \item {\tt h}, a Numpy array,
  \item {\tt A}, a Scipy sparse matrix in column-compressed format,
  \item {\tt b}, a Numpy array, and
  \item {\tt dims}, a Python dictionary with the key-value pairs,
  \begin{itemize}
    \item {\tt l}, the number of linear cones, and
    \item {\tt q}, a list of the size of second-order cones.
  \end{itemize}
\end{itemize}
The {\tt dims} output dictionary, which describes the cones,
is not to be confused with the {\tt dims} input
dictionary, which specifies problem dimensions.
The output dictionary corresponds to the problem data in \eqref{e-stdform}
and are sufficient for \emph{any} conic solver.

The data {\tt G} and {\tt h} may be `None,' in which case the standard form
\qcml problem has no conic constraints. Similarly, {\tt A} and {\tt b} may be
`None,' in which case the standard form \qcml problem has no equality
constraints.

\subsubsection{The {\tt socp\_to\_prob} function}
The {\tt socp\_to\_prob} function takes four arguments, {\tt x}, {\tt y},
{\tt z}, and {\tt dims} and returns a dictionary with keys
corresponding to the names of the {\tt variable}s (including any dual
variables) in the given \qcml problem.
The {\tt dims} argument is the same as in {\tt prob\_to\_socp}; the {\tt x}
argument is the (primal) solution to the cone program; the {\tt y}
argument is the (dual) solution corresponding to the
affine equality constraint $Ax=b$ in \eqref{e-stdform}; and the {\tt z}
argument is the (dual) solution corresponding
to the conic constraints $s \in \mathcal{K}$ in \eqref{e-stdform}.
The values of these entries are Numpy arrays (if vectors) or Python floats.

The input argument is a Numpy array.

\subsubsection{Dynamic execution}
In addition to saving the generated Python source code, the code is compiled
into Python bytecode during runtime and can be \emph{executed} right after
{\tt codegen}. After the {\tt codegen} step, the QCML object will have two
new methods, {\tt prob2socp} and {\tt socp2prob}, which correspond to the
generated code. These methods can be used without having to save the Python
source.

\subsection{Matlab}
To generate Matlab code, invoke the {\tt codegen} function with the string
{\tt `matlab'} as the argument. This will generate two functions
\begin{itemize}
\item {\tt prob\_to\_socp(params, dims)} and
\item {\tt socp\_to\_prob(x, y, z, dims)}.
\end{itemize}
Invoking the {\tt save} function will save the two functions to a folder.

\subsubsection{The {\tt prob\_to\_socp} function}
The {\tt prob\_to\_socp} function takes two Matlab struct
arguments, a {\tt params} and a {\tt dims} dictionary. If all dimensions are
concrete before {\tt codegen} is invoked, the {\tt dims} argument is unused.
The fields in these
structs correspond to the names of the {\tt parameter}s and the
remaining (abstract)
{\tt dimension}s specified in the problem string.

Any extra parameters or dimensions will be unused.

The function will return a struct which contains all the information
necessary for solving a cone program. This consists of the fields
\begin{itemize}
  \item {\tt c}, a dense vector,
  \item {\tt G}, a sparse matrix,
  \item {\tt h}, a dense vector,
  \item {\tt A}, a sparse matrix,
  \item {\tt b}, a dense vector, and
  \item {\tt dims}, a Matlab struct with the fields,
  \begin{itemize}
    \item {\tt l}, the number of linear cones, and
    \item {\tt q}, a vector with the size of second-order cones.
  \end{itemize}
\end{itemize}
The {\tt dims} output struct, which describes the cones,
is not to be confused with the {\tt dims} input
struct, which specifies problem dimensions.
The output struct corresponds to the problem data in \eqref{e-stdform}
and are sufficient for \emph{any} conic solver.

The matrix {\tt G} and vector {\tt h} may be empty, in which case the
standard form \qcml problem has no conic constraints. Similarly, {\tt A} and
{\tt b} may be empty, in which case the standard form \qcml problem has no
equality constraints.

\subsubsection{The {\tt socp\_to\_prob} function}
The {\tt socp\_to\_prob} function takes four arguments, {\tt x}, {\tt y},
{\tt z}, and {\tt dims} and returns a struct with fields
corresponding to the names of the {\tt variable}s (including any dual
variables) in the given \qcml problem.
The {\tt dims} argument is the same as in {\tt prob\_to\_socp}; the {\tt x}
argument is the (primal) solution to the cone program; the {\tt y}
argument is the (dual) solution corresponding to the
affine equality constraint $Ax=b$ in \eqref{e-stdform}; and the {\tt z}
argument is the (dual) solution corresponding
to the conic constraints $s \in \mathcal{K}$ in \eqref{e-stdform}.

\subsection{C}
To generate C code, invoke the {\tt codegen} function with the string
{\tt `C'} as the argument. This will generate two functions
\begin{itemize}
\item {\tt qc\_socp *qc\_prob2socp(const prob\_params *params, const prob\_dims *dims)}, and
\item
{\tt
\begin{tabbing}
void qc\_socp2prob(\=const double *x, const double *y, const double *z,\\
\> prob\_vars *vars, const prob\_dims *dims).
\end{tabbing}
}
\end{itemize}
Invoking the {\tt save} function will save the two functions to a folder along
with several other files:
\begin{itemize}
  \item a {\tt qcml\_utils.h} header file defining matrix and {\tt qc\_socp} data structures,
  \item a {\tt qcml\_utils.c} source file implementing matrix utility functions,
  \item a {\tt prob.h} header file defining {\tt qc\_prob2socp} and {\tt qc\_socp2prob},
  \item a {\tt prob.c} source file implementing the matrix stuffing, and
  \item a {\tt Makefile} to compile the sources into object files.
\end{itemize}
To prevent naming clashes, occurrences of {\tt prob} in filenames, function
names, and struct names are replaced by the name of the folder specified in
the {\tt save} method.

The {\tt qcml\_utils} header and source file are \emph{not} custom generated
for each problem. Instead, they contain the common matrix data structures and
functions needed by \emph{any} generated code. Thus, multiple problems can
use the \emph{same} {\tt qcml\_utils} header and source code.

The supplied {\tt Makefile} only compiles the source code into binary objects.
It is up to the user to link them against a main binary.

\subsubsection{The {\tt prob\_to\_socp} function}
The {\tt prob\_to\_socp} function takes two struct arguments, a {\tt
prob\_params} and a {\tt prob\_dims} struct. If all dimensions are concrete
before {\tt codegen} is invoked, the {\tt prob\_dims} argument can be {\tt
NULL}. The fields in these structs correspond to the names of the {\tt
parameter}s and the remaining (abstract) {\tt dimension}s specified in the
problem string.

Vector {\tt parameter}s
are supplied as a pointer to (dense) double arrays, and matrix {\tt
parameter}s are supplied as a pointer to the custom {\tt qc\_matrix} struct,
which stores the matrix in triplet ($i,j,v$) format.

Any extra parameters or dimensions will be unused.

The function will return a {\tt qc\_socp} struct which contains all the
information necessary for solving a cone program. This consists of the
fields (with their type):
\begin{itemize}
  \item {\tt long n}, the number of variables in \eqref{e-stdform},
  \item {\tt long m}, number of cone constraints in \eqref{e-stdform},
  \item {\tt long p}, number of equality constraints in \eqref{e-stdform},
  \item {\tt long l}, number of linear cones,
  \item {\tt long nsoc}, number of second-order cones,
  \item {\tt long *q}, list of second-order cone sizes,
  \item {\tt double *G}, nonzero values of G (in column-compressed format),
  \item {\tt long *Gp}, column pointers of G (in column-compressed format),
  \item {\tt long *Gi}, row values of G (in column-compressed format),
  \item {\tt double *A}, nonzero values of A (in column-compressed format),
  \item {\tt long *Ap}, column pointers of A (in column-compressed format),
  \item {\tt long *Ai}, row values of A (in column-compressed format),
  \item {\tt double *c}, c vector (dense),
  \item {\tt double *h}, h vector (dense), and
  \item {\tt double *b}, b vector (dense),
\end{itemize}
The {\tt qc\_socp} struct corresponds to the problem data in \eqref{e-stdform}
and are sufficient for \emph{any} conic solver. It must be freed when no
longer in use.

The data pointers {\tt Gx}, {\tt Gp}, {\tt Gi}, and {\tt h} may be {\tt
NULL}, in which case the standard form \qcml problem has no conic
constraints. Similarly, {\tt Ax}, {\tt Ap}, {\tt Ai}, and {\tt b} may be {\tt
NULL}, in which case the standard form \qcml problem has no equality
constraints.

\subsubsection{The {\tt socp\_to\_prob} function}
The {\tt socp\_to\_prob} function takes five arguments: a {\tt double *}, which
points to a double array containing the (primal) solution to the cone program;
a second {\tt double *}, which points to a double array containing the (dual) solution
corresponding to the
affine equality constraint $Ax=b$ in \eqref{e-stdform}; a third {\tt double *},
which points to a double array containing the (dual) solution corresponding
to the conic constraints $s \in \mathcal{K}$ in \eqref{e-stdform};
a {\tt prob\_vars} struct, which is set to
the \emph{pointers} in the underlying {\tt prob\_vars} struct to the
{\tt variable}s in the \qcml problem; and a {\tt prob\_dims} struct.

\section{Rapid prototyping}
\qcml also provides a helper function for rapid prototyping in Python. This
is useful to verify the optimization model before generating code to use
elsewhere. The {\tt solve} function executes the {\tt parse}, {\tt canonicalize},
and {\tt codegen} functions in succession. It also takes the generated source
code and produces bytecode that is executed on-the-fly.

Thus, if {\tt prob} is a \qcml problem, then
{\tt
\begin{tabbing}
  \qquad \= >>> p = QCML() \\
  \> >>> p.parse(prob) \\
  \> >>> p.solve()
\end{tabbing}
}
\noindent
will use parameters and dimensions defined locally to stuff the matrices and
invoke the ECOS solver to solve the problem.

This feature is useful in Python to test (small) models before committing to
a source code.

\section{Lasso example}
In this section, we will walk through a simple \qcml use-case by implementing
a lasso ($\ell_1$-regularized least squares) solver in C. This example
and others like it can be found under the {\tt qcml/examples} directory.

The lasso problem is
\[
\begin{array}{ll}
  \mbox{minimize} & \|Ax - b\|_2^2 + \lambda \|x\|_1,
\end{array}
\]
with variable $x \in \reals^n$ and problem data $A\in\reals^{m\times n}$,
$b \in \reals^m$, and $\lambda > 0$. We can solve this problem using a
standard interior-point solver, such as ECOS, with the transformation
to standard cone form provided by \qcml.

First, we begin by generating some random problem data using Numpy,
{\tt
\begin{tabbing}
\qquad \= from numpy.random import randn\\
\> n = 1000    \# number of features\\
\> m = 100     \# number of examples\\
\> A = randn(m,n)\\
\> b = randn(m)\\
\> gamma = 1
\end{tabbing}
}
\noindent We then specify the lasso problem in \qcml as follows:
{\tt
\begin{tabbing}
\qquad
\= dimensions m n \\
\> variable x(n) \\
\> parameters A(m,n) b(m)\\
\> parameter gamma positive\\
\\
\> minimize square(norm(A*x - b)) + gamma*norm1(x)
\end{tabbing}
}
\noindent Storing this description in the Python string variable {\tt prob},
we first solve the problem using ECOS,
{\tt
\begin{tabbing}
\qquad \= from qcml import QCML\\
\> p = QCML()\\
\> p.parse(prob)\\
\> res = p.solve()
\end{tabbing}
}
\noindent Typically, at this stage, one would tweak the model as needed to
obtain better performance (on a cross-validation set, say), but since we
have committed to solving the lasso problem, this step is only to verify that
the problem is properly solved.

We can print the value of {\tt res['objval']} to see the optimal
value of the randomly generated lasso problem and save the randomly generated
data for validation later. Next, we generate C source
code for the lasso problem
{\tt
\begin{tabbing}
\qquad \= p.codegen("C")\\
\> p.save("lasso")
\end{tabbing}
}

This will create a directory named `{\tt lasso}' which contains the source code
along with a Makefile. The
generated functions will be named {\tt qc\_lasso2socp} and {\tt qc\_socp2lasso}.
We can then write a separate main function which calls the {\tt qc\_lasso2socp}
to create the necessary data structures for calling the ECOS solver:
{\tt
\begin{tabbing}
\qquad \= /* read data into arrays */ \\
\> double *Av = ...; /* nonzero values of A parameter */\\
\> double *b = ...;  /* values of b parameter */\\
\> long *Ai = ...;   /* nonzero row indices */\\
\> long *Aj = ...;   /* nonzero col indices */\\
\\
\> /* create parameter, dimension, and solution structs */\\
\> lasso\_params p;\\
\> lasso\_dims d;\\
\> lasso\_vars sol;\\
\\
\> /* matrix used in lasso\_params */\\
\> qc\_matrix A;\\
\> A.v = Av; A.i = Ai; A.j = Aj; A.nnz = m*n;\\
\> A.m = m; A.n = n; /* m, n provided exogenously */ \\
\\
\> /* set the parameters and dims*/\\
\> p.A = \&A; p.b = b; p.gamma = 1.0;\\
\> d.m = A.m; d.n = A.n;\\
\\
\> /* stuff the matrices */\\
\> qc\_socp *data = qc\_lasso2socp(\&p, \&d);\\
\\
\> /* run ecos and solve it */\\
\> pwork *mywork = ECOS\_setup(data->n, data->m, data->p,\\
\> \quad \= data->l, data->nsoc, data->q,\\
\> \> data->Gx, data->Gp, data->Gi,\\
\> \> data->Ax, data->Ap, data->Ai,\\
\> \> data->c, data->h, data->b);\\
\> if (mywork)\\
\> \{\\
\> \quad \= ECOS\_solve(mywork);\\
\\
\> \> /* recover the solution */ \\
\> \> qc\_socp2lasso(mywork->x, mywork->y, mywork->z, \&sol, \&d);\\
\> \> ... sol.x ... /* do something with solution */\\
\> \}\\
\\
\> /* free the data */ \\
\> qc\_socp\_free(data);\\
\> if (mywork) ECOS\_cleanup(mywork, 0);
\end{tabbing}
}

Finally, the main file can be linked against the {\tt qcml\_utils} and
generated {\tt lasso} objects and used as a stand-alone binary.

% \newpage
\bibliographystyle{plain}
\bibliography{userguide}
\end{document}


% This LaTeX was auto-generated from an M-file by MATLAB.
% To make changes, update the M-file and republish this document.

      \subsection{hypCurb.m}

\begin{par}
\textbf{Summary:} Wrapper for GP training (via gpr.m), penalizing large SNR and extreme length-scales to avoid numerical instabilities
\end{par} \vspace{1em}

\begin{verbatim}   function [f df] = hypCurb(lh, covfunc, x, y, curb)\end{verbatim}
    \begin{par}
\textbf{Input arguments:}
\end{par} \vspace{1em}
\begin{verbatim}lh       log-hyper-parameters                                   [D+2 x  E ]
covfunc  covariance function, e.g.,
                            covfunc = \{'covSum', \{'covSEard', 'covNoise'\}\};
x        training inputs                                        [ n  x  D ]
y        training targets                                      [ n  x  E ]
curb     (optional) parameters to penalize extreme hyper-parameters
  .ls    length-scales
  .snr   signal-to-noise ratio (try to keep it below 500)
  .std   additional parameter required for length-scale penalty\end{verbatim}
\begin{par}
\textbf{Output arguments:}
\end{par} \vspace{1em}
\begin{verbatim}f        penalized negative log-marginal likelihood
df       derivative of penalized negative log-marginal likelihood wrt
         GP log-hyper-parameters\end{verbatim}
\begin{par}
Copyright (C) 2008-2013 by Marc Deisenroth, Andrew McHutchon, Joe Hall, and Carl Edward Rasmussen.
\end{par} \vspace{1em}
\begin{par}
Last modified: 2011-12-19
\end{par} \vspace{1em}

\subsection*{High-Level Steps}

\begin{enumerate}
\setlength{\itemsep}{-1ex}
   \item Compute the negative log-marginal likelihood (plus derivatives)
   \item Add penalties and change derivatives accordingly
\end{enumerate}

\begin{lstlisting}
function [f df] = hypCurb(lh, covfunc, x, y, curb)
\end{lstlisting}

\subsection*{Code}

\begin{lstlisting}
if nargin < 5, curb.snr = 500; curb.ls = 100; curb.std = 1; end   % set default

p = 30;                                                         % penalty power
D = size(x,2);
if size(lh,1) == 3*D+2; li = 1:2*D; sfi = 2*D+1:3*D+1; % 1D and DD terms
elseif size(lh,1) == 2*D+1; li = 1:D; sfi = D+1:2*D;   % Just 1D terms
elseif size(lh,1) == D+2; li = 1:D; sfi = D+1;         % Just DD terms
else error('Incorrect number of hyperparameters');
end

ll = lh(li); lsf = lh(sfi); lsn = lh(end);

% 1) compute the negative log-marginal likelihood (plus derivatives)
[f df] = gpr(lh, covfunc, x, y);                              % first, call gpr

% 2) add penalties and change derivatives accordingly
f = f + sum(((ll - log(curb.std'))./log(curb.ls)).^p);   % length-scales
df(li) = df(li) + p*(ll - log(curb.std')).^(p-1)/log(curb.ls)^p;

f = f + sum(((lsf - lsn)/log(curb.snr)).^p); % signal to noise ratio
df(sfi) = df(sfi) + p*(lsf - lsn).^(p-1)/log(curb.snr)^p;
df(end) = df(end) - p*sum((lsf - lsn).^(p-1)/log(curb.snr)^p);
\end{lstlisting}


\documentclass[a4paper,twocolumn]{article}

\usepackage[utf8]{inputenc}
\usepackage[english]{babel}
\usepackage[T1]{fontenc}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{dsfont}
\usepackage{graphicx}
\usepackage{color}
\usepackage{interval}

\newcommand{\N}{\mathbf{N}}
\newcommand{\Z}{\mathbf{Z}}
\newcommand{\Q}{\mathbf{Q}}
\newcommand{\R}{\mathbf{R}}
\newcommand{\C}{\mathbf{C}}

\author{Florian Fontan}
\title{Advanced Models and Methods in Operations Research \\ Project: Vehicle routing}
\date{2021--2022}

\begin{document}

\maketitle

For each problem considered, instances and a code skeleton containing an instance parser and a solution checker are provided in the \texttt{data/} and \texttt{python/} folders of the project.

The algorithms must be implemented in the provided files between the tags \texttt{TODO START} and \texttt{TODO END}.

They must be tested on all the provided instances with the command:
\texttt{python3 problem.py -i instance.json -c certificate.json}

And each solution file must be validated by the provided checker:
\texttt{python3 problem.py -a checker -i instance.json -c certificate.json}

The results must be reproducible.

\bigskip

The delivrable must contain:
\begin{itemize}
  \item A \emph{short} report describing and justifying the proposed algorithms
  \item The code implementing the algorithms
  \item The solution files obtained on the provided instances
\end{itemize}

\section{Dynamic Programming}

We consider the Elementary shortest path problem with resource constraint and a single slot:
\begin{itemize}
  \item Input:
    \begin{itemize}
      \item $1$ depot
      \item $n - 1$ customers; for each customer $j = 2, \dots, n$, a visit interval $\interval[open right]{s_j}{e_j}$, $s_j \in \N_+$, $e_j \in \N_+$, $s_j < e_j$
      \item an $n \times n$ symmetric matrix $t$ specifying the times in $\R_+$ to travel between each pair of locations
      \item an $n \times n$ matrix $c$ specifying the costs in $\R$ to travel between each pair of locations
    \end{itemize}
  \item Problem: find a sub-tour starting and ending at the depot such that
    \begin{itemize}
      \item each customer is visited at most once
      \item the arrival at a customer $j$ is before $s_j$
      \item the departure from a customer is at $e_j$ (even if the arrival was before $s_j$)
    \end{itemize}
  \item Objective: minimize the cost of the sub-tour
\end{itemize}

Note that the costs might be negative.

Propose and implement an algorithm based on Dynamic Programming for this problem.

\section{Heuristic Tree Search}

We consider the Elementary shortest path problem with resource constraint and two slots:
\begin{itemize}
  \item Input:
    \begin{itemize}
      \item $1$ depot
      \item $n - 1$ customers; for each customer $j = 2, \dots, n$, two visit intervals (which might overlap)
        \begin{itemize}
          \item $\interval[open right]{s_j^1}{e_j^1}$, $s_j^1 \in \N_+$, $e_j^1 \in \N_+$, $s_j^1 < e_j^2$
          \item $\interval[open right]{s_j^2}{e_j^2}$, $s_j^2 \in \N_+$, $e_j^2 \in \N_+$, $s_j^2 < e_j^2$
        \end{itemize}
      \item an $n \times n$ symmetric matrix $t$ specifying the times in $\R_+$ to travel between each pair of locations
      \item an $n \times n$ matrix $c$ specifying the costs in $\R$ to travel between each pair of locations
    \end{itemize}
  \item Problem: find a sub-tour starting and ending at the depot such that
    \begin{itemize}
      \item each customer is visited at most once
      \item the arrival and the departure from a customer include one of its two visit intervals
    \end{itemize}
  \item Objective: minimize the cost of the sub-tour
\end{itemize}

Propose and implement an algorithm based on Heuristic Tree Search with Dynamic Programming for this problem.

\section{Column Generation \\ + Dynamic Programming}

We consider the Vehicle routing problem with a single slot:
\begin{itemize}
  \item Input:
    \begin{itemize}
      \item $1$ depot
      \item $n - 1$ customers; for each customer $j = 2, \dots, n$, a visit interval $\interval[open right]{s_j}{e_j}$, $s_j \in \N_+$, $e_j \in \N_+$, $s_j < e_j$
      \item an $n \times n$ symmetric matrix $t$ specifying the times in $\R_+$ to travel between each pair of locations
    \end{itemize}
  \item Problem: find a set of routes starting and ending at the depot such that
    \begin{itemize}
      \item each customer is visited exactly once
      \item the arrival at a customer $j$ is before $s_j$
      \item the departure from a customer is at $e_j$ (even if the arrival was before $s_j$)
    \end{itemize}
  \item Objective: minimize the total traveled distance
\end{itemize}

Propose an exponential formulation and implement an algorithm based on a Column Generation heuristic for this problem.

\section{Column Generation \\ + Heuristic Tree Search}

We consider the Vehicle routing problem with two slots:
\begin{itemize}
  \item Input:
    \begin{itemize}
      \item $1$ depot
      \item $n - 1$ customers; for each customer $j = 2, \dots, n$, two visit intervals (which might overlap)
        \begin{itemize}
          \item $\interval[open right]{s_j^1}{e_j^1}$, $s_j^1 \in \N_+$, $e_j^1 \in \N_+$, $s_j^1 < e_j^2$
          \item $\interval[open right]{s_j^2}{e_j^2}$, $s_j^2 \in \N_+$, $e_j^2 \in \N_+$, $s_j^2 < e_j^2$
        \end{itemize}
      \item an $n \times n$ symmetric matrix $t$ specifying the times in $\R_+$ to travel between each pair of locations
    \end{itemize}
  \item Problem: find a set of routes starting and ending at the depot such that
    \begin{itemize}
      \item each customer is visited exactly once
      \item the arrival and the departure from a customer include one of its two visit intervals
    \end{itemize}
  \item Objective: minimize the total traveled distance
\end{itemize}

Propose an exponential formulation and implement an algorithm based on a Column Generation heuristic for this problem.

\end{document}

2021-2022 - M2 ORCO - Advanced OR/Projects/Vehicle routing/subject/main.tex