Note
Go to the end to download the full example code.
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
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
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)