oximo-clarabel
Wraps the clarabel crate: an open-source,
pure-Rust interior-point solver for convex conic programs. Supports LP, convex QP
(quadratic objective, linear constraints), and SOCP model kinds. It has no
integer support, so mixed-integer models are rejected.
Usage
Enable the clarabel feature on the umbrella oximo crate:
[]
= { = "0.5.1", = ["clarabel"] }
To use this crate directly:
[]
= "0.5.1"
= "0.5.1"
= "0.5.1"
The optional faer feature adds the faer
sparse LDL factorization as an alternative KKT backend.
Quick example
use *;
use ;
use ;
let m = new;
variable!;
variable!;
variable!;
m.fix;
soc_constraint!; // ||(x, y)||_2 <= t
objective!;
let result = Clarabel.solve.unwrap;
assert_eq!;
println!; // -sqrt(2)
Run the bundled SOCP example:
Supported model kinds
| Kind | Supported |
|---|---|
LP |
Yes |
QP (quadratic objective, linear constraints) |
Yes, the objective Hessian must be positive semidefinite (Clarabel does not check and a non-convex P fails numerically) |
SOCP |
Yes |
MILP/MIQP/MISOCP |
No, Clarabel has no integer support (returned as UnsupportedKind) |
QCP/MIQCP |
No, convex-QCP-to-SOC reformulation is not implemented. Write the constraint in SOC form instead. |
A quadratic constraint that is already SOC-shaped (sum p_i x_i^2 <= n t^2,
t >= 0) is detected as SOCP and solved, a general convex quadratic
constraint is not.
Persistent handle (repeated solves)
Clarabel.solve builds a fresh solver for each call. When you re-solve one model
many times (parameter sweeps, sensitivity studies, column generation, rolling
horizons, etc) build a resident handle with Clarabel.persistent() and call
solve on it instead. ClarabelPersistent is a plain Solver. When the next
model has the same dimensions, cone layout, and P/A sparsity pattern, only
the numeric data (P, q, A, b) is overwritten in place via Clarabel's
update_data, reusing the KKT symbolic factorization. Any structural change
(added/removed rows or columns, a changed sparsity pattern, a new cone, or a
flipped constraint sense that moves a row between cones) triggers a transparent
rebuild, so results always match a cold solve.
Convex quadratic objectives (QP)
A quadratic objective (e.g. x.powi(2), x * y) with linear constraints is
detected as QP. oximo derives the Hessian from the objective and Clarabel
minimizes c'x + 0.5·x'Px.
Convexity. Clarabel solves only convex QPs. For minimization
Pmust be positive semidefinite; for maximization, negative semidefinite. Clarabel does not check this, so an indefinite or incorrectly signed Hessian may fail numerically or return a non-optimal point.
Options
ClarabelOptions is a typed builder. All methods return Self for chaining,
and every field is Option. None leaves Clarabel's own default in place.
Universal options (via UniversalOptionsExt)
| Method | Clarabel setting | Default |
|---|---|---|
.time_limit(Duration) |
time_limit |
none |
.threads(usize) |
max_threads (KKT solvers only, see note) |
none |
.verbose(bool) |
verbose |
none |
.threads maps to max_threads, which only affects multithreaded KKT solvers.
The default qdldl is single-threaded.
Clarabel options (selected)
| Method | Clarabel setting | Default |
|---|---|---|
.direct_solve_method(ClarabelDirectSolve) |
direct_solve_method |
Auto |
.max_iter(u32) |
max_iter |
200 |
.max_step_fraction(f64) |
max_step_fraction |
0.99 |
.tol_gap_abs(f64) |
tol_gap_abs |
1e-8 |
.tol_gap_rel(f64) |
tol_gap_rel |
1e-8 |
.tol_feas(f64) |
tol_feas |
1e-8 |
.tol_infeas_abs(f64) |
tol_infeas_abs |
1e-8 |
.tol_infeas_rel(f64) |
tol_infeas_rel |
1e-8 |
.tol_ktratio(f64) |
tol_ktratio |
1e-6 |
.equilibrate_enable(bool) |
equilibrate_enable |
true |
.static_regularization_enable(bool) |
static_regularization_enable |
true |
.dynamic_regularization_enable(bool) |
dynamic_regularization_enable |
true |
.iterative_refinement_enable(bool) |
iterative_refinement_enable |
true |
.presolve_enable(bool) |
presolve_enable |
true |
.input_sparse_dropzeros(bool) |
input_sparse_dropzeros |
false |
There is also a matching set of low-accuracy fallback tolerances
(reduced_tol_*) and further equilibration, line-search, and regularization
options. The full list is in src/options.rs.
use ;
use UniversalOptionsExt;
let opts = default
.max_iter
.tol_gap_rel
.direct_solve_method
.verbose;
Result
SolverResult fields, populated whenever a usable point is available
(primal_status is FeasiblePoint or OptimalPoint):
solutions- primal points (Vec<SolutionPoint>). This backend returns a single point holding theprimalvalues keyed byVarIdand theobjective(adjusted for the objective sign and any constant term). Access viaresult.objective()/result.value_of(var)dual- constraint duals, keyed byConstraintId, access viaresult.dual_of(c). Reported for equality and single-sided/range linear constraints in the LP convention (gradient = A' yof the problem as posed)soc_dual- for each explicitsoc_constraint!, its norm-form bound multiplier (z0), keyed bySocConstraintId, access viaresult.soc_dual_of(soc)reduced_costs- not populated by this backend (always empty)termination- why the solve stopped, mapped from Clarabel'sSolverStatus:Optimal(Solved),Infeasible(PrimalInfeasible),Unbounded(DualInfeasible),IterationLimit(MaxIterations),TimeLimit(MaxTime),Interrupted(AlmostSolved),NumericError(NumericalError/InsufficientProgress),NotSolved(Unsolved)primal_status- whether a usable point came back (NoSolution/FeasiblePoint/OptimalPoint),result.has_solution()is the shortcutbest_bound/gap- alwaysNone(conic solver, no MIP bound)solve_time- wall time measured around the Clarabel solve calliterations- interior-point iteration count
License
MIT OR Apache-2.0