Documentation
Basin is a numerical optimization library for Rust. It follows the overall
shape of argmin: a generic executor loop drives a solver over a state, calling into the problem traits you implement
(CostFunction, Gradient, and friends).
You minimize a function by implementing one trait for your objective, picking a
solver, and handing both to the Executor. Basin covers first-order and
quasi-Newton methods (gradient descent, BFGS, L-BFGS, L-BFGS-B), derivative-free
search (Nelder–Mead, Powell’s NEWUOA/BOBYQA family, MADS), nonlinear least
squares (Gauss–Newton, Levenberg–Marquardt, trust-region-reflective), and global
or stochastic optimizers (CMA-ES, a steady-state GA, memetic hybrids), with box,
linear, and nonlinear constraints handled problem-side. Every solver is generic
over the linear-algebra backend, from plain Vec<f64> to nalgebra, ndarray, or
faer.
Bracketed scalar equations use the separate BrentRoot::solve API. It accepts
a fallible closure and returns the signed function value and final bracket
directly, without representing root finding as objective minimization.
A Solver Run at a Glance
The smallest complete program: minimize the sphere function with the
derivative-free Nelder–Mead simplex. Implement CostFunction, then let Executor::from_start build the state from your starting point.
use basin::{CostFunction, Executor, MaxIter, NelderMead};
use std::convert::Infallible;
struct Sphere;
impl CostFunction for Sphere {
type Param = Vec<f64>;
type Output = f64;
type Error = Infallible;
fn cost(&self, x: &Vec<f64>) -> Result<f64, Self::Error> {
Ok(x.iter().map(|xi| xi * xi).sum())
}
}
fn main() {
let result =
Executor::from_start(Sphere, NelderMead::new(), vec![1.0, 1.0])
.terminate_on(MaxIter(500))
.run()
.unwrap();
println!("x = {:?}", result.param()); // ~[0.0, 0.0]
println!("f = {}", result.cost()); // ~0.0
} Nelder–Mead needs no derivatives, so CostFunction is the only trait to
implement. If you want to reach for a gradient-based solver and you add a Gradient impl; the Getting Started guide walks through
that full path on the Rosenbrock function.
How the Pieces Fit
- Problem: what you implement. A
CostFunction(and aGradient, if your solver needs one) describing the objective. Constraints such as box bounds live here too, not on the solver. - Solver: the algorithm. Gradient descent, Nelder–Mead, L-BFGS, Levenberg–Marquardt, CMA-ES, and more.
- State: the iterate(s) a solver carries: a single point (
BasicState), a simplex (BasicSimplexState), a population, and so on. - Executor: the driver that runs a solver to termination and hands back an
OptimizationResult. - Termination: pluggable stopping criteria (gradient, parameter, and cost tolerances, iteration and time budgets) configured uniformly across solvers.
- Observers: read-only hooks fired around the loop
(
observe_init/observe_iter/observe_final) for logging, progress reporting, or recording a trajectory. Sibling to termination: observers watch, criteria decide.
Choosing a Solver
A rough map from the shape of your problem to where to start. The Solvers catalog has the full list and the backend each one needs.
- Smooth objective, gradient available:
GradientDescentto start, thenBfgsorLbfgsfor faster convergence (Lbfgswhen the dimension is large). - No derivatives, low dimension:
NelderMead, or Powell’s model-basedNewuoa/Bobyqafor smoother functions. - Sum-of-squares residuals: the nonlinear-least-squares family,
GaussNewton,LevenbergMarquardt, orTrf(trust-region-reflective, for bound constraints). - Rugged or multimodal landscape: the global and stochastic optimizers,
CmaEs, the steady-state GA, or a memetic hybrid. - Constraints: box bounds, linear (in)equalities, and nonlinear constraints
describe the problem, so they live problem-side. Bounded solvers (
Lbfgsb, boundedNelderMead,Trf) consume them directly; adapters (projection, log-barrier, augmented Lagrangian, orCobyla) wrap unconstrained solvers. - Scalar equation with a sign-changing interval:
BrentRootcombines bisection, secant steps, and inverse quadratic interpolation through a direct root-specific API.
Citing Basin
If you use Basin in your research, please cite the paper describing it, arXiv:2608.11279:
Larsson, J. (2026). Basin: Efficient and Extensible Numerical Optimization in Rust (arXiv:2608.11279). arXiv. https://doi.org/10.48550/arXiv.2608.11279@misc{larsson2026basin,
title = {Basin: Efficient and Extensible Numerical Optimization in {{Rust}}},
shorttitle = {Basin},
author = {Larsson, Johan},
year = {2026},
month = aug,
number = {arXiv:2608.11279},
eprint = {2608.11279},
primaryclass = {cs.LG},
publisher = {arXiv},
doi = {10.48550/arXiv.2608.11279},
archiveprefix = {arXiv}
}@online{larsson2026basin,
title = {Basin: Efficient and Extensible Numerical Optimization in {{Rust}}},
shorttitle = {Basin},
author = {Larsson, Johan},
date = {2026-08-11},
eprint = {2608.11279},
eprinttype = {arXiv},
eprintclass = {cs.LG},
doi = {10.48550/arXiv.2608.11279},
pubstate = {prepublished}
}The repository’s CITATION.cff carries
the same reference in machine-readable form.
Where to Go Next
- Getting Started: install Basin and run your first solve.
- Migrating from Argmin: translate problem traits, solver configuration, errors, bounds, and observers from Argmin 0.11.
- Solvers: the catalog of optimization solvers, scalar root finding, and backend support.
You can also watch solvers converge interactively in the visualizer, or browse the full API on docs.rs.