DAQP: Dual Active-Set QP Solver
DAQP is a dual active-set solver designed for convex quadratic programs (QPs), including mixed-integer QPs (MIQPs) and hierarchical QPs (HQPs). Written in C and library-free, it provides high-performance interfaces for Python, Julia, and MATLAB. It excels at solving small to medium-scale, dense QP and LP problems, particularly those arising in real-time Model Predictive Control (MPC) applications. The current version is 0.8.5, with frequent releases addressing improvements and bug fixes.
Common errors
-
ModuleNotFoundError: No module named 'daqp'
cause The DAQP library is not installed in the current Python environment.fixRun `pip install daqp` to install the package. -
AttributeError: module 'daqp' has no attribute 'solve'
cause You are trying to call a function or access an attribute that does not exist or is not exposed in the `daqp` module, or you are using an outdated version where the API differs.fixCheck the official DAQP documentation or GitHub repository for the correct function names and usage for your installed version. Ensure your `daqp` package is up-to-date (`pip install --upgrade daqp`). The main solver function is `daqp.solve`. -
ValueError: expected array of shape (N,) for f, got (N, M)
cause Commonly occurs when input arrays for `f`, `bl`, `bu`, `l`, or `u` (which should be 1D vectors) are provided as 2D arrays (e.g., `(N, 1)` matrices from NumPy operations).fixEnsure all vector inputs (`f`, `bl`, `bu`, `l`, `u`) are 1D NumPy arrays. Use `.flatten()` or `.squeeze()` on 2D arrays, or initialize them directly as 1D arrays, e.g., `np.array([1, 2, 3])` instead of `np.array([[1], [2], [3]])`.
Warnings
- breaking The Python interface was re-implemented in Cython in v0.5.0, potentially breaking existing code that relied on the previous Python bindings. Additionally, the detection of binary constraints from the 'sense' parameter was introduced.
- gotcha DAQP is highly optimized for small to medium-scale, dense quadratic programs. Its performance and suitability for large-scale or sparse problems may be significantly limited. For sparse problems, consider other solvers like OSQP.
- breaking Starting from v0.8.3, the Hessian matrix `H` is explicitly symmetrized in-place (as `0.5 * (H + H.T)`) during the solver setup. If your application relies on an asymmetric `H` being passed and processed in a specific non-symmetrized manner, this behavior change might impact results.
- deprecated Features such as warm-starting with primal/dual iterates and setting a `time_limit` were introduced in v0.8.1. These functionalities are not available in earlier versions of the library.
Install
-
pip install daqp
Imports
- daqp
from daqp import solve
import daqp
- solve
daqp.solve(H, f, A, bl, bu)
Quickstart
import numpy as np
import daqp
# Define a simple QP: min 0.5*x'*H*x + f'*x s.t. bl <= A*x <= bu, l <= x <= u
H = np.array([[2.0, 0.0], [0.0, 2.0]]) # Hessian (positive definite)
f = np.array([-2.0, -2.0]) # Linear term
A = np.array([[1.0, 0.0], [0.0, 1.0], [1.0, 1.0]]) # Constraint matrix
bl = np.array([0.0, 0.0, 0.0]) # Lower bound for A*x
bu = np.array([10.0, 10.0, 1.0]) # Upper bound for A*x
# No explicit bounds on x (l, u can be omitted or set to -inf, +inf)
x_min = np.full(H.shape[0], -np.inf) # Lower bound for x
x_max = np.full(H.shape[0], np.inf) # Upper bound for x
# Solve the QP problem
# Note: H, f, A, bl, bu are the minimum required arguments. l and u can be passed if needed.
result = daqp.solve(H, f, A, bl, bu)
if result.exitflag == 1: # exitflag 1 means optimal solution found
print(f"Optimal solution x: {result.x}")
print(f"Optimal objective value: {result.fval}")
print(f"Number of iterations: {result.iter}")
else:
print(f"Solver failed with exitflag: {result.exitflag}")
print(f"Result details: {result}")