Basin

Search documentation

Search the guides, solvers, and migration docs.

  • Guide
  • Visualizer
  • Benchmarks

Documentation

  • Overview
  • Getting started
  • Migrating from Argmin
  • Migrating to Basin 2.0
  • Migrating to Basin 3.0

Solvers

  • Choosing a solver
  • First-order
    • Gradient descent
    • Nonlinear CG
    • Stochastic gradient descent
    • Projected gradient descent
  • Quasi-Newton
    • BFGS
    • L-BFGS
    • L-BFGS-B
  • Derivative-free
    • Nelder–Mead
    • MADS
    • NEWUOA
    • BOBYQA
    • LINCOA
    • COBYLA
    • Solis–Wets
  • Trust-region
    • Trust-region Newton
  • Nonlinear least squares
    • Gauss–Newton
    • Levenberg–Marquardt
    • Levenberg–Marquardt QR
    • Bounded Levenberg–Marquardt
    • Trust-region reflective
  • Global and stochastic
    • DIRECT
    • Globalized bounded Nelder–Mead
    • Simulated annealing
    • CMA-ES
    • Bounded CMA-ES
    • Differential evolution
    • Particle swarm
    • Random search
    • Steady-state genetic algorithm
    • Basin-hopping
  • Memetic
    • CMA-ES with local search
    • Bounded CMA-ES with local search
    • DE with local search
    • Local-search chains
    • CMA-ES chains
    • Solis–Wets chains
  • General constrained
    • SLSQP
    • Barrier method
    • Augmented Lagrangian
  • Scalar minimization
    • Brent
    • Brent with derivatives
    • Golden-section search
  • Root finding
    • Bisection
    • Brent
    • Secant
    • Newton
    • Halley
    • TOMS 748
Navigation

Documentation

  • Overview
  • Getting started
  • Migrating from Argmin
  • Migrating to Basin 2.0
  • Migrating to Basin 3.0

Solvers

  • Choosing a solver
  • First-order
    • Gradient descent
    • Nonlinear CG
    • Stochastic gradient descent
    • Projected gradient descent
  • Quasi-Newton
    • BFGS
    • L-BFGS
    • L-BFGS-B
  • Derivative-free
    • Nelder–Mead
    • MADS
    • NEWUOA
    • BOBYQA
    • LINCOA
    • COBYLA
    • Solis–Wets
  • Trust-region
    • Trust-region Newton
  • Nonlinear least squares
    • Gauss–Newton
    • Levenberg–Marquardt
    • Levenberg–Marquardt QR
    • Bounded Levenberg–Marquardt
    • Trust-region reflective
  • Global and stochastic
    • DIRECT
    • Globalized bounded Nelder–Mead
    • Simulated annealing
    • CMA-ES
    • Bounded CMA-ES
    • Differential evolution
    • Particle swarm
    • Random search
    • Steady-state genetic algorithm
    • Basin-hopping
  • Memetic
    • CMA-ES with local search
    • Bounded CMA-ES with local search
    • DE with local search
    • Local-search chains
    • CMA-ES chains
    • Solis–Wets chains
  • General constrained
    • SLSQP
    • Barrier method
    • Augmented Lagrangian
  • Scalar minimization
    • Brent
    • Brent with derivatives
    • Golden-section search
  • Root finding
    • Bisection
    • Brent
    • Secant
    • Newton
    • Halley
    • TOMS 748

L-BFGS-B

L-BFGS-B is a local optimizer for smooth functions with box bounds when you can compute a gradient. It builds a curvature model from a short history of steps and gradient changes, keeping storage manageable for large problems. Its search accounts for the bounds so objective and gradient evaluations stay inside the box.

API reference

PropertyRequirement
ObjectiveA smooth scalar function
EvaluationsCostFunction and Gradient
SearchLocal, from one starting point
ConstraintsA box-only ConstraintSet<BoxBounds<V>> on the problem
ParametersContiguous vectors on all four dense backends, with f32 or f64

When to use it

Consider L-BFGS-B when each parameter has an independent lower or upper bound and you want to use curvature information without storing a dense matrix. The algorithm combines gradient projection with a limited-memory BFGS model (Byrd et al., 1995).

For an unconstrained problem, use L-BFGS or BFGS. Projected gradient descent offers a simpler method with little working storage for box bounds. For least-squares objectives with bounds, compare trust-region reflective. Linear and nonlinear constraint blocks need a method that supports them, such as SLSQP.

L-BFGS-B finds a local constrained solution. Different starting points can lead to different minima, and noisy or nonsmooth gradients can make its curvature estimates unreliable.

How it works

Basin projects the starting point into the box before evaluating the objective and gradient. Each iteration first explores the projected negative-gradient path to find a generalized Cauchy point. It then refines the quadratic model over variables that are free to move, followed by a line search that keeps the step feasible. This is the bound-constrained algorithm described in Zhu et al. (1997), with the version 3.0 subspace changes of Morales and Nocedal (2011).

After an accepted step, the solver retains the change in parameters and the change in gradient when they pass its curvature safeguard. At most m pairs contribute to the model. The default Moré–Thuente line search seeks sufficient decrease and a strong Wolfe curvature condition within the feasible step interval (Moré and Thuente, 1994). A single iteration can require several objective and gradient evaluations.

Example

This quadratic has its unconstrained minimum at [1.0, -2.0]. The box moves the constrained minimum to [0.5, -1.0], where the raw gradient is nonzero. The example declares bounds on the problem and uses a projected-gradient stopping test.

use basin::{
    BoxBounds, ConstraintDescription, ConstraintSet, Constraints, CostFunction,
    Executor, Gradient, Lbfgsb, Termination,
};
use std::convert::Infallible;

struct BoundedQuadratic {
    lower: Vec<f64>,
    upper: Vec<f64>,
}

impl Constraints for BoundedQuadratic {
    type Set = ConstraintSet<BoxBounds<Vec<f64>>>;

    fn constraints(
        &self,
    ) -> <Self::Set as ConstraintDescription>::Borrowed<'_> {
        ConstraintSet::new()
            .with_bounds(BoxBounds::new(Some(&self.lower), Some(&self.upper)))
    }
}

impl CostFunction for BoundedQuadratic {
    type Param = Vec<f64>;
    type Output = f64;
    type Error = Infallible;

    fn cost(&self, x: &Self::Param) -> Result<f64, Self::Error> {
        Ok((x[0] - 1.0).powi(2) + 4.0 * (x[1] + 2.0).powi(2))
    }
}

impl Gradient for BoundedQuadratic {
    type Gradient = Vec<f64>;

    fn gradient(&self, x: &Self::Param) -> Result<Self::Gradient, Self::Error> {
        Ok(vec![2.0 * (x[0] - 1.0), 8.0 * (x[1] + 2.0)])
    }
}

fn main() {
    let problem = BoundedQuadratic {
        lower: vec![-1.0, -1.0],
        upper: vec![0.5, 1.0],
    };
    let solver = Lbfgsb::new()
        .with_m_capacity(10)
        .with_absolute_projected_gradient_tolerance(1e-8)
        .with_relative_cost_reduction_tolerance(None);

    let result = Executor::from_start(problem, solver, vec![-3.0, 5.0])
        .max_iter(200)
        .run()
        .unwrap();

    assert!(matches!(
        result.report.termination,
        Termination::Converged(_)
    ));
    assert!((result.param()[0] - 0.5).abs() < 1e-7);
    assert!((result.param()[1] + 1.0).abs() < 1e-7);
}

Lbfgsb is the alias for the default bounded mode of Lbfgs. Calling Lbfgs::new() selects the same algorithm; .unbounded() selects unconstrained L-BFGS. Initialization projects this example’s seed to [-1.0, 1.0] before the first objective or gradient evaluation.

Practical considerations

Use a projected stationarity test

At a constrained minimum, the negative gradient can point out of the feasible box. L-BFGS-B tests the infinity norm of its bound-clipped gradient, which vanishes at a box-constrained stationary point. Configure it through with_absolute_projected_gradient_tolerance. The default is 1e-9 for f64 and 1e-10 for f32; choose a threshold for your objective’s scale, parameter units, precision, and derivative accuracy. With numerical gradients, account for approximation error rather than assuming the default is attainable.

Distinguish the stopping reasons

For f64, the solver also stops when the signed cost reduction is at most 10 * f64::EPSILON * max(|f_previous|, |f_current|, 1). Configure the factor with with_relative_cost_reduction_tolerance; this check is disabled by default for f32. The example disables it explicitly so convergence depends on the projected-gradient test. None disables either configurable check, and zero requests an exact-zero threshold.

A small cost reduction alone does not establish stationarity. Inspect the termination report, and keep iteration and evaluation budgets on the executor.

Start with the default history length

Basin retains up to ten curvature pairs by default. with_m_capacity(m) changes this capacity for a fresh solve. Increasing it stores more information and uses more memory, but does not guarantee faster convergence.

Implementation

Basin ports the L-BFGS-B 3.0 Fortran implementation, including its compact curvature model and subspace minimization. Singular or non-positive-definite model factorizations cause it to clear the history and retry. It publishes the current point, objective, and gradient through FirstOrderState; the solver owns the curvature history and work buffers. Fresh solves clear that history and reset the line search; exact solver-and-state checkpoints retain them.

Bounds belong to the problem through Constraints, using a box-only ConstraintSet<BoxBounds<V>>. The solver validates this declaration and rejects unsupported constraint blocks. You can supply another strategy through Lbfgs::with_line_search(search), but it must implement bounded steps. The default line search preserves iteration-wise parity with the Fortran reference.

Supported parameter types are Vec<F>, nalgebra::DVector<F>, ndarray::Array1<F>, and faer::Col<F>, with F = f32 or f64. Parameter storage must be contiguous; strided ndarray views are unsupported. The compact model uses pure-Rust factorizations without a BLAS/LAPACK provider. See the API’s Backends section for the exact capability requirements.

References

  1. Byrd, R. H., Lu, P., Nocedal, J., and Zhu, C. (1995). A limited memory algorithm for bound constrained optimization. SIAM Journal on Scientific Computing, 16(5), 1190–1208. doi:10.1137/0916069.
  2. Zhu, C., Byrd, R. H., Lu, P., and Nocedal, J. (1997). Algorithm 778: L-BFGS-B: Fortran subroutines for large-scale bound-constrained optimization. ACM Transactions on Mathematical Software, 23(4), 550–560. doi:10.1145/279232.279236.
  3. Morales, J. L. and Nocedal, J. (2011). Remark on “Algorithm 778: L-BFGS-B: Fortran subroutines for large-scale bound constrained optimization”. ACM Transactions on Mathematical Software, 38(1), 7:1–7:4. doi:10.1145/2049662.2049669.
  4. Moré, J. J. and Thuente, D. J. (1994). Line search algorithms with guaranteed sufficient decrease. ACM Transactions on Mathematical Software, 20(3), 286–307. doi:10.1145/192115.192132.

Basin v3.1.0 — numerical optimization for Rust.

GitHub docs.rs crates.io