pub struct Lbfgs<Mode = Bounded, S = MoreThuente, F = f64> { /* private fields */ }Expand description
Limited-memory BFGS, parameterised over a type-state mode marker.
Lbfgs<Bounded> (aliased as Lbfgsb) is a faithful port of
Byrd–Lu–Nocedal 1995 / Zhu–Byrd–Lu–Nocedal 1997 (ACM TOMS Alg. 778),
with the Nocedal–Morales 2011 v3.0 directional-derivative + bound-
backtracking deviation in subspace minimization. Iteration-wise
parity with the Fortran v3.0 reference (references/lbfgsb-v3.0/)
is verified by tests/lbfgsb_iter_parity.rs.
Lbfgs<Unbounded> is unconstrained limited-memory BFGS via
Nocedal–Wright’s two-loop recursion (Algorithm 7.4). It reuses the
same LbfgsState history machinery but skips the Cauchy /
freev / subsm phases — those are box-constraint-specific.
Construct with Lbfgs::<Unbounded>::new(), or transition from
the default Lbfgs::<Bounded>::new() via Lbfgs::unbounded.
§Bounded mode — per-iteration outline
- Walks the projected gradient ray, building a piecewise-quadratic
model and identifying the generalized Cauchy point
xcp— the minimizer along the path (see thecauchysubmodule). - Restricts to the free variables at
xcpand computes an approximate subspace minimizer via a structured Newton step against the limited-memory compact-form Hessian (see thesubsmsubmodule). If the projected Newton step is infeasible, a uniform-α bound-backtracking branch fires. - Performs a Moré–Thuente line search along
d = z − x, safeguarded so the step is feasible. - Accepts the step, updates the limited-memory
(s, y)history when the curvature condition holds, and rebuilds the compact-form middle matrixTvia Cholesky factorization (seecompact::formt).
On a singular middle-matrix or non-positive-definite T, the
solver clears the history and retries the iteration (Fortran’s
goto 222 reset path). One retry is enough — after clearing,
col = 0 falls through to the line-search-only path, which
either succeeds with the projected steepest-descent direction or
fails the whole solve.
§Unbounded mode — per-iteration outline
- Two-loop recursion (Nocedal–Wright Alg. 7.4) over the
(s_i, y_i)history with initial HessianH₀ = (1/θ)·I(θ = (y_last·y_last) / (s_last·y_last)after the first accepted update) to produced = −H_k · ∇f. - Moré–Thuente line search along
d. - Curvature-conditioned limited-memory update (same as bounded).
§Memory parameter
The history capacity m lives on LbfgsState:
LbfgsState::new(x0, m). Fortran recommends m ∈ [3, 20];
m = 10 is a reasonable default.
§Termination
No solver-internal optimality test on the unbounded path — pair with
the framework-level
GradientTolerance.
On the bounded path, a built-in projected-gradient check fires
when ‖projgr(x, g, l, u)‖_∞ ≤ tol_pg (Fortran-pgtol parity);
the framework-level
ProjectedGradientTolerance
is the canonical companion when external bookkeeping wants the same
metric. Pair either mode with
MaxIter,
MaxCostEvals, and
CostTolerance as
desired.
§Backends
Generic over any parameter type implementing
AsFloatSliceMut<F> + Clone + Dot<F> +
ScaledAdd<F>. Built-in impls cover Vec<F>,
nalgebra::DVector<F> (feature nalgebra), faer::Col<F>
(feature faer), and ndarray::Array1<F> (feature ndarray).
Other backends can implement the trait if their storage is
contiguous.
§Examples
See Bfgs for the quasi-Newton Executor pattern.
L-BFGS iterates an LbfgsState sized to the history length m
(LbfgsState::new(x0, m)); construct the solver with Lbfgs::new()
(L-BFGS-B, the default) or Lbfgs::<Unbounded>::new().
Implementations§
Source§impl Lbfgs<Bounded, MoreThuente>
impl Lbfgs<Bounded, MoreThuente>
Source§impl Lbfgs<Unbounded, MoreThuente>
impl Lbfgs<Unbounded, MoreThuente>
Sourcepub fn new() -> Self
pub fn new() -> Self
Unconstrained L-BFGS with Moré–Thuente line search and the same
curvature-skip / history defaults as the bounded path. The
tol_pg field is unused in this mode — terminate via the
framework-level
GradientTolerance.
Source§impl<S, F: Scalar> Lbfgs<Bounded, S, F>
impl<S, F: Scalar> Lbfgs<Bounded, S, F>
Sourcepub fn with_line_search(line_search: S) -> Self
pub fn with_line_search(line_search: S) -> Self
L-BFGS-B with an explicit line-search strategy. Note: using
anything other than MoreThuente forfeits iteration-wise
parity with the Fortran reference. The curvature-skip threshold
defaults to F::epsilon() (matching f64::EPSILON when
F = f64); tol_pg defaults to 1e-10.
Sourcepub fn with_tol_pg(self, tol_pg: F) -> Self
pub fn with_tol_pg(self, tol_pg: F) -> Self
Override the built-in projected-gradient convergence tolerance.
Default 1e-10; pass 0.0 to disable (Fortran-pgtol=0
semantics, used by the iteration-wise parity test). Bounded
mode only — the unbounded path doesn’t compute a projected
gradient.
Source§impl<S, F: Scalar> Lbfgs<Unbounded, S, F>
impl<S, F: Scalar> Lbfgs<Unbounded, S, F>
Sourcepub fn with_line_search(line_search: S) -> Self
pub fn with_line_search(line_search: S) -> Self
Unconstrained L-BFGS with an explicit line-search strategy. The
curvature-skip threshold defaults to F::epsilon() (matching
f64::EPSILON when F = f64).
Source§impl<Mode, S, F: Scalar> Lbfgs<Mode, S, F>
impl<Mode, S, F: Scalar> Lbfgs<Mode, S, F>
Sourcepub fn with_epsilon(self, epsilon: F) -> Self
pub fn with_epsilon(self, epsilon: F) -> Self
Override the curvature-skip threshold. Default F::epsilon()
(= f64::EPSILON when F = f64), matching Fortran’s
dr ≤ epsmch · ddum test.
Sourcepub fn with_m_capacity(self, m_capacity: usize) -> Self
pub fn with_m_capacity(self, m_capacity: usize) -> Self
Override the default limited-memory history capacity used when
the solver constructs its own LbfgsState (memetic seeding).
Standalone usage that hands in a state via LbfgsState::new(x, m)
is unaffected. Default 10; Nocedal recommends [3, 20].
§Panics
Panics if m_capacity == 0.
Trait Implementations§
Source§impl<S, V, F> MemeticInner<V, F> for Lbfgs<Bounded, S, F>
impl<S, V, F> MemeticInner<V, F> for Lbfgs<Bounded, S, F>
Source§impl<P, V, S, F> Solver<P, LbfgsState<V, F>> for Lbfgs<Bounded, S, F>where
F: Scalar,
P: CostFunction<Param = V, Output = F> + Gradient<Gradient = V> + BoxConstraints,
V: AsFloatSliceMut<F> + Clone + Dot<F> + ScaledAdd<F>,
S: LineSearch<P, V, F, Error = P::Error>,
impl<P, V, S, F> Solver<P, LbfgsState<V, F>> for Lbfgs<Bounded, S, F>where
F: Scalar,
P: CostFunction<Param = V, Output = F> + Gradient<Gradient = V> + BoxConstraints,
V: AsFloatSliceMut<F> + Clone + Dot<F> + ScaledAdd<F>,
S: LineSearch<P, V, F, Error = P::Error>,
Source§type Error = <P as CostFunction>::Error
type Error = <P as CostFunction>::Error
type Error. See the trait docs.Source§fn init(
&mut self,
problem: &mut Problem<P>,
state: LbfgsState<V, F>,
) -> Result<LbfgsState<V, F>, Self::Error>
fn init( &mut self, problem: &mut Problem<P>, state: LbfgsState<V, F>, ) -> Result<LbfgsState<V, F>, Self::Error>
Source§fn next_iter(
&mut self,
problem: &mut Problem<P>,
state: LbfgsState<V, F>,
) -> Result<(LbfgsState<V, F>, Option<TerminationReason>), Self::Error>
fn next_iter( &mut self, problem: &mut Problem<P>, state: LbfgsState<V, F>, ) -> Result<(LbfgsState<V, F>, Option<TerminationReason>), Self::Error>
Source§impl<P, V, S, F> Solver<P, LbfgsState<V, F>> for Lbfgs<Unbounded, S, F>where
F: Scalar,
P: CostFunction<Param = V, Output = F> + Gradient<Gradient = V>,
V: AsFloatSliceMut<F> + Clone + Dot<F> + ScaledAdd<F>,
S: LineSearch<P, V, F, Error = P::Error>,
impl<P, V, S, F> Solver<P, LbfgsState<V, F>> for Lbfgs<Unbounded, S, F>where
F: Scalar,
P: CostFunction<Param = V, Output = F> + Gradient<Gradient = V>,
V: AsFloatSliceMut<F> + Clone + Dot<F> + ScaledAdd<F>,
S: LineSearch<P, V, F, Error = P::Error>,
Source§type Error = <P as CostFunction>::Error
type Error = <P as CostFunction>::Error
type Error. See the trait docs.Source§fn init(
&mut self,
problem: &mut Problem<P>,
state: LbfgsState<V, F>,
) -> Result<LbfgsState<V, F>, Self::Error>
fn init( &mut self, problem: &mut Problem<P>, state: LbfgsState<V, F>, ) -> Result<LbfgsState<V, F>, Self::Error>
Source§fn next_iter(
&mut self,
problem: &mut Problem<P>,
state: LbfgsState<V, F>,
) -> Result<(LbfgsState<V, F>, Option<TerminationReason>), Self::Error>
fn next_iter( &mut self, problem: &mut Problem<P>, state: LbfgsState<V, F>, ) -> Result<(LbfgsState<V, F>, Option<TerminationReason>), Self::Error>
Auto Trait Implementations§
impl<Mode, S, F> Freeze for Lbfgs<Mode, S, F>
impl<Mode, S, F> RefUnwindSafe for Lbfgs<Mode, S, F>where
S: RefUnwindSafe,
F: RefUnwindSafe,
impl<Mode, S, F> Send for Lbfgs<Mode, S, F>
impl<Mode, S, F> Sync for Lbfgs<Mode, S, F>
impl<Mode, S, F> Unpin for Lbfgs<Mode, S, F>
impl<Mode, S, F> UnsafeUnpin for Lbfgs<Mode, S, F>where
S: UnsafeUnpin,
F: UnsafeUnpin,
impl<Mode, S, F> UnwindSafe for Lbfgs<Mode, S, F>where
S: UnwindSafe,
F: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<T, U> Imply<T> for U
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.