Basic Usage¶
This guide covers the CvxpyLayer constructor and common usage patterns.
Constructor¶
CvxpyLayer(
problem, # CVXPY Problem object
parameters, # List of cp.Parameter objects
variables, # List of cp.Variable objects to return
solver=None, # Solver to use (optional)
gp=False, # True for geometric programs
verbose=False, # Print solver output
solver_args=None, # Default solver arguments
)
Parameters¶
Argument |
Type |
Description |
|---|---|---|
|
|
A DPP-compliant CVXPY problem |
|
|
Parameters that will receive values at runtime |
|
|
Variables to return from the solution |
|
|
Solver backend (e.g., |
|
|
Set |
|
|
Print solver output |
|
|
Default arguments passed to the solver |
DPP Requirements¶
Your problem must be DPP-compliant. This means:
Parameters appear affinely in the objective and constraints
Problem structure is fixed (same constraints for all parameter values)
No parameter-dependent domains
import cvxpy as cp
x = cp.Variable(2)
A = cp.Parameter((3, 2))
b = cp.Parameter(3)
# Good: Parameter appears affinely
problem = cp.Problem(cp.Minimize(cp.sum_squares(A @ x - b)))
assert problem.is_dpp() # True
# Bad: Parameter in non-affine position
c = cp.Parameter(nonneg=True)
bad_problem = cp.Problem(cp.Minimize(cp.quad_form(x, c * np.eye(2))))
# This may not be DPP-compliant
Calling the Layer¶
The layer is called with parameter values in the same order as the parameters list:
layer = CvxpyLayer(problem, parameters=[A, b, c], variables=[x, y])
# Call with matching parameter values
x_sol, y_sol = layer(A_tensor, b_tensor, c_tensor)
Return Values¶
The layer returns a tuple of tensors corresponding to the variables list:
# Single variable
layer = CvxpyLayer(problem, parameters=[A], variables=[x])
(x_sol,) = layer(A_tensor) # Note the tuple unpacking
# Multiple variables
layer = CvxpyLayer(problem, parameters=[A], variables=[x, y, z])
x_sol, y_sol, z_sol = layer(A_tensor)
Parameter Shapes¶
Parameters must match their CVXPY declaration shapes:
A = cp.Parameter((m, n)) # Shape (m, n)
b = cp.Parameter(m) # Shape (m,)
c = cp.Parameter() # Scalar
layer = CvxpyLayer(problem, parameters=[A, b, c], variables=[x])
# Tensor shapes must match
A_tensor = torch.randn(m, n) # Shape (m, n)
b_tensor = torch.randn(m) # Shape (m,)
c_tensor = torch.tensor(1.0) # Scalar
(solution,) = layer(A_tensor, b_tensor, c_tensor)
Using with Neural Networks (PyTorch)¶
The PyTorch layer extends torch.nn.Module, so it integrates naturally:
import torch.nn as nn
class OptimizationNet(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(10, 6) # Outputs A (2x3) flattened
# Create CVXPY problem
x = cp.Variable(3)
A = cp.Parameter((2, 3))
b = cp.Parameter(2)
problem = cp.Problem(
cp.Minimize(cp.sum_squares(A @ x - b)),
[x >= 0]
)
self.cvx_layer = CvxpyLayer(problem, parameters=[A, b], variables=[x])
def forward(self, input_features, b):
# Neural network predicts A
A_flat = self.linear(input_features)
A = A_flat.view(-1, 2, 3)
# Optimization layer finds optimal x
(x,) = self.cvx_layer(A, b)
return x
Solver Arguments at Call Time¶
Override solver settings per-call:
# Default solver args in constructor
layer = CvxpyLayer(problem, parameters=[A], variables=[x],
solver_args={"max_iters": 1000})
# Override at call time
(solution,) = layer(A_tensor, solver_args={"max_iters": 5000, "eps": 1e-8})
Error Handling¶
Common errors and solutions:
Problem Not DPP¶
AssertionError: Problem must be DPP
Check with problem.is_dpp(). Ensure parameters appear affinely.
Shape Mismatch¶
ValueError: Parameter A has shape (3, 2) but tensor has shape (2, 3)
Ensure tensor shapes match parameter declarations.
Solver Failure¶
SolverError: Solver 'SCS' failed.
Try:
Different solver:
solver=cp.CLARABELMore iterations:
solver_args={"max_iters": 10000}Looser tolerance:
solver_args={"eps": 1e-6}