cvxgenrust takes a parameterized CVXPY
optimization problem and generates a Rust solver crate tailored to that problem
family. The generated crate reconstructs canonical cone-program data and solves
it with Clarabel. It also includes a Python
wrapper that can be registered as a custom CVXPY solve method for prototyping.
More details can be found in the associated paper.
Install the released package from PyPI with:
pip install cvxgenrustGenerated solver projects use Rust, Cargo, Clarabel, and, when the Python wrapper is enabled, a PyO3/maturin build. Install a stable Rust toolchain before building or importing generated extension wrappers.
For development from this repository, use uv
to manage dependencies. Once uv is installed, run:
make syncThis installs the default development environment defined by the repository
Makefile.
Generate a small nonnegative least-squares solver as a Rust crate:
import cvxpy as cp
import cvxgenrust as cgr
m, n = 3, 2
A = cp.Parameter((m, n), name="A")
b = cp.Parameter(m, name="b")
x = cp.Variable(n, name="x")
problem = cp.Problem(
cp.Minimize(cp.sum_squares(A @ x - b)),
[x >= 0],
)
project = cgr.generate_code(
problem,
code_dir="nonneg_ls_cgr",
module_name="nonneg_ls",
)
print("generated:", project.output_dir)You should always set name= on CVXPY parameters and variables. The generated Rust
setters, extractors, metadata, and Python wrapper use those names after code
generation.
You can build and run the generated Rust project with:
cd nonneg_ls_cgr
cargo run --example solveBy default, generate_code also compiles the generated Python extension wrapper
into the generated project's python/ directory. Pass wrapper=False to only
write the Rust crate and Python wrapper sources.
An HTML documentation of the generated project is written to
nonneg_ls_cgr/README.html, where you can find more details of the generated
code and usage examples.
cvxgenrust supports real dense, diagonal, symmetric, PSD, NSD, and explicitly
sparse CVXPY parameters. Declaring invariant structure with sparsity= keeps
known zero entries out of the generated canonical matrices; declaring the same
parameter as dense can increase generated code size and solver work. The
coordinates excluded by a parameter's sparsity=
pattern must remain structural zeros for every update; use a dense parameter if
any excluded entry may later become nonzero. Complex and Hermitian parameter
layouts are not supported.
Each generated README.html reports the logical shape, packed size, offset,
layout, and exact Rust setter order for every parameter. Its generated Python
example also shows how to assign values for that problem's layouts.