Skip to content

Commit

Permalink
udpate documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
hlefebvr committed Jan 23, 2025
1 parent d5145dc commit 5fc7d1e
Show file tree
Hide file tree
Showing 17 changed files with 475 additions and 253 deletions.
1 change: 1 addition & 0 deletions dev/main.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <iostream>
#include <idol/idol/modeling/matrix/Column.h>
#include "idol/general/utils/SparseVector.h"
#include "idol/mixed-integer/modeling/variables/Var.h"
#include "idol/mixed-integer/modeling/models/Model.h"
Expand Down
13 changes: 13 additions & 0 deletions docs/_static/design.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ body {

.content:not(.custom) {
max-width: 900px;
text-align: justify;
}

.content img {
Expand All @@ -20,6 +21,18 @@ body {
grid-template-columns: auto auto auto;
}

.content .toctree-l1 {

> ul {
margin-top: 20px;
}

ul {
margin-bottom: 20px;
}

}

#cards > a {
display: block;
width: 270px;
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = 'idol'
copyright = '2023, Henri Lefebvre'
copyright = '2025, Henri Lefebvre'
author = 'Henri Lefebvre'


Expand Down
7 changes: 5 additions & 2 deletions docs/tutorials/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
Tutorials
=========

Mixed-Integer Programming
-------------------------
On this page, you will find a collection of tutorials that demonstrate how to use idol to solve various optimization problems.
The tutorials are organized by topic.

Mixed-Integer Optimization
--------------------------

.. toctree::
:maxdepth: 3
Expand Down
26 changes: 24 additions & 2 deletions docs/tutorials/mixed-integer-programming/index.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
.. _mip:

Mixed-Integer Programming
=========================
Mixed-Integer Optimization
==========================

Mixed-integer optimization deals with problems of the following form:

.. math::
:label: eq:mip
\begin{align}
\min_{x} \quad & c^\top x + x^\top D x + c_0 \\
\text{s.t.} \quad & a_{i\cdot}^\top x + x^\top Q^i x \le b_i, \quad i = 1, \ldots, m, \\
& x_j \in \mathbb{Z}, \quad j \in I \subseteq \{ 1, \dotsc, n \}.
\end{align}
Here, :math:`x` are the decision variables, while :math:`c`, :math:`D`, :math:`c_0`, :math:`a_i`, :math:`Q^i`, and :math:`b_i` are given data.
Some of the decision variables are required to be integer-valued and are indexed by :math:`I`.

We say that :math:numref:`eq:mip` is an integer problem if :math:`I = \{ 1, \dotsc, n \}`, i.e., if all variables are required to
be integer. It is said to be mixed-integer if :math:`I \neq \emptyset`. Otherwise, we say that :math:numref:`eq:mip` is a continuous problem.

An important class of problems is when :math:`D = 0` and :math:`Q^i = 0` for all :math:`i`, i.e., when the objective function and the constraints are linear.
In such a case, we say that :math:numref:`eq:mip` is a mixed-integer linear problem (MILP), or a linear problem (LP) if all variables are continuous.

**Table of Contents**

.. toctree::
:maxdepth: 2
Expand Down
79 changes: 57 additions & 22 deletions docs/tutorials/mixed-integer-programming/modeling/constraints.rst
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
.. _api_constraints:

Constraints
-----------
Constraints: :code:`Ctr` and :code:`QCtr`
=========================================

Constraints are mathematical expressions that must be satisfied by the decision variables of an optimization problem.
They are used to model relationships between variables, and to restrict the feasible region of the problem.

There are mainly two types of constraints:

- **Linear Constraints**: constraints that are linear in the decision variables.
- **Quadratic Constraints**: constraints that are non-linear in the decision variables.

.. contents:: Table of Contents
:local:
:depth: 2

Linear Constraints
------------------

Creating Constraints
^^^^^^^^^^^^^^^^^^^^

Similarly to variables, constraints are easily created and added to a given ``Model``.

Constraints can be created by calling the constructor of the :ref:`Ctr <api_Ctr>` class and added to a model by means of
:cpp:`Model::add` or by calling the :cpp:`Model::add_ctr` method. See for instance.
:cpp:`Model::add` or by calling the :cpp:`Model::add_ctr` method.

Using the :cpp:`Ctr` class directly creates a variable that is not associated to any model. We will then need to add it
explicitly to a model. This is done by calling the :cpp:`Model::add` method. See for instance the following code.

.. code::
Expand All @@ -35,9 +49,12 @@ A more compact version of this code is obtained by making use of the ``Model::ad
Env env;
Model model(env);
const auto x = model.add_vars(Dim<1>(2), 0., Inf, Continuous, "x");
const auto x = model.add_vars(Dim<1>(2), 0., Inf, Continuous, 0, "x");
const auto constraint = model.add_ctr(x[0] + x[1] >= 1);
Temporary Constraints
^^^^^^^^^^^^^^^^^^^^^

As you can see, a constraint is created using the pattern :code:`{expression} {sign} {expression}` where

* :code:`{sign}` is one of :code:`<=`, :code:`>=` and :code:`==`;
Expand All @@ -53,49 +70,56 @@ Temporary constraints are objects of the class :ref:`TempCtr <api_TempCtr>`. An
Model model(env);
const auto x = model.add_vars(Dim<1>(2), 0., Inf, Continuous, "x");
const auto temporary_constraint = TempCtr(Row(x[0] + x[1], 1), GreaterThan);
const auto temporary_constraint = TempCtr(x[0] + x[1], GreaterOrEqual, 1);
model.add_ctr(temporary_constraint);
Here, we used the class :ref:`Row <api_Row>` to create the row associated to the constraint. The sign of the constraint is
Here, the sign of the constraint is
specified by the second argument of the constructor of the :ref:`TempCtr <api_TempCtr>` class, and can take values
:code:`LessThan`, :code:`GreaterThan` and :code:`EqualTo`.
:code:`LessOrEqual`, :code:`GreaterOrEqual` and :code:`EqualTo`.

Accessing Constraints
^^^^^^^^^^^^^^^^^^^^^

Information about a given constraint in a model can be accessed by calling the corresponding methods of the model.
The type of a constraint can be accessed by calling the :cpp:`Model::get_ctr_type` method. The row of a constraint can be
accessed by calling the :cpp:`Model::get_ctr_row` method.
For instance, one can access the right-hand side of a constraint by calling the :cpp:`Model::get_ctr_rhs` method.
Here is a list of the most common methods to access information about a constraint.

If a given model has been solved and feasibility could be proved (or better, optimality), the dual value of a constraint
can be accessed by calling the :cpp:`Model::get_ctr_dual` method.
For infeasible models, a Farkas certificate (dual ray) can be accessed by calling the :cpp:`Model::get_ctr_farkas` method.
- :code:`Model::get_ctr_rhs`: get the right-hand side of a constraint,
- :code:`Model::get_ctr_type`: get the type of a constraint,
- :code:`Model::get_ctr_row`: get the row of a constraint,
- :code:`Model::get_ctr_index`: get the index of a constraint.

The :cpp:`Model::has` method can be used to check if a given constraint is in the model.
When available, the values associated to the constraint in a given solution can be accessed in a similar way.
Here is a list of the most common methods to access information about a constraint in a solution.

The current index of a constraint in the model can be accessed by calling the :cpp:`Model::get_ctr_index` method.
Beware, however, that the index may change if the model is modified.
- :code:`Model::get_ctr_dual`: get the dual value of a constraint,
- :code:`Model::get_ctr_farkas`: get the Farkas certificate of a constraint (for infeasible systems).

The :cpp:`Model::has` method can be used to check if a given constraint is in the model.

For more details, see the :ref:`Model <api_Model>` class.

Modifying Constraints
^^^^^^^^^^^^^^^^^^^^^

The type of a constraint can be modified by calling the :cpp:`Ctr::set_ctr_type` method.
The value of the right-hand side of a constraint can be modified by calling the :cpp:`Ctr::set_rhs` method.
Similarly to accessing constraints, the attributes of a constraint can be modified by calling the corresponding methods of the model.
Here is a list of the most common methods to modify a constraint.

- :code:`Model::set_ctr_rhs`: set the right-hand side of a constraint,
- :code:`Model::set_ctr_type`: set the type of a constraint,
- :code:`Model::set_ctr_row`: set the row of a constraint.

The row of a constraint in the model can be modified by calling the :cpp:`Ctr::set_row` method.
For instance.

.. code:: cpp
Row row;
row.set_rhs(2);
row.linear().set(x, coefficient_for_x_in_constraint);
row.linear().set(y, coefficient_for_y_in_constraint);
LinExpr row;
row.set(x, coefficient_for_x_in_constraint);
row.set(y, coefficient_for_y_in_constraint);
constraint.set_ctr_row(constraint, row);
model.set_ctr_row(constraint, row);
For more details, see the :ref:`Model <api_Model>` class.

Expand All @@ -104,3 +128,14 @@ Removing Constraints

A constraint can be removed from a model by calling the :cpp:`Model::remove` method.

Quadratic Constraints
---------------------

Creating, accessing and modifying quadratic constraints is similar to linear constraints. The main difference is that
quadratic constraints are created using the :ref:`QCtr <api_QCtr>` class. Moreover, the corresponding methods in :code:`Model`
use :code:`qctr` instead of :code:`ctr`. For instance, the following code accesses the type of a quadratic constraint.

.. code::
model.get_qctr_type(quadratic_constraint);
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
The Environment
---------------
The Environment and the :code:`Env` class
-----------------------------------------

Every optimization object (such as variables and constraints) are managed by an "optimization environment".
It is the environment that controls the death and life of such objects. It is also through the environment that idol
Expand Down
93 changes: 46 additions & 47 deletions docs/tutorials/mixed-integer-programming/modeling/expressions.rst
Original file line number Diff line number Diff line change
@@ -1,80 +1,79 @@
Expressions
-----------
Expressions with the :code:`QuadExpr`, :code:`AffExpr` and :code:`LinExpr` Classes
==================================================================================

An expression generically refers to any mathematical expression involving variables or constraints. In idol, expressions
are represented by the :ref:`AffExpr <api_Expr>` class.
are represented by the :code:`QuadExpr`, :code:`AffExpr` and :code:`LinExpr` classes. These classes are used to represent
quadratic, affine and linear expressions, respectively.

An expression can be created by adding, subtracting or multiplying variables with constants or other expressions. For instance,
An expression can be created by adding, subtracting or multiplying variables together. For instance,
the following code creates the mathematical expression :math:`1 + 3 x_0 + x_1 + x_0 + 2 x_0 x_1`.

.. code:: cpp
const AffExpr expr = 1 + 3 * x[0] + x[1] + x[0] + 2 * x[0] * x[1];
std::cout << expr << std::endl; // "1 + 4 * x[0] + 1 * x[1] + 2 * x[0] * x[1]"
std::cout << expr << std::endl;
Expressions are composed of three parts:
* A constant (or offset) which is an instance of the :ref:`Constant <api_Constant>` class;
* A linear part which is an instance of the :ref:`LinExpr <api_LinExpr>` class;
* A quadratic part which is an instance of the :ref:`QuadExpr <api_QuadExpr>` class.
.. contents:: Table of Contents
:local:
:depth: 2

Each of these parts can be accessed using the methods :cpp:`AffExpr::constant`, :cpp:`AffExpr::linear` and :cpp:`AffExpr::quadratic`, respectively.
For instance, consider the following code.
:code:`LinExpr`: Linear Expressions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code-block:: cpp
The :code:`LinExpr` class is used to represent linear expressions. A linear expression is a mathematical expression
that is linear in the variables. For instance, the following code creates the mathematical expression :math:`1 + 3 x_0 + x_1`.

for (const auto& [var, coefficient] : expr.linear()) {
std::cout << var << " is multiplied by " << coefficient << std::endl;
}
.. code:: cpp
This code iterates over the linear part of the expression and prints the variables and their coefficients.
const LinExpr expr = 1 + 3 * x[0] + x[1];
std::cout << expr << std::endl; // "1 + 3 * x[0] + 1 * x[1]"
.. admonition:: About constants in expressions
.. admonition:: Linear in What?

Without going into too much detail, we should here precise that each constant multiplying a variable in an :cpp:`AffExpr`,
as well as the offset constant, can actually be composite. For instance, this is the case when a variable is multiplied by
a parameter which is considered fixed in the current model but cannot be evaluated at the time the expression is created.
Actually, :code:`LinExpr` is a template class with one parameter, which is the type of the "variables" in the linear expression.
For instance, it is possible de create a linear expression of :code:`Ctr` objects, which are constraints. The following code
creates the mathematical expression :math:`1 + 3 c_0 + c_1`.

Creating such "parameters" can be done by prepending a variable with the ``!`` symbol. This will automatically
create an instance of the :ref:`Param <api_Param>` class.
For instance, the following code creates
a constant which involves the variables :math:`\xi_0` and :math:`\xi_1`, viewed as parameters.
.. code:: cpp
.. code-block::
const LinExpr<Ctr> expr = 1 + 3 * c[0] + c[1];
Env env;
const Model model(env);
const auto x = model.add_vars(Dim<1>(2), 0., Inf, Continuous, "x");
std::cout << expr << std::endl; // "1 + 3 * c[0] + 1 * c[1]"
const Model model2(env);
const auto xi = model2.add_vars(Dim<1>(2), 0., 1., Continuous, "xi");
It is possible to iterate over the terms in the expression as follows.

const AffExpr expr = (1 + 2 * !xi[0]) * x[0] + 3 * !xi[1] * x[1];
.. code::
Here, ``1 + 2 * !xi_0`` is an instance of the ``Constant`` object and can be used as follows.
for (const auto& [var, constant] : expr) {
std::cout << constant << " multiplied by " << var << std::endl;
}
.. code-block::
:code:`AffExpr`: Affine Expressions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Constant constant = 1 + 2 * !xi_0;
The :code:`AffExpr` class is used to represent affine expressions. An affine expression is a mathematical expression
that is linear in the variables and has a constant term.

std::cout << constant.numerical() << std::endl; // output: 1
The linear part of the expression is accessed by the :code:`AffExpr::linear()` method, and the constant term is accessed
by the :code:`AffExpr::constant()` method.

for (const auto& [param, coeff] : constant) {
std::cout << coeff << " * " << param << std::endl; // output: 2 * !xi_0
}
:code:`QuadExpr`: Quadratic Expressions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Note that a parameter can be turned back into a variable by calling the :cpp:`Param::as<T>` template method.
See, for instance.
The :code:`QuadExpr` class is used to represent quadratic expressions. A quadratic expression is a mathematical expression
which contains an affine part and a quadratic part. The affine part can be accessed by the :code:`QuadExpr::affine()` method.

.. code-block:: cpp
It is possible to iterate over the terms in the quadratic part of the expression as follows.

const auto param = !xi[0];
.. code::
if (param.is<Var>()) {
const auto var = param.as<Var>();
// do somthing with the variable
}
for (const auto& [pair, constant] : expr) {
std::cout << constant << " multiplied by " << pair.first << " and " << pair.second << std::endl;
}
Parameters can be variables or constraints.
for (const auto& [var, constant] : expr.affine().linear()) {
std::cout << constant << " multiplied by " << var << std::endl;
}
5 changes: 2 additions & 3 deletions docs/tutorials/mixed-integer-programming/modeling/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
.. role:: cpp(code)
:language: cpp

Modeling
========
Modeling a MIP with idol
========================

This page introduces the basic concepts of modeling optimization problems in idol.
We will discuss how to create optimization models and add variables, constraints and objective functions to that model.
We will also see how to access the different components of an existing model.


All classes which are used for modeling (standard) optimization problems can be accessed by including :code:`#include <idol/modeling.h>`.

To simplify things, we will use the :code:`namespace idol` in the following examples. This dispenses us from prefixing
Expand Down
Loading

0 comments on commit 5fc7d1e

Please sign in to comment.