Expand description
Basin: a numerical optimization library.
The framework lives in core: problem traits the user implements
(CostFunction, Gradient, BoxConstraints,
LinearInequalityConstraints, LinearEqualityConstraints,
LinearConstraints, NonlinearInequalityConstraints,
NonlinearConstraints), state shapes
solvers iterate over (State, GradientState, SimplexState),
the Solver trait, solver-owned convergence, execution controls
(RunControl), and a read-only observer layer
(Observe). Concrete optimization solvers are in solver; line
searches in line_search; and direct scalar root finders in root.
Start at Executor for optimization runs, root for scalar equations,
or core for the trait taxonomy and the iteration-loop contract.
See CONTRIBUTING.md at the repo root for the design tenets that shape
these APIs (notably tenet 3 on solver-owned convergence, tenet 4
on first-class constraints, and tenet 5 on backend tiering).
§Example
Implement CostFunction (and Gradient when the solver needs
derivatives), then hand the problem, a solver, and an initial state to
the Executor:
use basin::{
BasicState, CostFunction, Executor, Gradient, GradientDescent,
};
struct Sphere;
impl CostFunction for Sphere {
type Param = Vec<f64>;
type Output = f64;
type Error = std::convert::Infallible;
fn cost(&self, x: &Vec<f64>) -> Result<f64, std::convert::Infallible> {
Ok(x.iter().map(|xi| xi * xi).sum())
}
}
impl Gradient for Sphere {
type Gradient = Vec<f64>;
fn gradient(
&self,
x: &Vec<f64>,
) -> Result<Vec<f64>, std::convert::Infallible> {
Ok(x.iter().map(|xi| 2.0 * xi).collect())
}
}
let result = Executor::new(
Sphere,
(GradientDescent::new(0.1)).with_absolute_gradient_tolerance(1e-8),
BasicState::new(vec![1.0, 1.0]),
)
.max_iter(1_000)
.run()
.unwrap();
assert!(result.cost() < 1e-12);§Seeding the initial state
Executor::new takes a fully-built State so you control the initial
iterate (a custom simplex, a warm-started inverse Hessian, an anisotropic
CMA-ES covariance). For the common case (start at a point, use the
solver’s natural defaults) Executor::from_start takes the bare
starting vector instead and builds the state for you via
InitialState::seed, so you never name the concrete state type:
use basin::{Executor, NelderMead};
let result = Executor::from_start(Sphere, NelderMead::new(), vec![1.0, 1.0])
.max_iter(500)
.run()
.unwrap();Most solvers support from_start; the few whose natural initialization
needs more than a point do not implement InitialState, so calling
from_start with one is a compile error (use Executor::new with an
explicit state). The map:
| Solver | State | from_start |
|---|---|---|
GradientDescent, Sgd | BasicState | ✓ |
NonlinearCg | FirstOrderState | ✓ |
ProjectedGradientDescent | BasicState | ✓ (f64 only) |
Bfgs | QuasiNewtonState | ✓ (Vec/nalgebra/ndarray/faer) |
Lbfgs, Lbfgsb | LbfgsState | ✓ |
TrustRegion | BasicState | ✓ |
GaussNewton, LevenbergMarquardt, LevenbergMarquardtQr, Trf, TrustRegionReflective | NllsState | ✓ |
NelderMead | BasicSimplexState | ✓ |
Gbnm | GbnmState | ✓ |
Newuoa, Bobyqa, Lincoa, Cobyla | NewuoaState/… | ✓ |
Mads | MadsState/ConstrainedMadsState | ✓ |
SolisWets | SolisWetsState | ✓ |
SimulatedAnnealing | SimulatedAnnealingState | ✓ |
BarrierMethod, AugmentedLagrangianMethod | BasicState | ✓ |
CmaEs, BoundedCmaEs, CmaInject, BoundedCmaInject, MaLsChCma, MaLsChSw | CmaEsState/MaLsChState/… | ✗ (needs a step-size σ or samples the box) |
GlobalBestPso | GlobalBestPsoState | ✗ (samples a swarm from the box) |
RandomSearch, Ssga, De, DeInject | BasicPopulationState | ✗ (sample the box, ignore a point) |
Direct | PointState | ✗ (starts at the box midpoint) |
Brent, BrentDerivative, GoldenSection | ScalarState | ✗ (bracket, not a point) |
§Error model
Basin distinguishes three outcomes a run can produce. The split is a stable part of the public contract; downstream code can rely on it:
- Soft reject: return
Ok(f64::INFINITY)fromCostFunction::costto reject a single point without stopping the solve. Line searches treat+∞as worse and retreat; population solvers treat it as worst fitness. This is the channel for “thisxis outside my domain, but the solve should continue.” - Clean stop: the run ends normally with a
TerminationReason, either because convergence or an execution limit was reached, an attachedCancellationTokenwas cancelled, or theSolverreported a mid-iteration stop.Executor::runreturnsOk(OptimizationResult)carrying that reason. This is not an error. - Hard abort: return
Err(_)from a problem-trait method to terminate the entire solve. The error is your own type and bubbles out ofExecutor::rununtouched, typed asResult<_, P::Error>. Use it when the failure is not about a particularx: a downstream service vanished, an expensive evaluation detected a fine-grained cancellation request, or an early-stop condition in your own problem state fired.
§One error type, threaded through
The hard-abort error is chosen once, on the problem
(CostFunction::Error, or
Residual::Error for nonlinear
least squares). Every downstream trait mirrors it: Solver::Error and
LineSearch::Error are set to P::Error, so a custom problem error flows
through the solver and line search out to the caller with no conversion glue.
Problems that cannot fail pick std::convert::Infallible; its niche
optimization keeps Result<f64, Infallible> the same layout as a bare f64,
so the happy path stays zero-cost.
The direct scalar root APIs follow the same typed-error principle without
using optimization state: callback failures are wrapped in
BrentRootError::Evaluation or RootError::Evaluation, structural
bracket failures have distinct variants, and an iteration-limit exit is a
clean RootResult.
The problem module docs carry the per-trait detail.
§Backends
Parameters and linear algebra are generic over the backend. Vec<f64> needs
no features. Each external backend has exact version features and a moving
alias:
| Backend | Exact features | Moving alias |
|---|---|---|
| nalgebra | nalgebra_v0_32 through nalgebra_v0_35 | nalgebra_latest |
| ndarray | ndarray_v0_15 through ndarray_v0_17 | ndarray_latest |
| faer | faer_v0_22 through faer_v0_24 | faer_latest |
The original features remain frozen for Basin 1.x compatibility:
nalgebra selects 0.34, ndarray selects 0.17, and faer selects 0.24.
If dependency feature unification enables several releases of one backend,
Basin implements the newest enabled release.
Each nalgebra release includes its matching nalgebra-sparse release:
0.32/0.9, 0.33/0.10, 0.34/0.11, and 0.35/0.12. Versioned acceleration uses
the nalgebra_v0_XX-lapack and ndarray_v0_XX-blas features. The moving
aliases are nalgebra_latest-lapack and ndarray_latest-blas; the original
nalgebra-lapack and ndarray-blas features remain frozen at nalgebra 0.34
and ndarray 0.17.
BLAS/LAPACK acceleration is off by default, is not wasm-compatible, and
expects the application to supply BLAS/LAPACK symbols at link time. The
default build is wasm-friendly and single-threaded; parallelism is behind
the opt-in parallel feature.
Basin’s package MSRV is Rust 1.87. nalgebra_v0_35 and
nalgebra_latest require Rust 1.89 because nalgebra 0.35 does.
§Citation
If you use Basin in your research, please cite the paper:
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}
}CITATION.cff at the repo root carries the same reference in
machine-readable form.
Re-exports§
pub use crate::bracket::BracketError;pub use crate::bracket::BracketTerminationReason;pub use crate::bracket::MinimumBracketResult;pub use crate::bracket::MinimumBracketer;pub use crate::bracket::RootBracketResult;pub use crate::bracket::RootBracketer;pub use crate::core::augmented_lagrangian::AugmentedLagrangian;pub use crate::core::barrier::LogBarrier;pub use crate::core::checkpoint::CheckpointSink;pub use crate::core::checkpoint::ExactCheckpoint;pub use crate::core::checkpoint::CheckpointStatus;serdeand non-WebAssemblypub use crate::core::checkpoint::CheckpointWriteError;serdeand non-WebAssemblypub use crate::core::checkpoint::ExactCheckpointWriter;serdeand non-WebAssemblypub use crate::core::checkpoint::read_exact_checkpoint;serdeand non-WebAssemblypub use crate::core::constraint::BoxConstraints;pub use crate::core::constraint::ConstraintJacobian;pub use crate::core::constraint::FoldedConstraints;pub use crate::core::constraint::LinearConstraints;pub use crate::core::constraint::LinearEqualityConstraints;pub use crate::core::constraint::LinearInequalityConstraints;pub use crate::core::constraint::NonlinearConstraints;pub use crate::core::constraint::NonlinearInequalityConstraints;pub use crate::core::convergence::ConfiguredSolver;pub use crate::core::executor::CancellationToken;pub use crate::core::executor::Executor;pub use crate::core::executor::OptimizationResult;pub use crate::core::executor::OptimizationResultWithSolver;pub use crate::core::executor::StepOutcome;pub use crate::core::executor::Stepper;pub use crate::core::executor::run_loop;Deprecated pub use crate::core::executor::run_loop_with_control;pub use crate::core::inner::InitialState;pub use crate::core::inner::InnerExecutor;pub use crate::core::inner::ResumableInner;pub use crate::core::inner::WarmStart;pub use crate::core::least_squares::ArctanLoss;pub use crate::core::least_squares::CauchyLoss;pub use crate::core::least_squares::HuberLoss;pub use crate::core::least_squares::LossEvaluation;pub use crate::core::least_squares::LossFunction;pub use crate::core::least_squares::RobustLeastSquares;pub use crate::core::least_squares::SoftL1Loss;pub use crate::core::least_squares::SquaredLoss;pub use crate::core::math::AddDiagonalVectorInPlace;pub use crate::core::math::ClampInPlace;pub use crate::core::math::ComponentMulAssign;pub use crate::core::math::DenseMatrix;pub use crate::core::math::DenseMatrixFromFn;pub use crate::core::math::Dot;pub use crate::core::math::FactorizePivotedQr;pub use crate::core::math::GramMatrix;pub use crate::core::math::LinearSolveError;pub use crate::core::math::LinearSolveLstsq;pub use crate::core::math::LinearSolveSpd;pub use crate::core::math::MatTransposeVec;pub use crate::core::math::MatVec;pub use crate::core::math::MatrixFromDiagonal;pub use crate::core::math::MatrixIdentity;pub use crate::core::math::MatrixIndex;pub use crate::core::math::MaxDiagonal;pub use crate::core::math::NegInPlace;pub use crate::core::math::NormInfinity;pub use crate::core::math::NormSquared;pub use crate::core::math::QrFactorization;pub use crate::core::math::QrSolveError;pub use crate::core::math::RegularizedQrSolve;pub use crate::core::math::SampleStandardNormal;pub use crate::core::math::SampleUniformBox;pub use crate::core::math::Scalar;pub use crate::core::math::ScaleInPlace;pub use crate::core::math::ScaleRowsInPlace;pub use crate::core::math::ScaledAdd;pub use crate::core::math::SymmetricEigen;pub use crate::core::math::SymmetricEigenError;pub use crate::core::math::VectorIndex;pub use crate::core::math::VectorLen;pub use crate::core::numdiff::BoundedFiniteDiff;pub use crate::core::numdiff::DerivativeCheckError;pub use crate::core::numdiff::DerivativeCheckReport;pub use crate::core::numdiff::DerivativeChecker;pub use crate::core::numdiff::DerivativeComparison;pub use crate::core::numdiff::DerivativeSource;pub use crate::core::numdiff::FiniteDiff;pub use crate::core::numdiff::Method;pub use crate::core::numdiff::central_difference_gradient;pub use crate::core::numdiff::central_difference_hessian;pub use crate::core::numdiff::central_difference_hessian_product;pub use crate::core::numdiff::central_difference_jacobian;pub use crate::core::numdiff::forward_difference_gradient;pub use crate::core::numdiff::forward_difference_hessian;pub use crate::core::numdiff::forward_difference_hessian_product;pub use crate::core::numdiff::forward_difference_jacobian;pub use crate::core::observer::CheckpointWriter;serdeand non-WebAssemblypub use crate::core::observer::read_checkpoint;serdeand non-WebAssemblypub use crate::core::observer::History;pub use crate::core::observer::Observe;pub use crate::core::observer::ObserverMode;pub use crate::core::observer::Report;pub use crate::core::problem::CostFunction;pub use crate::core::problem::EvalCounts;pub use crate::core::problem::EvaluationKind;pub use crate::core::problem::Gradient;pub use crate::core::problem::Hessian;pub use crate::core::problem::HessianProduct;pub use crate::core::problem::Jacobian;pub use crate::core::problem::MiniBatchGradient;pub use crate::core::problem::Problem;pub use crate::core::problem::Residual;pub use crate::core::run_control::RunControl;pub use crate::core::solver::Solver;pub use crate::core::state::FaerQuasiNewtonState;faer_allpub use crate::core::state::NalgebraQuasiNewtonState;nalgebra_allpub use crate::core::state::NdarrayQuasiNewtonState;ndarray_allpub use crate::core::state::AcceptanceState;pub use crate::core::state::BasicPopulationState;pub use crate::core::state::BasicSimplexState;pub use crate::core::state::BasicState;pub use crate::core::state::BobyqaState;pub use crate::core::state::CmaEsState;pub use crate::core::state::CobylaState;pub use crate::core::state::ConstrainedMadsState;pub use crate::core::state::CountsMirror;pub use crate::core::state::EvaluatedGradientState;pub use crate::core::state::EvaluatedState;pub use crate::core::state::ExactResumeState;pub use crate::core::state::FirstOrderState;pub use crate::core::state::GbnmState;pub use crate::core::state::GlobalBestPsoState;pub use crate::core::state::GradientDimensionMismatch;pub use crate::core::state::GradientState;pub use crate::core::state::IncumbentRef;pub use crate::core::state::IncumbentState;pub use crate::core::state::IntoInitialSimplex;pub use crate::core::state::LbfgsState;pub use crate::core::state::LincoaState;pub use crate::core::state::MadsState;pub use crate::core::state::MeshState;pub use crate::core::state::NewuoaState;pub use crate::core::state::NllsState;pub use crate::core::state::ObjectiveIncumbentState;pub use crate::core::state::PointState;pub use crate::core::state::PopulationState;pub use crate::core::state::RawEvaluationState;pub use crate::core::state::RhoState;pub use crate::core::state::ScalarGradientState;pub use crate::core::state::ScalarState;pub use crate::core::state::SimplexState;pub use crate::core::state::SimulatedAnnealingState;pub use crate::core::state::SlsqpState;pub use crate::core::state::SolisWetsState;pub use crate::core::state::State;pub use crate::core::state::DenseQuasiNewtonState;pub use crate::core::state::QuasiNewtonState;pub use crate::core::termination::CmaEsTolerance;Deprecated pub use crate::core::termination::CostTolerance;Deprecated pub use crate::core::termination::GradientTolerance;Deprecated pub use crate::core::termination::MaxCostEvals;Deprecated pub use crate::core::termination::MaxGradientEvals;Deprecated pub use crate::core::termination::MaxIter;Deprecated pub use crate::core::termination::MaxTime;Deprecated pub use crate::core::termination::MeshTolerance;Deprecated pub use crate::core::termination::NoAcceptance;Deprecated pub use crate::core::termination::NoImprovement;Deprecated pub use crate::core::termination::ParamTolerance;Deprecated pub use crate::core::termination::ProjectedGradientTolerance;Deprecated pub use crate::core::termination::RelativeCostTolerance;Deprecated pub use crate::core::termination::RelativeGradientTolerance;Deprecated pub use crate::core::termination::RelativeParamTolerance;Deprecated pub use crate::core::termination::RhoTolerance;Deprecated pub use crate::core::termination::SimplexTolerance;Deprecated pub use crate::core::termination::TargetCost;Deprecated pub use crate::core::termination::TerminationCriterion;Deprecated pub use crate::core::termination::TerminationReason;pub use crate::line_search::Backtracking;pub use crate::line_search::Constant;pub use crate::line_search::HagerZhang;pub use crate::line_search::LineSearch;pub use crate::line_search::LineSearchBounds;pub use crate::line_search::LineSearchEvaluation;pub use crate::line_search::LineSearchOutcome;pub use crate::line_search::LineSearchResult;pub use crate::line_search::MoreThuente;pub use crate::line_search::Wolfe;pub use crate::root::BrentRoot;pub use crate::root::BrentRootError;pub use crate::root::HalleyRoot;pub use crate::root::NewtonRoot;pub use crate::root::RootError;pub use crate::root::RootResult;pub use crate::root::RootTerminationReason;pub use crate::root::SecantRoot;pub use crate::root::Toms748Root;pub use crate::solver::Bfgs;pub use crate::solver::lbfgs::Lbfgs;pub use crate::solver::lbfgs::Lbfgsb;pub use crate::solver::trust_region::CauchyPoint;pub use crate::solver::trust_region::Dogleg;pub use crate::solver::trust_region::ExactHessian;pub use crate::solver::trust_region::MatrixFree;pub use crate::solver::trust_region::MoreSorensen;pub use crate::solver::trust_region::Steihaug;pub use crate::solver::trust_region::TrustRegion;pub use crate::solver::AcceptanceTest;pub use crate::solver::AugmentedLagrangianMethod;pub use crate::solver::BarrierMethod;pub use crate::solver::BasinHopping;pub use crate::solver::Bobyqa;pub use crate::solver::BoundedCmaEs;pub use crate::solver::BoundedCmaInject;pub use crate::solver::Brent;pub use crate::solver::BrentDerivative;pub use crate::solver::CgUpdate;pub use crate::solver::ClosureInner;pub use crate::solver::CmaEs;pub use crate::solver::CmaInject;pub use crate::solver::Cobyla;pub use crate::solver::De;pub use crate::solver::DeInject;pub use crate::solver::Direct;pub use crate::solver::GaussNewton;pub use crate::solver::Gbnm;pub use crate::solver::GlobalBestPso;pub use crate::solver::GoldenSection;pub use crate::solver::GradientDescent;pub use crate::solver::LevenbergMarquardt;pub use crate::solver::LevenbergMarquardtQr;pub use crate::solver::Lincoa;pub use crate::solver::LmDamping;pub use crate::solver::MaLsCh;pub use crate::solver::MaLsChCma;pub use crate::solver::MaLsChGenericState;pub use crate::solver::MaLsChState;pub use crate::solver::MaLsChSw;pub use crate::solver::MaLsChSwState;pub use crate::solver::Mads;pub use crate::solver::MemeticInner;pub use crate::solver::Metropolis;pub use crate::solver::Neighbor;pub use crate::solver::NelderMead;pub use crate::solver::Newuoa;pub use crate::solver::NonlinearCg;pub use crate::solver::ProjectedGradientDescent;pub use crate::solver::PsoBoundaryHandling;pub use crate::solver::PsoVelocityLimit;pub use crate::solver::RandomDisplacement;pub use crate::solver::RandomSearch;pub use crate::solver::Reannealing;pub use crate::solver::Sgd;pub use crate::solver::SimulatedAnnealing;pub use crate::solver::Slsqp;pub use crate::solver::SlsqpFailure;pub use crate::solver::SolisWets;pub use crate::solver::Ssga;pub use crate::solver::StepTaker;pub use crate::solver::TemperatureSchedule;pub use crate::solver::Trf;pub use crate::solver::TrustRegionReflective;
Modules§
- bracket
- Automatic scalar root and minimum bracketing. Automatic scalar root and minimum bracketing.
- core
- Framework: traits, state shapes, the iteration driver, and the convergence and execution controls. The slot taxonomy is:
- line_
search - Line searches: produce a step size
αalong a caller-supplied descent direction. Used by first-order solvers (gradient descent, BFGS). - problems
problems - Catalog of test problems used by the example tests and benchmarks. Standard optimization test problems.
- root
- Scalar root-finding algorithms with direct solve APIs. Scalar root-finding algorithms.
- solver
- Concrete solver implementations.