CasADi
CasADi is an open-source symbolic framework for numerical optimization and automatic differentiation. It enables users to formulate complex optimization problems (e.g., optimal control, nonlinear programming) using symbolic expressions and then efficiently solve them using state-of-the-art numerical solvers. It is actively maintained with several releases per year. Current version: 3.7.2.
Warnings
- breaking Major API changes occurred between CasADi v2.x and v3.x. Code written for v2.x (e.g., using `SXFunction`, `MXFunction`, or older solver interfaces) will not directly work with v3.x.
- gotcha CasADi uses different symbolic types (`MX`, `SX`) and numerical types (`DM`, `DMatrix`). Mixing them or using the wrong type can lead to performance issues or errors. `MX` is generally recommended for complex NLPs and AD due to its flexibility, while `SX` is for highly sparse, structured problems.
- gotcha CasADi functions are often JIT-compiled to C code. Errors in symbolic expressions might only surface during the compilation step when a function is constructed (e.g., `ca.Function(...)` or `ca.nlpsol(...)`), not necessarily when the symbolic expression is initially defined.
Install
-
pip install casadi
Imports
- casadi
import casadi as ca
- Function
solver = ca.nlpsol(...)
Quickstart
import casadi as ca
import numpy as np
# Declare symbolic variables
x = ca.MX.sym("x")
y = ca.MX.sym("y")
# Define objective function (e.g., Rosenbrock function)
f = (x - 1)**2 + 10*(y - x**2)**2
# Define constraints (e.g., x + y >= 0)
g = x + y
# Formulate NLP problem
nlp = {'x': ca.vertcat(x,y), 'f': f, 'g': g}
# Choose a solver (IPOPT is common, ensure it's available)
solver_opts = {'ipopt': {'print_level': 0}, 'print_time': 0}
solver = ca.nlpsol('solver', 'ipopt', nlp, solver_opts)
# Solve the NLP
# Set lower/upper bounds for variables (lbx, ubx) and constraints (lbg, ubg)
sol = solver(
lbx=[-ca.inf, -ca.inf], ubx=[ca.inf, ca.inf],
lbg=[0], ubg=[ca.inf] # g >= 0
)
print(f"Optimal solution x: {sol['x'].full().flatten()}")
print(f"Optimal objective f: {sol['f'].full().item()}")