Solvers

Solve oximo models with a variety of solvers.

oximo is solver-agnostic, and provides a variety of backends to solve your optimization models.

Every backend implements the same Solver trait, so swapping engines is a one-line change. The general pattern is:

let result = Backend.solve(&model, &BackendOptions::default())?;

result is a SolverResult, the same struct regardless of backend.

πŸ”—Choosing a backend

To determine what backend to use, consider what each backend solves (by model kind) and what it costs and offers (license, install, diagnostics). Each backend's Cargo feature flag is named in its own section below.

πŸ”—Model kind support

Each row is what Solver::supports accepts for that backend, against every ModelKind:

BackendLPMILPQPMIQPQCPMIQCPSOCPMISOCPNLPMINLP
Highsβœ“βœ“βœ“β€”β€”β€”β€”β€”β€”β€”
Clarabelβœ“β€”βœ“β€”β€”β€”βœ“β€”β€”β€”
Pounceβœ“β€”βœ“β€”βœ“β€”βœ“β€”βœ“β€”
Gurobiβœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“
Mosekβœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“β€”β€”
Baronβœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“
Gamsβœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“βœ“

Gams accepts every kind at the oximo layer, but the actual coverage is the GAMS sub-solver's. Pick one that handles the kind you emit.

πŸ”—Requirements & capabilities

Deployment cost and diagnostic/solve capability per backend.

βœ“ = yes/supported; β€” = no.

BackendLicenseSeparate installC compilerDirect interfaceIISWarm startSol. poolDualsParallel
Highsβ€”β€”βœ“βœ“β€”β€ βœ“β€”βœ“βœ“
Clarabelβ€”β€”β€”βœ“β€”βœ“β€”βœ“βœ“
Pounceβ€”β€”β€”βœ“β€”βœ“β€”βœ“β€”
Gurobiβœ“βœ“β€”βœ“βœ“βœ“βœ“βœ“βœ“
Mosekβœ“βœ“β€”βœ“β€”βœ“β€”βœ“βœ“
Baronβœ“βœ“β€”β€”βœ“β€”βœ“βœ“βœ“
Gamsβœ“βœ“β€”β€”β€”β€”βœ“ΒΆβœ“βœ“

Column meanings:

  • License: the underlying solver is commercial and needs a license at runtime. The oximo wrapper crates are all MIT OR Apache-2.0.
  • Direct interface: talks to the solver in-process. C API/FFI for HiGHS, Gurobi, and MOSEK. Pure Rust for Clarabel and Pounce. BARON and GAMS instead exchange model/result files (.bar, .gms) with an external executable.
  • C compiler: whether a C/C++ compiler is required at build time.
  • IIS: computes an irreducible infeasible set to explain an infeasible model.
  • Warm start: persistent handle for incremental re-solves.
  • Sol. pool: returns multiple solutions, best-first.
  • Duals: shadow prices/reduced costs.
  • Parallel: solver can solve in parallel.

Footnotes:

  • † The highs crate does not support IIS yet.
  • ΒΆ GAMS's pool and duals come from the underlying sub-solver's GDX output (e.g. CPLEX solnpool).

A backend rejects model kinds it can't handle, so check Model::kind() if a solve returns SolverError::UnsupportedKind.

πŸ”—HiGHS

Highs is enabled with the highs Cargo feature. No external solver install is required, but a C/C++ compiler is needed at build time. Add it with cargo add oximo --features highs.

use oximo::prelude::*;
use oximo::solvers::Highs;
use std::time::Duration;

let result = Highs.solve(&m, &HighsOptions::default()
    .time_limit(Duration::from_secs(60))
    .threads(4)
    .mip_gap(0.01)
    .verbose(true)
    .method(HighsMethod::Ipm))?;

Common HighsOptions:

MethodEffect
.time_limit(d)Stop after d (std::time::Duration)
.threads(n)Cap parallelism
.mip_gap(g)Relative MIP optimality gap (e.g. 0.01 = 1%)
.verbose(b)Stream the solver log
.method(m)LP algorithm via HighsMethod (Simplex, Ipm, …)

πŸ”—Clarabel

Clarabel is a pure-Rust conic interior-point solver. No install, no license. It handles continuous LP, QP (convex quadratic objectives), and SOCP models.

use oximo::prelude::*;
use oximo::solvers::Clarabel;

let result = Clarabel.solve(&m, &ClarabelOptions::default())?;

πŸ”—POUNCE

Pounce is a pure-Rust IPOPT and convex-solver backend. Enable the pounce feature:

use oximo::prelude::*;
use oximo::pounce::{Pounce, PounceOptions, PounceSolverSelection};

let result = Pounce.solve(&m, &PounceOptions::default())?;

πŸ”—Derivatives

  • Default stable path: LP/QP/QCP models use exact analytic derivatives, including Jacobian rows and the constant Lagrangian Hessian. Nonlinear models use compiled tapes with finite-difference nonlinear derivatives and a limited-memory L-BFGS Hessian.
  • pounce-enzyme feature: nightly-only exact gradients, sparse Jacobians, and sparse Lagrangian Hessians for nonlinear models. See Installation > Advanced: exact nonlinear derivatives.

Note: pounce-enzyme currently requires the nightly-2026-07-26 toolchain. Later nightly toolchains fail. See rust-lang/rust#160470.

πŸ”—Automatic routing

PounceSolverSelection::Auto is the default. It certifies convexity before selecting a specialized engine:

  • LP and convex QP use the convex IPM.
  • SOCP with a convex objective uses the conic IPM, including explicit cones and recognized quadratic SOC forms.
  • QCP, indefinite QP, and general NLP use the TNLP/builder path.
  • Inconclusive convexity checks fall back to NLP.

A numerical failure in an automatically selected LP or detected-SOCP route gets one NLP attempt. The specialized convex engines currently have no time-limit hook, with a time limit, Auto uses NLP.

πŸ”—Options

PounceOptions provides dedicated setters and typed builders for POUNCE's option reference:

use oximo::pounce::{MuStrategy, PounceOptions, PounceSolverSelection};

let options = PounceOptions::default()
    .tol(1e-8)
    .mu_strategy(MuStrategy::Adaptive)
    .solver_selection(PounceSolverSelection::Auto)
    .presolve(true)
    .linear_solver("feral");

// Escape hatch for an option not exposed by a dedicated setter.
let options = options.set("acceptable_tol", 1e-5);

The backend manages print_level, max_cpu_time, warm_start_init_point, and hessian_approximation. Configure those through the corresponding oximo options or persistent handle.

πŸ”—Gurobi

Gurobi uses gurobi-rs when the gurobi Cargo feature is enabled. It requires a licensed Gurobi installation. Set GUROBI_HOME to the installation directory before building and make sure a Gurobi license is active.

Note: Only Gurobi v13 and later are supported.

[dependencies]
oximo = { version = "0.6", features = ["gurobi"] }
use oximo::prelude::*;
use oximo::solvers::Gurobi;
use std::time::Duration;

let result = Gurobi.solve(&m, &GurobiOptions::default()
    .time_limit(Duration::from_secs(120))
    .mip_focus(1)
    .seed(101))?;

Common GurobiOptions:

MethodEffect
.time_limit(d)Wall-clock limit
.mip_focus(n)Gurobi MIPFocus (1 = feasibility, 2 = optimality, 3 = bound)
.mip_gap(g)Relative MIP optimality gap
.seed(n)Random seed for reproducible runs

πŸ”—MOSEK

Mosek supports LP, MILP, convex QP/MIQP, convex QCP/MIQCP, and SOCP/MISOCP models. It requires the mosek Cargo feature, a licensed MOSEK 11.2 installation, and MOSEK_BINDIR_112 when MOSEK is outside its default location. MOSEK validates the convexity of quadratic data. The backend links through the mosek crate.

On Windows, setting MOSEK_BINDIR_112 directly to a path containing spaces can fail because of an unquoted linker flag in the current mosek crate build script. Create a junction with a space-free path and point the environment variable at that junction; see mosek.rust#1.

Only MOSEK 11.2 is currently supported.

[dependencies]
oximo = { version = "0.6", features = ["mosek"] }
use oximo::prelude::*;
use oximo::solvers::Mosek;
use std::time::Duration;

let result = Mosek.solve(&m, &MosekOptions::default()
    .time_limit(Duration::from_secs(120))
    .threads(4)
    .mio_tol_rel_gap(1e-4))?;

MosekOptions provides builders for every MOSEK 11.2 parameter. Universal options such as time_limit, threads, and verbose are applied first. MOSEK-specific parameter builders are then applied in call order.

πŸ”—BARON

Baron is a global solver for LP/MILP/QP/MIQP/QCP/MIQCP/SOCP/MISOCP/ NLP/MINLP models. The Oximo adapter supports all of these model kinds and translates explicit second-order cones to BARON's quadratic constraint representation. It requires the baron feature, a licensed BARON installation on PATH, and exchanges model and result files with the external executable.

[dependencies]
oximo = { version = "0.6", features = ["baron"] }
use oximo::prelude::*;
use oximo::solvers::Baron;

let result = Baron::new().solve(&m, &BaronOptions::default())?;

πŸ”—GAMS

Gams requires the gams Cargo feature plus a GAMS installation on PATH. It exchanges model and result files with GAMS, which is useful when you want to route a model through GAMS-managed solvers (CPLEX, BARON, IPOPT, KNITRO, ...).

[dependencies]
oximo = { version = "0.6", features = ["gams"] }
use oximo::prelude::*;
use oximo::solvers::Gams;

let result = Gams.solve(&m, &GamsOptions::default())?;

See GamsOptions and the per-solver option structs in oximo::gams (GamsCplexOptions, GamsBaronOptions, GamsIpoptOptions, ...) for tuning the underlying solver.

πŸ”—Next steps

  • Results: inspect solver status, values, duals, and solution pools
  • Printing & Debugging: print a model as algebra and track down what it actually says
  • I/O: write your model to MPS, LP or NL for use with external tools