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 7.1634461        1 0.000768
NLP0014I             2         OPT 7.3931981        3 0.000277
NLP0014I             3         OPT 7.4294776        4 0.001024
NLP0014I             4         OPT 7.3116311        4 0.001007
NLP0014I             5         OPT 7.391059        3 0.000778
NLP0014I             6         OPT 7.4267658        3 0.000771
NLP0014I             7         OPT 7.3226671        3 0.000926
NLP0014I             8         OPT 7.2178235        4 0.001002
NLP0014I             9         OPT 7.317799        4 0.000996
NLP0014I            10         OPT 7.1673877        4 3.4e-05
NLP0014I            11         OPT 7.5241396        3 0.000875
Cbc0010I After 0 nodes, 1 on tree, 1e+50 best solution, best possible -1.7976931e+308 (0.01 seconds)
NLP0014I            12         OPT 7.3931981        3 0
NLP0014I            13         OPT 7.4294776        4 0.000999
NLP0014I            14         OPT 7.519926        3 0.000784
NLP0014I            15         OPT 7.7069707        4 1e-06
NLP0014I            16         OPT 7.6334899        4 0.000995
NLP0014I            17         OPT 7.827939        4 0.001024
NLP0014I            18         OPT 7.7285696        5 0.001314
NLP0014I            19         OPT 8.1883194        5 0.001247
NLP0014I            20         OPT 7.7289256        8 0.001921
NLP0012I
              Num      Status      Obj             It       time                 Location
NLP0014I             1         OPT 7.7289256        0 0
Cbc0004I Integer solution of 7.7289256 found after 40 iterations and 9 nodes (0.02 seconds)
NLP0012I
              Num      Status      Obj             It       time                 Location
NLP0014I            21         OPT 7.6310256        4 0.001006
NLP0014I            22         OPT 7.647755        3 0.000867
NLP0014I            23         OPT 7.7408105        4 0.001066
NLP0014I            24         OPT 7.945347        5 0.001246
NLP0014I            25         OPT 7.744171        4 0.001009
NLP0014I            26         OPT 8.0432648        5 0.001259
NLP0014I            27         OPT 7.9033191        5 0.001269
NLP0014I            28         OPT 7.9084546        4 0.001021
NLP0014I            29         OPT 8.2760625        6 0.001601
Cbc0001I Search completed - best objective 7.728925639068868, took 80 iterations and 18 nodes (0.03 seconds)
Cbc0032I Strong branching done 5 times (35 iterations), fathomed 0 nodes and fixed 0 variables
Cbc0035I Maximum depth 4, 0 variables fixed on reduced cost
solver_bonmin_Nlp3  :   t_proc      (avg)   t_wall      (avg)    n_eval
             nlp_f  | 596.00us (  4.08us) 525.45us (  3.60us)       146
             nlp_g  |   1.00us (  1.00us)   1.37us (  1.37us)         1
        nlp_grad_f  | 643.00us (  3.40us) 618.78us (  3.27us)       189
        nlp_hess_l  | 576.00us (  4.97us) 561.77us (  4.84us)       116
             total  |  41.19ms ( 41.19ms)  41.19ms ( 41.19ms)         1
[0, -3, 3, 1, 0]

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

Gallery generated by Sphinx-Gallery