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 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)