Skip to main content

Module numdiff

Module numdiff 

Source
Expand description

Finite-difference derivative synthesis.

FiniteDiff wraps a problem that only exposes function values (CostFunction and/or Residual) and adds the derivative traits the solvers want: Gradient (for first-order solvers), Jacobian (for least-squares solvers), and Hessian (for second-order solvers). Each derivative is approximated by finite differences of the wrapped problem, so a values-only problem flows straight into the existing solvers via basin’s type-system dispatch.

The wrapper forwards BoxConstraints when the inner problem carries box bounds — adding derivatives must not silently un-constrain a problem (tenet 4 in CONTRIBUTING.md: an adapter that adds a capability preserves the rest).

§Step sizes (paper-anchored)

  • Gradient and Hessian use Numerical-Recipes-style adaptive steps hⱼ = scale · max(|xⱼ|, 1), with scale = eps_f^{1/3} (central gradient), eps_f^{1/2} (forward gradient), or eps_f^{1/4} (Hessian), where eps_f = function_precision.max(f64::EPSILON) is the assumed relative accuracy of the function. The step is re-rounded so xⱼ + hⱼ is exactly representable.
  • Forward Jacobian reproduces MINPACK fdjac2 exactly: eps = sqrt(eps_f), hⱼ = eps · |xⱼ|, and hⱼ = eps when xⱼ = 0. This is the function-values-only counterpart of MINPACK lmder, i.e. the lmdif Jacobian — chosen as the default so least-squares fits via FiniteDiff match lmdif’s convergence lineage.

§Caveats

  • Evaluation counting. One counted Gradient::gradient, Jacobian::jacobian, or Hessian::hessian call performs many internal cost/residual evaluations (2n central / n+1 forward gradient, n+1 / 2n Jacobian columns, ~2n² Hessian). Eval counting lives on the solver State and is incremented by the solver per derivative call, so a problem wrapper has no way to record the inner calls — result.cost_evals() will not reflect them. Users who need true cost-evaluation budgets should account for the O(n)/O(n²) multiplier themselves.
  • Domain & hard-abort. Each probe ?-propagates the inner function’s Error. If the inner cost / residual returns Err, the derivative call returns the same Err — no swallowing, no partial result. A point where the inner function soft-rejects (Ok(f64::INFINITY)) poisons the derivative with ±∞ rather than aborting; keeping probes inside the strict domain (e.g. via FiniteDiff::function_precision or FiniteDiff::with_step) is the caller’s responsibility.

§Parallelism (parallel feature)

The probes of one derivative are independent, so with the parallel feature they fan across a rayon thread pool: the n gradient/Jacobian columns, and the n(n+1)/2 upper-triangular Hessian entries, are evaluated concurrently (the shared f(x) / r(x) base evaluation runs once up front). The result is bit-identical to the sequential path — each output slot is written independently and collected in order, with no floating-point reduction — so enabling the feature never changes the numbers, only the wall-clock.

This is a win when the wrapped cost / residual is expensive; for a cheap function at small n the thread-pool overhead can exceed the saving, so it is opt-in. Under the feature, FiniteDiff’s Gradient / Jacobian / Hessian impls additionally require the wrapped problem (and its param vector / error type) to be Sync / Send; without the feature there is no such bound and the evaluation is sequential.

Structs§

FiniteDiff
Wraps a problem to synthesize its derivatives by finite differences.

Enums§

Method
Which finite-difference stencil to use for a given derivative.

Functions§

central_difference_gradient
Central-difference gradient ∇f(x)ⱼ ≈ (f(x+hⱼeⱼ) − f(x−hⱼeⱼ)) / 2hⱼ.
central_difference_hessian
Central-difference Hessian (Numerical Recipes second differences).
central_difference_jacobian
Central-difference Jacobian, column j ≈ (r(x+hⱼeⱼ) − r(x−hⱼeⱼ)) / 2hⱼ.
forward_difference_gradient
Forward-difference gradient ∇f(x)ⱼ ≈ (f(x+hⱼeⱼ) − f(x)) / hⱼ.
forward_difference_hessian
Forward-difference Hessian (one-sided second differences).
forward_difference_jacobian
Forward-difference Jacobian, column j ≈ (r(x+hⱼeⱼ) − r(x)) / hⱼ.