A mixed integer linear programming example#

In this example, we show how to formualte and solve a simple mixed integer linear programming (MILP) problem via csnlp. This simple problem, taken from here, is

\[\begin{split}\begin{aligned} \max_{x, y \in \mathbb{Z}} \quad & y \\ \textrm{s.t.} \quad & -x + y \leq 1 \\ & 3 x + 2 y \leq 12 \\ & 2 x + 3 y \leq 12 \\ & x, y \geq 0. \end{aligned}\end{split}\]

The focus here is on how to formulate mixed integer problems, so for more basic usage of the library, please refer to the other Introductory examples.

Creating the problem#

We can create the problem as usual, but we need to specify that (some of) the primal variables are discrete. This is done by passing the corresponding domain` argument when creating each variable. The rest of the problem formulation is standard.

import casadi as cs

from csnlp import Nlp

nlp = Nlp[cs.MX](sym_type="MX")
x = nlp.variable("x", lb=0, discrete=True)[0]
y = nlp.variable("y", lb=0, discrete=True)[0]

nlp.minimize(-y)
_, _ = nlp.constraint("con1", -x + y, "<=", 1)
_, _ = nlp.constraint("con2", 3 * x + 2 * y, "<=", 12)
_, _ = nlp.constraint("con3", 2 * x + 3 * y, "<=", 12)

Solving the problem#

However, pay attention: now we have to initialize a suitable solver. For example, we can use the cbc solver, which is an open-source mixed integer linear programming solver. We get a solution as usual by calling csnlp.Nlp.solve.

nlp.init_solver(solver="cbc")
sol = nlp.solve()
Welcome to the CBC MILP Solver
Version: 2.10.11
Build Date: Sep  9 2025

command line - CbcInterface -solve -quit (default strategy 1)
Integer solution of -2 found by DiveCoefficient after 0 iterations and 0 nodes (0.00 seconds)
Search completed - best objective -2, took 0 iterations and 0 nodes (0.00 seconds)
Maximum depth 0, 0 variables fixed on reduced cost
Cuts at root node changed objective from -2.8 to -2.8
Probing was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
Gomory was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
Knapsack was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
Clique was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
MixedIntegerRounding2 was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
FlowCover was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
TwoMirCuts was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
ZeroHalf was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)

Result - Optimal solution found

Objective value:                -2.00000000
Enumerated nodes:               0
Total iterations:               0
Time (CPU seconds):             0.00
Time (Wallclock seconds):       0.00

Total time (CPU seconds):       0.00   (Wallclock seconds):       0.00

We expect the optimal point to be either \((x^\star, y^\star) = (1, 2)\) or \((x^\star, y^\star) = (2, 2)\).

print(sol.vals)
{'x': DM(1), 'y': DM(2)}

A mixed integer quadratic programming (MIQP) example#

We are not limited to MILP. Unfortunatelly, that is only what cbc can handle. In case of more general mixed integer problems, we can use the bonmin solver, which can solve mixed integer nonlinear programs (MINLP). For example, let’s consider the following MIQP problem

\[\min_{x \in \mathbb{Z}^n}{ \lVert A x - b \rVert_2^2 }\]

The following code is very similar to the MILP case.

import numpy as np

m, n = 10, 5
A = np.random.rand(m, n)
b = np.random.randn(m)

nlp = Nlp[cs.MX](sym_type="MX")
x = nlp.variable("x", (n, 1), discrete=True)[0]
nlp.minimize(cs.sumsqr(A @ x - b))
nlp.init_solver(solver="bonmin")
sol = nlp.solve()

print(sol.vals["x"])
NLP0012I
              Num      Status      Obj             It       time                 Location
NLP0014I             1         OPT 8.3815354        1 0.000788
NLP0014I             2         OPT 8.6207755        4 0.000602
NLP0014I             3         OPT 8.7308335        4 0.001001
NLP0014I             4         OPT 8.4910848        3 0.000797
NLP0014I             5         OPT 8.661836        3 0.000788
NLP0014I             6         OPT 8.411657        4 0.001009
NLP0014I             7         OPT 8.6144912        3 0.000759
NLP0014I             8         OPT 8.6938572        3 0.000751
NLP0014I             9         OPT 8.4043991        4 5.3e-05
NLP0014I            10         OPT 9.586314        5 0.001204
NLP0014I            11         OPT 8.4336099        4 0.001006
Cbc0010I After 0 nodes, 1 on tree, 1e+50 best solution, best possible -1.7976931e+308 (0.01 seconds)
NLP0014I            12         OPT 8.4336099        4 0.001001
NLP0014I            13         OPT 9.586314        5 0.001218
NLP0014I            14         OPT 8.7302447        4 0.000312
NLP0014I            15         OPT 8.7438724        4 0.001009
NLP0014I            16         OPT 8.8324389        4 0.001004
NLP0014I            17         OPT 9.1785591        5 0.001242
NLP0014I            18         OPT 8.8628383        6 0.000538
NLP0014I            19         OPT 9.1777779        4 0.001153
NLP0014I            20         OPT 8.9353513        8 0.000959
NLP0012I
              Num      Status      Obj             It       time                 Location
NLP0014I             1         OPT 8.9353514        0 0
Cbc0004I Integer solution of 8.9353514 found after 44 iterations and 9 nodes (0.02 seconds)
NLP0012I
              Num      Status      Obj             It       time                 Location
NLP0014I            21         OPT 8.746384        4 0.001029
NLP0014I            22         OPT 9.6258296        5 0.001225
NLP0014I            23         OPT 8.8559854        4 0.001019
NLP0014I            24         OPT 9.0127321        5 0.001379
NLP0014I            25         OPT 8.9189031        5 0.00124
NLP0014I            26         OPT 10.133111        7 0.001709
NLP0014I            27         OPT 8.9243344        5 0.00126
NLP0014I            28         OPT 10.054117        6 0.001443
NLP0014I            29         OPT 8.9442353        4 0.00099
NLP0014I            30         OPT 10.078136        6 0.00145
NLP0014I            31         OPT 9.655213        6 0.001474
Cbc0001I Search completed - best objective 8.935351358570609, took 101 iterations and 20 nodes (0.04 seconds)
Cbc0032I Strong branching done 5 times (37 iterations), fathomed 0 nodes and fixed 0 variables
Cbc0035I Maximum depth 6, 0 variables fixed on reduced cost
solver_bonmin_Nlp3  :   t_proc      (avg)   t_wall      (avg)    n_eval
             nlp_f  | 717.00us (  4.19us) 592.65us (  3.47us)       171
             nlp_g  |   1.00us (  1.00us)   1.28us (  1.28us)         1
        nlp_grad_f  | 725.00us (  3.28us) 681.47us (  3.08us)       221
        nlp_hess_l  | 660.00us (  4.75us) 675.56us (  4.86us)       139
             total  |  46.99ms ( 46.99ms)  46.99ms ( 46.99ms)         1
[0, -2, 0, 0, 2]

Total running time of the script: (0 minutes 0.063 seconds)

Gallery generated by Sphinx-Gallery