ProxSuite

repository·devel·Indexed 20 days ago

https://github.com/simple-robotics/proxsuite

A collection of efficient, numerically robust, and scalable numerical solvers for Linear Programs (LPs) and Quadratic Programs (QPs) based on primal-dual proximal algorithms. Designed for high-performance robotics applications, it supports dense, sparse, and matrix-free problems. It includes ProxQP for solving convex quadratic programs and QPLayer for integrating QPs as layers within PyTorch machine learning architectures.

Tokens
12K
Snippets
23
Records
44
Agent score
70%

What's inside proxsuite

  1. What is ProxQP?

    devel

    ProxQP is a numerical optimization approach within ProxSuite designed to solve Quadratic Programming (QP) problems of the form:

    $$\min_{x} , \frac{1}{2}x^{T}Hx+g^{T}x$$ $$\text{s.t.} , A x = b$$ $$\text{s.t.} , l \leq C x \leq u$$

    Where:

    • $x \in \mathbb{R}^n$ is the optimization variable.
    • $H \in \mathcal{S}^n_+$ is a positive semidefinite matrix.
    • $g \in \mathbb{R}^n$ is a vector.
    • $A \in \mathbb{R}^{n_{\text{eq}} \times n}$ is the equality-constraint matrix.
    • $C \in \mathbb{R}^{n_{\text{in}} \times n}$ is the inequality-constraint matrix.
    • $b, l, u$ are the corresponding constraint vectors.
  2. What is QPLayer?

    devel

    QPLayer is a component that enables using a Quadratic Program (QP) as a layer within standard machine learning architectures. It is interfaced with PyTorch and allows for parallelized calculus over CPUs.

    Key capabilities include:

    • Differentiating over parameters $\theta$ for both primal and dual solutions.
    • Differentiating over Linear Programs (LPs).
    • Learning structured architectures (e.g., learning elements of the constraint matrix $A$ while keeping $b$ fixed).
  3. Understand ProxQP timing and benchmarking

    devel

    When benchmarking ProxQP against other solvers, use results.info.run_time (the sum of setup_time and solve_time).

    ProxQP's timing breakdown is:

    • setup_time: Measures model initialization and preconditioning (if activated).
    • solve_time: Measures everything else, including the first matrix factorization.

    Warning: Some solvers (like OSQP) include the first factorization in their setup_time. To ensure a fair comparison, always compare the total runtime (setup + solve) of ProxQP against the total runtime of the other solver.

  4. Handle primal infeasibility with ProxQP

    devel
    ProxQP includes a specific feature for handling primal infeasibility. If the solver detects that the problem is primal infeasible, it will automatically solve for the closest primal feasible problem in the $\ell_2$ sense. The returned primal-dual triplet $(x, y, z)$ will satisfy the optimality conditions for this modified problem.
  5. Choose an initial guess strategy for ProxQP

    devel

    The solver supports five initial guess strategies to manage warm starting for the variables $x$, $y$, and $z$:

    • NO_INITIAL_GUESS: Starts with $x, y, z$ as the zero vector.
    • EQUALITY_CONSTRAINED_INITIAL_GUESS: Solves a specific system for $x$ and $y$ at the start (where $z=0$). This is generally effective for warm starting equality-constrained QPs.
    • WARM_START_WITH_PREVIOUS_RESULT: (Default) Uses the values from the previous solve for $x, y, z$ and retains the previous solver parameters (like proximal step sizes and Cholesky factorization). This is ideal for optimal control problems where the problem changes only slightly between steps. If matrices or parameters change, the solver automatically refactorizes the Cholesky factorization.
    • WARM_START: Expects the user to provide a warm start directly in the solve method call. You do not need to manually set this in the settings; the solver handles the internal state change when you pass a warm start to solve.
    • COLD_START_WITH_PREVIOUS_RESULT: (Note: Full details for this option were not provided in the source segment).
    // Example of setting WARM_START manually in C++ (though often unnecessary if using the solve method correctly)
    Qp.settings.initial_guess = proxsuite::qp::InitialGuessStatus::WARM_START;
  6. How the duality gap affects convergence in ProxQP

    devel

    By default, ProxQP stops based on primal and dual residuals (using the $L_ ext{inf}$ norm). However, satisfying residual criteria alone does not guarantee optimality. To ensure a stronger guarantee, you can enable the check_duality_gap option.

    When check_duality_gap is True, the solver also checks the duality gap $r_g$ against absolute and relative thresholds (eps_duality_gap_abs and eps_duality_gap_rel).

    Recommendation for thresholds: Because the duality gap scales with the square root of the problem dimension, it is numerically harder to achieve for large problems. A recommended setting for the absolute duality gap threshold is: $$\epsilon^{\text{gap}}{\text{abs}} = \epsilon{\text{abs}} \sqrt{\max(n, n_{\text{eq}}, n_{\text{ineq}})}$$

  7. Choose between Sparse and Dense backends

    devel

    ProxQP provides both sparse and dense backends. Use the following heuristic to choose:

    Use the Dense backend if your problem is:

    1. Relatively small (less than a few thousand variables).
    2. Relatively dense (sparsity ratio of matrices is greater than 0.1).

    Sparsity ratio is calculated as: $$\text{sparsity}(A) = \frac{\text{nnz}(A)}{\text{number}{\text{row}}(A) * \text{number}{\text{col}}(A)}$$

  8. Enable duality gap checking for stronger optimality guarantees

    devel

    By default, ProxQP checks convergence based on primal and dual residuals. However, checking residuals alone does not guarantee that the KKT conditions are fully satisfied.

    To ensure a stronger guarantee of optimality, enable the check_duality_gap option in the settings. This includes the duality gap ($r_g$) in the stopping criterion, similar to the SCS solver.

    Recommendation: Because the duality gap scales with the square root of the problem dimension, it is numerically harder to achieve than residual targets. A recommended setting for the absolute duality gap threshold is: $$\epsilon^{\text{gap}}{\text{abs}} = \epsilon{\text{abs}} \sqrt{\max(n, n_{\text{eq}}, n_{\text{ineq}})}$$

  9. Use QPLayer for differentiable quadratic programming in learning architectures

    devel

    QPLayer allows you to integrate a Quadratic Program (QP) as a differentiable layer within standard machine learning architectures. It enables differentiation with respect to the parameters $\theta$ that define the QP problem components.

    Specifically, it handles QPs of the form:

    $$\min_{x} \frac{1}{2}x^{T}H(\theta)x+g(\theta)^{T}x$$ $$\text{s.t.} \quad A(\theta) x = b(\theta)$$ $$\quad \quad l(\theta) \leq C(\theta) x \leq u(\theta)$$

    Where:

    • $x \in \mathbb{R}^n$ is the optimization variable.
    • $H(\theta) \in \mathcal{S}^n_+$ is a positive semidefinite matrix.
    • $g(\theta) \in \mathbb{R}^n$ is a vector.
    • $A(\theta) \in \mathbb{R}^{n_{\text{eq}} \times n}$ is the equality-constraint matrix.
    • $C(\theta) \in \mathbb{R}^{n_{\text{in}} \times n}$ is the inequality-constraint matrix.
    • $b(\theta)$, $l(\theta)$, and $u(\theta)$ are the constraint vectors.

    To use this in a PyTorch-based learning pipeline, use the QPFunction class located in proxsuite.torch.qplayer.

    from proxsuite.torch.qplayer import QPFunction
    
    # QPFunction is the core implementation of the differentiable QP layer
  10. Understand the ProxQP solver workflow

    devel

    The ProxQP solver follows a standard lifecycle for solving convex Quadratic Programs (QPs):

    1. Problem Generation: Define the QP problem (primal variables, equality constraints, and inequality constraints).
    2. Initialization: Create a solver object (e.g., Qp) specifying the dimensions:
      • n: dimension of primal variable x.
      • n_eq: number of equality constraints.
      • n_in: number of inequality constraints.
    3. Configuration: Set solver settings such as accuracy_threshold and verbose (to control output).
    4. Solve: Call the .init() method to load the problem and the .solve() method to compute the solution.
    5. Results: Access the solution and metadata via the .results attribute.

    API Differences: C++ vs Python

    • C++: Uses Eigen objects for matrices and vectors. The API is fully template-based for maximum efficiency.
    • Python: The API mirrors the C++ interface but uses NumPy matrices and vectors instead of Eigen.
  11. Warm start the ProxQP solver with previous results

    devel

    To speed up runtime in optimal control-like problems where the next problem is similar to the previous one, you can enable warm starting.

    When this option is set, the solver warms starts the primal solution x, equality multiplier y, and inequality multiplier z with the values from the previous solve.

    Note: Unlike the WARM_START_WITH_PREVIOUS_RESULT option, this specific warm start resets all other parameters (such as proximal step sizes and the full workspace/LDLT factorization) to their default values. This means a new factorization is performed, but it takes the z warm start into account for the active set.

    At the first solve, x, y, and z are initialized to the zero vector.

  12. Choose between PrimalDualLDLT and PrimalLDLT backends

    devel

    The dense version of ProxQP offers two specialized backends. While the constructor uses a heuristic to choose automatically, you can specify one manually for better performance or accuracy:

    • PrimalDualLDLT: Factorizes a regularized version of the KKT system. It provides high accuracy and stability. It is slower if the primal dimension ($n$) is significantly smaller than the number of constraints.
    • PrimalLDLT: Factorizes the matrix $H+\rho I+\frac{1}{\mu_{eq}} A^\top A$ and uses rank-one updates. It is faster when the primal dimension is much smaller than the constraint dimensions, but it is less accurate than PrimalDualLDLT.
    # Example: Specifying a backend in Python
    # (Note: Actual syntax depends on the specific implementation of the constructor)
    qp = ProxQP.dense(n, n_eq, n_in, backend='PrimalLDLT')