Getting Started
This section describes the process of creating a Clarabel model in Python, populating its settings and problem data, solving the problem and obtaining and understanding results. It is assumed here that you are building your project using cargo
.
The first step is to bring the Clarabel solver and other required packages into scope in your code using:
import clarabel
import numpy as np
from scipy import sparse
Problem Format
Clarabel solves optimisation problems in the format:
\[\begin{array}{ll} \text{minimize} & \textstyle{\frac{1}{2}}x^\top Px + q^\top x\\ \text{subject to} & Ax + s = b \\ & s \in \mathcal{K}, \end{array}\]
with decision variables $x \in \mathbb{R}^n$, $s \in \mathbb{R}^m$ and data matrices $P=P^\top \succeq 0$, $q \in \mathbb{R}^n$, $A \in \mathbb{R}^{m \times n}$, and $b \in \mathbb{R}^m$. The convex cone $\mathcal{K}$ is a composition of smaller convex cones $\mathcal{K} = \mathcal{K}_1 \times \mathcal{K}_2 \dots \mathcal{K}_p$. Equality conditions can be modelled in this format using the solver's ZeroCone type.
To initialize the solver with an optimisation problem we require three things:
- The objective function, i.e. the matrix
P
and the vectorq
in $\frac{1}{2}x^\top P x + q^\top x$. - The data matrix
A
and vectorb
, along with a description of the composite cone\mathcal{K}
and the dimensions of its constituent pieces. - A
settings
object that specifies how Clarabel solves the problem.
Objective Function
To set the objective function of your optimisation problem simply define the square positive semidefinite matrix $P \in \mathrm{R}^{n\times n}$ and the vector $q \in \mathrm{R}^{n}$.
Suppose that we have a problem with decision variable $x \in \mathbb{R}^3$ and our objective function is:
\[\begin{equation*} \min ~ \frac{1}{2} \left[ \begin{array}{l} x_1 \\ x_2 \\x_3 \end{array} \right] ^T \left[ \begin{array}{rrr} 3.0 & 1.0 & -1.0 \\ 1.0 & 4.0 & 2.0 \\ -1.0 & 2.0 & 5.0 \end{array} \right] \left[ \begin{array}{l} x_1 \\ x_2 \\x_3 \end{array} \right] + \left[ \begin{array}{r} 1 \\ 2 \\-3 \end{array} \right]^T \left[ \begin{array}{l} x_1 \\ x_2 \\x_3 \end{array} \right] \end{equation*}\]
Clarabel expects the P
matrix to be supplied in Compressed Sparse Column format. P
is assumed by the solver to be symmetric and only values in the upper triangular part of P
are needed by the solver, i.e. you only need to provide
\[\begin{equation*} P = \left[ \begin{array}{rrr} 3.0 & 1.0 & -1.0 \\ ⋅ & 4.0 & 2.0 \\ ⋅ & ⋅ & 5.0 \end{array} \right] \end{equation*}\]
The Clarabel default implementation in Python expects matrix data in Compressed Sparse Column format as produced by scipy
. We can define our cost data as
P = sparse.csc_matrix(
[[ 3., 1., -1.],
[ 1., 4., 2.],
[-1., 4., 5.]])
P = sparse.triu(P).tocsc()
Constraints
Clarabel interface expects constraints to be presented in the single vectorized form $Ax + s = b, s \in \mathcal{K}$, where $\mathcal{K} = \mathcal{K}_1 \times \dots \times \mathcal{K}_p$ and each $\mathcal{K}_i$ is one of the cones defined below:
Cone Type | Description |
---|---|
ZeroConeT | The set $\{ 0 \}^{dim}$ that contains the origin |
NonnegativeConeT | The nonnegative orthant $\{ x \in \mathbb{R}^{dim} : x_i \ge 0, \forall i=1,\dots,\mathrm{dim} \}$ |
SecondOrderConeT | The second-order (Lorenz) cone $\{ (t,x) \in \mathbb{R}^{dim} : |x|_2 \leq t \}$ |
ExponentialConeT | The exponential cone $\{(x, y, z) : y > 0,~~ ye^{x/y} ≤ z \}$ |
PowerConeT | The power cone $\{(x, y, z) : x^\alpha y^{(1-\alpha)} \geq |z|,~ (x,y) \geq 0 \}$ with $\alpha \in (0,1)$ |
Suppose that we have a problem with decision variable $x \in \mathbb{R}^3$ and our constraints are:
- A single equality constraint $x_1 + x_2 - x_3 = 1$.
- A pair of inequalities such that $x_2$ and $x_3$ are each less than 2.
- A second order cone constraint on the 3-dimensional vector $x$.
For the three constraints above, we have
\[ \begin{align*} A_{eq} &= \left[ \begin{array}{lll} 1 & 1 & -1 \end{array} \right], \quad & b_{eq} &= \left[ \begin{array}{l} 1 \end{array} \right], \\[4ex] A_{ineq} &= \left[ \begin{array}{lll} 0 & 1 & 0 \\ 0 & 0 & 1 \end{array} \right], \quad & b_{ineq} &= \left[ \begin{array}{l} 2\\2 \end{array} \right], \\[4ex] A_{soc} &= \left[ \begin{array}{rrr} -1 & 0 & 0 \\ 0 & -1 & 0 \\ 0 & 0 & -1 \end{array} \right], \quad & b_{soc} &= \left[ \begin{array}{l} 0 \\0 \\0 \end{array} \right] \end{align*} \]
We can define our constraint data as
# equality constraint
Aeq = sparse.csc_matrix([1.,1.,-1])
beq = np.array([1.])
# equality constraint
Aineq = sparse.csc_matrix(
[[0., 1., 0.],
[0., 0., 1.]])
bineq = np.array([2.,2.])
# SOC constraint
Asoc = -sparse.identity(3)
bsoc = np.array([0.,0.,0.])
# Clarabel constraint data
A = sparse.vstack([Aeq,Aineq,Asoc]).tocsc()
b = np.concatenate([beq,bineq,bsoc])
Clarabel expects to receive a vector of cone specifications. For the above constraints we should also define
cones = [clarabel.ZeroConeT(1),
clarabel.NonnegativeConeT(2),
clarabel.SecondOrderConeT(3)]
There is no restriction on the ordering of the cones that appear in cones
, nor on the number of instances of each type that appear. Your input vector b
should be compatible with the sum of the cone dimensions.
Note carefully the signs in the above example. The inequality condition is $A_{ineq} x \le b_{ineq}$, which is equivalent to $A_{ineq} x + s = b_{ineq}$ with $s \ge 0$, i.e. $s$ in the Nonnegative cone. The SOC condition is $x \in \mathcal{K}_{SOC}$, or equivalently $-x + s = 0$ with $s \in \mathcal{K}_{SOC}$.
Solver Settings
Solver settings for the Clarabel's default implementation in Rust are stored in a PyDefaultSettings
object and can be modified by the user. To create a settings object using all defaults you can call the constructor directly:
settings = clarabel.DefaultSettings();
If you want to disable verbose printing and set a 5 second time limit on the solver, you can then just modify the fields:
settings.verbose = True;
settings.time_limit = 5.;
The Clarabel Python interface set supports the same options as those listed in the Rust API Reference.
Making a Solver
Finally, populate the solver with problem data and solve:
solver = clarabel.DefaultSolver(P,q,A,b,cones,settings);
solution = solver.solve()
Results
Once the solver algorithm terminates you can inspect the solution using the solution
output. The primal solution will be in solution.x
and the dual solution in solution.z
. The outcome of the solve is specified in solution.status
and will be one of the following :
Status Code | Description |
---|---|
Solved | Solution found |
PrimalInfeasible | Problem is primal infeasible |
DualInfeasible | Problem is dual infeasible |
MaxIterations | Solver halted after reaching iteration limit |
MaxTime | Solver halted after reaching time limit |
The total solution time is available in solution.solve_time
.