Expand description
Basin: a numerical optimization library.
The framework lives in core: problem traits the user implements
(Constraints, CostFunction, Gradient, Residual, and
the nonlinear constraint evaluation capabilities), 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::{
FirstOrderState, 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),
FirstOrderState::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};
impl basin::CostFunction for Sphere {
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 | FirstOrderState | ✓ |
Sgd | PointState | ✓ |
NonlinearCg | FirstOrderState | ✓ |
ProjectedGradientDescent | FirstOrderState | ✓ |
Bfgs | FirstOrderState | ✓ (Vec/nalgebra/ndarray/faer) |
Lbfgs, Lbfgsb | FirstOrderState | ✓ |
TrustRegion | FirstOrderState | ✓ |
GaussNewton, LevenbergMarquardt, LevenbergMarquardtQr, BoundedLevenbergMarquardt, TrustRegionReflective | PointState | ✓ |
NelderMead | SimplexProgress | ✓ |
Gbnm | PointState | ✓ |
Newuoa, Bobyqa, Lincoa | PointState | ✓ |
Cobyla | SelectedState | ✓ |
Mads | PointState or SelectedState | ✓ |
BasinHopping | PointState | ✓ |
SolisWets | PointState | ✓ |
SimulatedAnnealing | ProposalState | ✓ |
BarrierMethod | PointState | ✓ |
Slsqp | SelectedFirstOrderState | ✓ |
AugmentedLagrangianMethod | SelectedState | ✓ |
CmaEs, BoundedCmaEs | PopulationProgress | ✓ (scale is configured on the solver) |
CmaInject, BoundedCmaInject | PopulationProgress | ✗ (explicit mean seed) |
MaLsChCma, MaLsChSw | PopulationProgress | ✗ (samples the box) |
GlobalBestPso | PopulationProgress | ✗ (samples a swarm from the box) |
RandomSearch, Ssga, De, DeInject | PopulationProgress | ✗ (samples the box or accepts explicit members) |
Direct | PointState | ✗ (starts at the box midpoint) |
BrentDerivative | FirstOrderState<F, F> | ✗ (bracket, not a point) |
Brent, GoldenSection | PointState<F, F> | ✗ (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
TerminationReport, 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.Executor::runpreserves the problem error in the solver’s error type, either directly or in a typed wrapper described below. 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). Unconstrained solvers and line searches use P::Error
directly. Solvers that validate constraints use
ConstraintSolveError<P::Error>: its
Evaluation variant preserves the original
callback error, while
InvalidConstraints reports invalid
declarations or malformed callback outputs. Executor::run returns the
solver’s Solver::Error, so callers can handle both failures without boxing
or stringifying the original error.
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.
§Features
Basin enables no features by default. Enable problems to use the standard
test-function corpus through basin::problems, for example with
cargo add basin --features problems.
§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 |
| ndarray | ndarray_v0_15 through ndarray_v0_17 | ndarray |
| faer | faer_v0_22 through faer_v0_24 | faer |
nalgebra selects 0.35, ndarray selects 0.17, and faer selects 0.24.
The *_latest features remain available as deprecated synonyms.
If dependency feature unification enables several releases of one backend,
Basin implements every enabled release independently.
BFGS uses FirstOrderState with a solver-owned inverse Hessian. Its
DenseBackend association selects the matrix belonging to the parameter’s
backend version, so feature unification cannot change the concrete type.
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-lapack and ndarray-blas; the
nalgebra_latest-lapack and ndarray_latest-blas features remain available
as deprecated synonyms.
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 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::BoundSide;pub use crate::core::constraint::BoxBounds;pub use crate::core::constraint::Constrained;pub use crate::core::constraint::ConstraintAxis;pub use crate::core::constraint::ConstraintBlock;pub use crate::core::constraint::ConstraintDescription;pub use crate::core::constraint::ConstraintError;pub use crate::core::constraint::ConstraintJacobian;pub use crate::core::constraint::ConstraintSet;pub use crate::core::constraint::ConstraintSolveError;pub use crate::core::constraint::Constraints;pub use crate::core::constraint::LinearBlock;pub use crate::core::constraint::LinearBlocks;pub use crate::core::constraint::NoBounds;pub use crate::core::constraint::NoConstraints;pub use crate::core::constraint::NoLinearBlock;pub use crate::core::constraint::NoLinearConstraints;pub use crate::core::constraint::NoNonlinearBlock;pub use crate::core::constraint::NoNonlinearConstraints;pub use crate::core::constraint::NonlinearBlock;pub use crate::core::constraint::NonlinearBlocks;pub use crate::core::constraint::NonlinearEqualityValues;pub use crate::core::constraint::NonlinearInequalityValues;pub use crate::core::constraint::RelaxedInner;pub use crate::core::constraint::SamplingBounds;pub use crate::core::constraint::SamplingDomain;pub use crate::core::convergence::ConfiguredSolver;pub use crate::core::convergence::NativeConvergenceDiagnostics;pub use crate::core::convergence::NativeConvergenceTest;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_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::DenseBackend;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::GeneralRankOneUpdate;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::MatTransposeVecInto;pub use crate::core::math::MatVec;pub use crate::core::math::MatVecInto;pub use crate::core::math::MatrixFinite;pub use crate::core::math::MatrixFromDiagonal;pub use crate::core::math::MatrixIdentity;pub use crate::core::math::MatrixIndex;pub use crate::core::math::MatrixShape;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::ObservationEvent;pub use crate::core::observer::Observe;pub use crate::core::observer::ObserveSolver;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::solver::SolverStep;pub use crate::core::state::AcceptanceState;pub use crate::core::state::ConstraintViolationState;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::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::MeshState;pub use crate::core::state::ObjectiveIncumbentState;pub use crate::core::state::PointState;pub use crate::core::state::PopulationProgress;pub use crate::core::state::PopulationShapeError;pub use crate::core::state::PopulationState;pub use crate::core::state::ProposalState;pub use crate::core::state::RawEvaluationState;pub use crate::core::state::RhoState;pub use crate::core::state::SelectedFirstOrderState;pub use crate::core::state::SelectedState;pub use crate::core::state::SimplexProgress;pub use crate::core::state::SimplexShapeError;pub use crate::core::state::SimplexState;pub use crate::core::state::State;pub use crate::core::state::ViolationMeasure;pub use crate::core::state::ViolationReport;pub use crate::core::state::ViolationScaling;pub use crate::core::state::ViolationTransformation;pub use crate::core::termination::ApplicationStop;pub use crate::core::termination::BinaryValue;pub use crate::core::termination::Convergence;pub use crate::core::termination::ConvergenceCriterion;pub use crate::core::termination::ConvergenceEvidence;pub use crate::core::termination::ConvergenceTest;pub use crate::core::termination::ExecutionLimit;pub use crate::core::termination::Measurement;pub use crate::core::termination::NumericalFailure;pub use crate::core::termination::PartialResultPolicy;pub use crate::core::termination::Stall;pub use crate::core::termination::Termination;pub use crate::core::termination::TerminationCode;pub use crate::core::termination::TerminationReport;pub use crate::core::termination::TerminationStage;pub use crate::core::termination::Threshold;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::BoundedLevenbergMarquardt;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::DeCrossover;pub use crate::solver::DeInject;pub use crate::solver::DeMutation;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::MaLsChSw;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::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.
- root
- Scalar root-finding algorithms with direct solve APIs. Scalar root-finding algorithms.
- solver
- Concrete solver implementations.