Open-source SQP solver with L-BFGS Hessian, filter line search, and first-class warm-starting
Project description
pyfiltersqp
Open-source SQP (Sequential Quadratic Programming) solver in Python with L-BFGS Hessian approximation, l₁-merit and filter line searches, and first-class warm-starting. Faster than IPOPT on most CUTEst problems we've benchmarked.
Why
The open-source NLP ecosystem is dominated by interior-point methods (IPOPT, ECOS, Clarabel). For SQP there's no modern, MIT-licensed, Python-friendly option with sparse Jacobians and warm-starting baked in. This fills that gap.
Headline benchmarks
vs cyipopt IPOPT on the classical CUTEst deck (47 problems, n up to 5000):
| problem | n | pyfiltersqp | IPOPT | speedup |
|---|---|---|---|---|
| ARWHEAD | 5000 | 1.9 ms | 132 ms | 70× |
| EXTROSNB | 1000 | 9.4 ms | 402 ms | 43× |
| HS25 | 3 | 0.1 ms | (fails) | wins outright |
| TQUARTIC | 5000 | 23 ms | 277 ms | 12× |
| ROSENBR | 2 | 3.4 ms | 35 ms | 10× |
| HS71 | 4 | 1.3 ms | 4.9 ms | 3.7× |
41 of 45 successfully-solved problems beat IPOPT, by 1.3× – 70×.
See scripts/bench_cutest.py for the harness.
Install
pip install pyfiltersqp # core
pip install "pyfiltersqp[numba]" # +Numba JIT (2× faster L-BFGS recursion)
pip install "pyfiltersqp[dev]" # +pytest for development
Requires Python ≥ 3.11. Core deps: numpy, scipy, osqp.
Quick start
import numpy as np
from pyfiltersqp import NLPProblem, solve
# HS71 — the classic 4-var SQP demo problem.
problem = NLPProblem(
n=4, m_eq=1, m_ineq=1,
xl=np.ones(4), xu=5 * np.ones(4),
objective = lambda x: x[0]*x[3]*(x[0]+x[1]+x[2]) + x[2],
gradient = lambda x: np.array([
x[3]*(2*x[0]+x[1]+x[2]),
x[0]*x[3],
x[0]*x[3] + 1,
x[0]*(x[0]+x[1]+x[2]),
]),
eq_constraints = lambda x: np.array([x[0]**2+x[1]**2+x[2]**2+x[3]**2 - 40]),
eq_jacobian = lambda x: np.array([[2*x[0], 2*x[1], 2*x[2], 2*x[3]]]),
ineq_constraints = lambda x: np.array([25 - x[0]*x[1]*x[2]*x[3]]),
ineq_jacobian = lambda x: np.array([[
-x[1]*x[2]*x[3], -x[0]*x[2]*x[3],
-x[0]*x[1]*x[3], -x[0]*x[1]*x[2],
]]),
)
result = solve(problem, x0=np.array([1., 5., 5., 1.]))
print(result.success, result.obj) # True, 17.014017...
Algorithm
- Outer: Sequential Quadratic Programming with l₁-merit Armijo line search; filter line search opt-in (Fletcher & Leyffer, 2002) for degenerate problems.
- Hessian: L-BFGS with Powell damping. Optional Numba JIT for the forward recursion. Compact (Byrd-Lu-Nocedal-Zhu) representation under the hood.
- QP backend (auto-selected by problem shape):
ImplicitLBFGSQP— primal-dual active-set + Schur complement, appliesB⁻¹via the L-BFGS two-loop recursion in O(n·m) without ever forming the densen×nHessian. Best for small-to-medium n with few active constraints.WoodburyADMM— Woodbury-identity ADMM on the compact L-BFGS factors, polished via a Schur solve on the inferred active set. Cost per ADMM step is O(n·m) and independent of the active set. Best for large n or many constraints.OSQP— the original v0.1 path. Retained as a deprecated fallback; every benchmark we've run is faster on the implicit / Woodbury paths.
- Robustness: second-order correction on Maratos-class line search collapse, mid-solve fallback to filter on stagnation, anti-cycling (Bland's rule + one-step tabu) in active-set, watchdog reset of L-BFGS on tiny-α streaks.
See DESIGN.md for the full algorithm specification.
Warm-starting
Designed for iterative MPCC strategies and homotopy methods where the constraint set changes slightly between solves:
result1 = solve(problem_v1, x0)
result2 = solve(problem_v2,
x0=result1.x,
lam_eq0=result1.lam_eq,
lam_ineq0=result1.lam_ineq)
Roadmap
See ROADMAP.md and CHANGELOG.md. The next
real-engineering items are PyPI publish (this commit), Woodbury custom KKT
solver inside OSQP for the n > 1000 range, and a projected-CG QP path for
n > 10 000.
References
- Nocedal & Wright, Numerical Optimization, 2nd ed. (2006) — chapters 18 (SQP), 7 (L-BFGS)
- Fletcher & Leyffer (2002), "Nonlinear programming without a penalty function" — filter line search
- Byrd, Lu, Nocedal & Zhu (1994), "Representations of quasi-Newton matrices and their use in limited memory methods" — compact L-BFGS
- Powell (1978), "A fast algorithm for nonlinearly constrained optimization calculations" — damped BFGS
- Stellato et al. (2020), OSQP
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyfiltersqp-0.3.0.tar.gz.
File metadata
- Download URL: pyfiltersqp-0.3.0.tar.gz
- Upload date:
- Size: 65.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ac88e1ff025b21ab66de527c25fb0eb054b47bfd671e4a4099d81560918db3f0
|
|
| MD5 |
682f90fa999edc8b9edec30db5c8b4b0
|
|
| BLAKE2b-256 |
46ad23a960e373c0fe1c0e659f7510ca694f03f98566377bb02346e73981a5e7
|
File details
Details for the file pyfiltersqp-0.3.0-py3-none-any.whl.
File metadata
- Download URL: pyfiltersqp-0.3.0-py3-none-any.whl
- Upload date:
- Size: 45.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d38140c528cef8e2a57edd49efacc94a35a37aadf3e2824914c73b8d9da3a1e7
|
|
| MD5 |
883e27e047d59002e9f867c75f971387
|
|
| BLAKE2b-256 |
264398300f2b7dfb28f7369e39269d04bfd8ddf8d819534a76ec7d040c5a0fc6
|