basin 0.7.0

Numerical optimization in pure Rust, with pluggable linear-algebra backends and WASM support.
Documentation

basin

CI crates.io docs.rs

A numerical optimization library for Rust, inspired by argmin. It pairs a small generic core --- problem traits you implement, a pluggable termination layer, and a driver loop (Executor) --- with a growing set of solvers spanning first-order, derivative-free, nonlinear least-squares, and evolutionary methods. Solvers are generic over the linear-algebra backend, constraints are first-class, and the default build compiles to wasm32-unknown-unknown with no BLAS/LAPACK or threads.

Narrative documentation lives at basin.bz/docs; the rustdoc reference is at docs.rs/basin. There is also an in-browser solver visualizer.

Install

cargo add basin

basin works on plain Vec<f64> out of the box. Linear-algebra backends are opt-in, one feature each:

cargo add basin --features nalgebra   # or: ndarray, faer

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, GradientTolerance};

struct Rosenbrock;

impl CostFunction for Rosenbrock {
    type Param = Vec<f64>;
    type Output = f64;
    fn cost(&self, x: &Vec<f64>) -> f64 {
        (1.0 - x[0]).powi(2) + 100.0 * (x[1] - x[0].powi(2)).powi(2)
    }
}

impl Gradient for Rosenbrock {
    type Param = Vec<f64>;
    type Gradient = Vec<f64>;
    fn gradient(&self, x: &Vec<f64>) -> Vec<f64> {
        vec![
            -2.0 * (1.0 - x[0]) - 400.0 * x[0] * (x[1] - x[0].powi(2)),
            200.0 * (x[1] - x[0].powi(2)),
        ]
    }
}

let result = Executor::new(
    Rosenbrock,
    GradientDescent::new(1e-3),
    BasicState::new(vec![-1.2, 1.0]),
)
    .max_iter(50_000)
    .terminate_on(GradientTolerance(1e-6))
    .run();

println!("x = {:?}, f = {}, stopped: {:?}", result.param(), result.cost(), result.reason);

Termination criteria are framework-level: the same ones compose across solvers, and they are bound to the state a solver actually exposes --- so asking for a gradient tolerance on a derivative-free solver is a compile error, not a runtime surprise.

Solvers

  • First-order / quasi-Newton: gradient descent (with momentum and pluggable line searches), BFGS, L-BFGS, L-BFGS-B.
  • Derivative-free: Nelder--Mead, Brent (1D).
  • Nonlinear least squares: Gauss--Newton, Levenberg--Marquardt, trust-region reflective.
  • Global / stochastic: random search, CMA-ES, a steady-state genetic algorithm, and memetic combinations.
  • Constrained: box bounds via projected gradient descent, bounded Nelder--Mead, L-BFGS-B, and bounded CMA-ES.

See Solvers for which backends each one supports.

Backends

Parameters and linear algebra are generic over the backend. Vec<f64> needs no features; nalgebra, ndarray, and faer are enabled one feature each, each pinning a single major version. First-order and derivative-free solvers run on any backend; linear-algebra-heavy solvers may require a specific one and say so in their docs.

The default build is wasm-friendly --- no BLAS/LAPACK and no threads. Parallelism and BLAS-backed paths are behind opt-in features (parallel, ndarray-blas).

Status

Early-stage alpha: the public API is still iterating and breaking changes are expected.

License

MIT