Solvers¶
CVXPYlayers supports multiple solver backends for different use cases.
Available Solvers¶
Solver |
Type |
Best For |
|---|---|---|
diffcp w/ SCS (default) |
CPU |
General use, most problem types |
diffcp w/ Clarabel |
CPU |
Higher accuracy |
CPU/GPU |
Best performance |
|
MPAX* |
CPU |
LPs/QPs |
CuClarabel w/ diffqcp |
GPU |
Open-source GPU alternative |
* Gradient support is currently broken.
Specifying a Solver¶
At Construction¶
import cvxpy as cp
from cvxpylayers.torch import CvxpyLayer
layer = CvxpyLayer(
problem,
parameters=[A, b],
variables=[x],
solver=cp.DIFFCP,
solver_args={'solver': cp.CLARABEL} # Use Clarabel
)
At Call Time¶
# Use default solver
(x,) = layer(A_tensor, b_tensor)
# Override with different solver
(x,) = layer(A_tensor, b_tensor, solver_args={"solver": cp.SCS})
Specifying a Custom Solver¶
From a pair of plain NumPy callables¶
import cvxpy as cp
from cvxpylayers.torch import CvxpyLayer
from cvxpylayers.interfaces import SolverInterface
custom_solver = SolverInterface.from_functions(
solve, # (P, q, A, dims, solver_args, needs_grad) -> (primal, dual, state)
derivative # (dprimal, ddual, state) -> (dP, dq, dA)
)
layer = CvxpyLayer(
problem,
parameters=[A, b],
variables=[x],
solver=custom_solver,
)
Here, P, q, and A are flattened NumPy arrays containing the canonical problem data,
dims describes the cone dimensions, needs_grad signals whether the backward pass
will run; state is whatever your solve wants to hand to derivative (can be
skipped if needs_grad=False); dprimal, ddual are upstream cotangents for the
primal and dual solutions.
From a pair of functions operating on the CVXPY problem¶
import cvxpy as cp
from cvxpylayers.torch import CvxpyLayer
from cvxpylayers.interfaces import SolverInterface
custom_solver = SolverInterface.from_parametric_functions(
solve, # problem -> objective_value
# reads .value from params; writes .value to vars
solve_and_state, # like solve but returns (objective_value, state)
gradient # (problem, state) -> None
# reads .gradient from vars; writes .gradient to params
)
layer = CvxpyLayer(
problem,
parameters=[A, b],
variables=[x],
solver=custom_solver,
)
From a pair of functions generated by CVXPYgen¶
import cvxpy as cp
from cvxpylayers.torch import CvxpyLayer
from cvxpylayers.interfaces import SolverInterface
from generated_code.cpg_solver import forward, backward
custom_solver = SolverInterface.from_codegen(forward, backward)
layer = CvxpyLayer(
problem,
parameters=[A, b],
variables=[x],
solver=custom_solver,
)
Solver Arguments¶
Pass solver-specific settings via solver_args:
# At construction (defaults for all calls)
layer = CvxpyLayer(
problem,
parameters=[A, b],
variables=[x],
solver_args={"max_iters": 5000, "eps": 1e-8}
)
# At call time (override for this call)
(x,) = layer(A_tensor, b_tensor, solver_args={"max_iters": 10000})
Common Arguments¶
Argument |
Solver |
Description |
|---|---|---|
|
SCS, Clarabel |
Convergence tolerance |
|
All |
Maximum iterations |
|
All |
Print solver output |
|
SCS |
Anderson acceleration window |
SCS Tuning¶
SCS is robust but may need tuning for difficult problems:
# Recommended settings for convergence issues
solver_args = {
"eps": 1e-8, # Tighter tolerance
"max_iters": 10000, # More iterations
"acceleration_lookback": 0 # Disable acceleration (more stable)
}
(x,) = layer(A_tensor, b_tensor, solver_args=solver_args)
If SCS still struggles, try Clarabel:
# Clarabel for better cone support
layer = CvxpyLayer(problem, parameters=[A, b], variables=[x], solver=cp.CLARABEL)
Moreau¶
Moreau is the recommended solver for best performance on both CPU and GPU.
It supports PyTorch and JAX with native autograd integration, warm starts, and jax.jit compatibility.
Setup¶
Moreau is available by request through a private package index. See the Moreau installation guide for access and setup instructions.
Usage (PyTorch)¶
import cvxpy as cp
import torch
from cvxpylayers.torch import CvxpyLayer
layer = CvxpyLayer(
problem,
parameters=[A, b],
variables=[x],
solver="MOREAU"
)
A_tch = torch.randn(m, n, requires_grad=True)
b_tch = torch.randn(m, requires_grad=True)
(x_sol,) = layer(A_tch, b_tch)
x_sol.sum().backward()
Usage (JAX)¶
import cvxpy as cp
import jax
from cvxpylayers.jax import CvxpyLayer
layer = CvxpyLayer(
problem,
parameters=[A, b],
variables=[x],
solver="MOREAU"
)
A_jax = jax.random.normal(jax.random.PRNGKey(0), shape=(m, n))
b_jax = jax.random.normal(jax.random.PRNGKey(1), shape=(m,))
(x_sol,) = layer(A_jax, b_jax)
Warm Starts¶
Moreau supports warm starting to speed up sequential solves:
(x_sol,) = layer(A_tch, b_tch, warm_start=True)
When to Use Moreau¶
Moreau is beneficial when:
You want the best solve + differentiation performance
You need
jax.jitcompatibilityYou’re solving sequences of similar problems (warm starts)
You want CPU or GPU support without Julia dependencies
CuClarabel (Open-Source Alternative)¶
CuClarabel is an open-source GPU solver alternative. It requires Julia and several additional dependencies. For NVIDIA GPUs, it keeps all data on the GPU:
See Installation for CuClarabel setup instructions.
Troubleshooting¶
Solver Failed¶
SolverError: Solver 'SCS' failed. Try another solver or adjust solver settings.
Solutions:
Try a different solver
Increase
max_itersLoosen tolerance (
eps)Check problem feasibility
Numerical Issues¶
Warning: Solution may be inaccurate.
Solutions:
Scale your data (normalize matrices)
Use tighter tolerance
Try Clarabel (often more numerically stable)
Slow Convergence¶
Solutions:
Warm-starting (if supported)
Problem reformulation
Use CuClarabel for large problems