Skip to main content

FiniteDiff

Struct FiniteDiff 

Source
pub struct FiniteDiff<P> { /* private fields */ }
Expand description

Wraps a problem to synthesize its derivatives by finite differences.

Construct with FiniteDiff::new (central gradient and Hessian, forward Jacobian; see the module docs) and adjust with the builder methods. The wrapper delegates CostFunction/Residual / all constraint traits to the inner problem and implements Gradient, Jacobian, crate::ConstraintJacobian, and Hessian via finite differences.

§Backends

Gradient and HessianProduct are backend-generic (any V: Clone + VectorLen + VectorIndex; no matrix type is involved). Jacobian and Hessian additionally require V: DenseMatrixFromFn, so they are available for Vec<f64>/DenseMatrix, nalgebra DVector<f64>/DMatrix, ndarray Array1<f64>/Array2, and faer Col<f64>/Mat. crate::ConstraintJacobian uses the parameter backend’s dense matrix, independently of the linear block matrices. Use BoundedFiniteDiff for f32 first derivatives.

§Solver stopping tolerances

The synthesized gradient has truncation and rounding error, so it can be nonzero at an exact minimum. Choose the solver’s gradient stopping tolerance to account for that error in the problem’s units. A threshold below the derivative error can cause extra evaluations or a line-search failure even after reaching an accurate solution. Central differences often reduce truncation error, but do not guarantee a particular stopping accuracy. function_precision controls probe step sizes; it is not a bound on gradient error. Objective scaling, curvature, parameter magnitudes, and evaluation noise also affect that error. See Lbfgs for a forward-difference stopping example.

§Examples

Run a gradient solver against a problem that only implements CostFunction: wrapping it in FiniteDiff synthesizes the Gradient by central differences.

use basin::{
    FirstOrderState, CostFunction, Executor, FiniteDiff, GradientDescent};

struct Sphere;
impl basin::ProblemConstraints for Sphere  {
    type Constraints = basin::NoConstraints;
    fn constraint_set(&self) -> basin::NoConstraints { basin::NoConstraints::EMPTY }
}
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())
    }
}

let result = Executor::new(
    FiniteDiff::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-10);

Implementations§

Source§

impl<P> FiniteDiff<P>

Source

pub fn with_bounds<V: VectorLen + VectorIndex>( self, lower: V, upper: V, ) -> BoundedFiniteDiff<P>

Transfer first-derivative settings into a BoundedFiniteDiff. The resulting adapter supports gradients and Jacobians only. Hessian settings have no effect on its first derivatives.

Source§

impl<P> FiniteDiff<P>

Source

pub fn new(problem: P) -> Self

Wrap problem with default settings: central-difference gradient and Hessian, forward-difference (MINPACK fdjac2) Jacobian, function_precision = f64::EPSILON, adaptive step sizes.

Source

pub fn gradient_method(self, method: Method) -> Self

Set the stencil used for the gradient (default Method::Central).

Source

pub fn jacobian_method(self, method: Method) -> Self

Set the stencil used for the Jacobian (default Method::Forward, the MINPACK fdjac2 parity choice).

Source

pub fn hessian_method(self, method: Method) -> Self

Set the stencil used for the Hessian (default Method::Central).

Source

pub fn function_precision(self, epsfcn: f64) -> Self

Set the assumed relative accuracy of the wrapped function (MINPACK’s epsfcn). Larger values widen the step, which helps when the function is noisy. Floored at f64::EPSILON. Default f64::EPSILON.

Source

pub fn with_step(self, h: f64) -> Self

Override the adaptive step rule with a fixed absolute step h used for every coordinate. Escape hatch; most callers should leave the adaptive |xⱼ|-scaled rule in place.

Source

pub fn get_ref(&self) -> &P

Borrow the wrapped problem.

Source

pub fn into_inner(self) -> P

Unwrap and return the inner problem.

Trait Implementations§

Source§

impl<P: Clone> Clone for FiniteDiff<P>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<P, V> ConstraintJacobian for FiniteDiff<P>
where P: CostFunction<Param = V, Output = f64> + MaybeSync, P::Constraints: NonlinearSet<P, V, f64>, V: Clone + VectorLen + VectorIndex<f64> + DenseMatrixFromFn<f64> + MaybeSync, P::Error: MaybeSend,

Source§

type Param = V

Parameter type.
Source§

type Jacobian = <V as DenseMatrixFromFn>::Matrix

Nonlinear Jacobian storage.
Source§

type Error = <P as CostFunction>::Error

Original callback error type.
Source§

fn constraint_jacobian( &self, x: &V, ) -> Result<Self::Jacobian, ConstraintSolveError<P::Error>>

Evaluate equality rows first, followed by inequality rows.
Source§

impl<P: Copy> Copy for FiniteDiff<P>

Source§

impl<P: CostFunction> CostFunction for FiniteDiff<P>

Source§

type Param = <P as CostFunction>::Param

The parameter type the objective is defined over.
Source§

type Output = <P as CostFunction>::Output

Scalar cost type. In practice f64 (see CONTRIBUTING.md’s provisional choices).
Source§

type Error = <P as CostFunction>::Error

User-chosen hard-abort error. Pick std::convert::Infallible when the cost cannot fail: its niche optimization keeps Result<f64, Infallible> the same layout as bare f64 on the happy path.
Source§

fn cost(&self, param: &Self::Param) -> Result<Self::Output, Self::Error>

Evaluate the objective at param.
Source§

impl<P: Debug> Debug for FiniteDiff<P>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<P, V> Gradient for FiniteDiff<P>
where P: CostFunction<Param = V, Output = f64> + MaybeSync, V: Clone + VectorLen + VectorIndex + MaybeSync, <P as CostFunction>::Error: MaybeSend,

Source§

type Gradient = V

The gradient type. Typically the same as CostFunction::Param.
Source§

fn gradient(&self, param: &V) -> Result<V, P::Error>

Evaluate the gradient at param.
Source§

fn cost_and_gradient( &self, param: &Self::Param, ) -> Result<(Self::Output, Self::Gradient), Self::Error>

Evaluate cost and gradient at param in one call. The default body delegates to CostFunction::cost and Gradient::gradient; override when shared intermediate work can be amortized across the two. Read more
Source§

impl<P, V> Hessian for FiniteDiff<P>
where P: CostFunction<Param = V, Output = f64> + MaybeSync, V: Clone + VectorLen + VectorIndex + DenseMatrixFromFn + MaybeSync, <P as CostFunction>::Error: MaybeSend,

Source§

type Hessian = <V as DenseMatrixFromFn>::Matrix

The Hessian matrix type, shape n × n and symmetric.
Source§

fn hessian(&self, param: &V) -> Result<Self::Hessian, P::Error>

Evaluate the Hessian at param.
Source§

fn cost_and_gradient_and_hessian( &self, param: &Self::Param, ) -> Result<(<Self as CostFunction>::Output, <Self as Gradient>::Gradient, Self::Hessian), <Self as CostFunction>::Error>

Evaluate cost, gradient, and Hessian at param in one call. The default body delegates to Gradient::cost_and_gradient followed by Hessian::hessian; override when all three share intermediate work. Read more
Source§

impl<P, V> HessianProduct for FiniteDiff<P>
where P: CostFunction<Param = V, Output = f64> + MaybeSync, V: Clone + VectorLen + VectorIndex + MaybeSync, <P as CostFunction>::Error: MaybeSend,

Source§

fn hessian_product(&self, param: &V, v: &V) -> Result<V, P::Error>

Hessian-vector product by differencing this wrapper’s own finite-difference gradients along v (stencil set by hessian_method). Note this stacks two truncation errors (FD of FD): it is the no-analytic-anything fallback. With an analytic Gradient, skip the wrapper and call forward_difference_hessian_product / central_difference_hessian_product directly (2 gradient evaluations per product). Cost here is 2 synthesized gradients: ~4n cost evaluations with the central/central default.

Source§

impl<P, V> Jacobian for FiniteDiff<P>
where P: Residual<Param = V, Output = V> + MaybeSync, V: Clone + VectorLen + VectorIndex + DenseMatrixFromFn + MaybeSync + MaybeSend, <P as Residual>::Error: MaybeSend,

Source§

type Jacobian = <V as DenseMatrixFromFn>::Matrix

The Jacobian matrix type, shape m × n.
Source§

fn jacobian(&self, param: &V) -> Result<Self::Jacobian, P::Error>

Evaluate the Jacobian at param.
Source§

fn residual_and_jacobian( &self, param: &Self::Param, ) -> Result<(<Self as Residual>::Output, Self::Jacobian), <Self as Residual>::Error>

Evaluate residual and Jacobian at param in one call. The default body delegates to Residual::residual and Jacobian::jacobian; override when shared intermediate work can be amortized across the two, common in NLLS where r(x) reuses forward-mode AD state that J(x) continues from. Read more
Source§

impl<P> NonlinearEqualityValues for FiniteDiff<P>

Source§

type Param = <P as NonlinearEqualityValues>::Param

Parameter type.
Source§

type Values = <P as NonlinearEqualityValues>::Values

Readable vector of equality residuals.
Source§

type Error = <P as NonlinearEqualityValues>::Error

Original callback error type.
Source§

fn nonlinear_equalities( &self, x: &Self::Param, ) -> Result<Self::Values, ConstraintSolveError<Self::Error>>

Evaluate h(x) = 0.
Source§

impl<P> NonlinearInequalityValues for FiniteDiff<P>

Source§

type Param = <P as NonlinearInequalityValues>::Param

Parameter type.
Source§

type Values = <P as NonlinearInequalityValues>::Values

Readable vector of constraint values, independent of the parameter type.
Source§

type Error = <P as NonlinearInequalityValues>::Error

Original callback error type.
Source§

fn nonlinear_inequalities( &self, x: &Self::Param, ) -> Result<Self::Values, ConstraintSolveError<Self::Error>>

Evaluate the inequalities in the public c(x) <= 0 convention.
Source§

impl<P> ProblemConstraints for FiniteDiff<P>

Source§

type Constraints = <P as ProblemConstraints>::Constraints

The complete constraint set. Its type determines solver compatibility.
Source§

fn constraint_set( &self, ) -> <Self::Constraints as ConstraintDescription>::Borrowed<'_>

Borrow the complete set without evaluating the problem.
Source§

impl<P: Residual> Residual for FiniteDiff<P>

Source§

type Param = <P as Residual>::Param

The parameter type the residual is defined over (matches CostFunction::Param).
Source§

type Output = <P as Residual>::Output

The residual vector type. Length is the number of residuals m, independent of param.len() = n.
Source§

type Error = <P as Residual>::Error

User-chosen hard-abort error. Independent of CostFunction::Error: the trait families are orthogonal (NLLS solvers bind on Residual + Jacobian; first-order solvers bind on CostFunction + Gradient).
Source§

fn residual(&self, param: &Self::Param) -> Result<Self::Output, Self::Error>

Evaluate the residual at param.

Auto Trait Implementations§

§

impl<P> Freeze for FiniteDiff<P>
where P: Freeze,

§

impl<P> RefUnwindSafe for FiniteDiff<P>
where P: RefUnwindSafe,

§

impl<P> Send for FiniteDiff<P>
where P: Send,

§

impl<P> Sync for FiniteDiff<P>
where P: Sync,

§

impl<P> Unpin for FiniteDiff<P>
where P: Unpin,

§

impl<P> UnsafeUnpin for FiniteDiff<P>
where P: UnsafeUnpin,

§

impl<P> UnwindSafe for FiniteDiff<P>
where P: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> ByRef<T> for T

Source§

fn by_ref(&self) -> &T

Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Imply<T> for U
where T: ?Sized, U: ?Sized,

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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 more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V