Skip to main content

rustyqlib/core/solvers/
mod.rs

1//! Shared 1-D root-finding for the whole library, one algorithm per file.
2//!
3//! Every iterative solve in the pricers routes through here — the BAW
4//! critical-exercise boundary (Newton-Raphson), implied volatility
5//! (safeguarded Newton), the inverse normal CDF polish (Halley) — so the
6//! numerical machinery lives in one maintainable place. Companion
7//! modules: [`fd_solvers`](crate::core::fd_solvers) for the finite-
8//! difference linear kernels and
9//! [`optimization`](crate::core::optimization) for multi-dimensional
10//! model calibration.
11//!
12//! Two ways to call a solver:
13//!
14//! **Direct**, when the method is fixed at the call site — [`Solver1d`]
15//! carries the convergence settings and each method is a call on it:
16//!
17//! ```
18//! use rustyqlib::core::solvers::Solver1d;
19//! let root = Solver1d::default()
20//!     .newton_raphson(|x| x * x - 2.0, |x| 2.0 * x, 1.0);
21//! assert!(root.converged && (root.x - 2.0_f64.sqrt()).abs() < 1e-12);
22//! ```
23//!
24//! **Pluggable**, when the method should be swappable — describe the
25//! problem once and pick the algorithm with [`Method`]; derivatives the
26//! problem does not supply are replaced by central finite differences, so
27//! every method runs on every problem (bracketed methods do require a
28//! bracket):
29//!
30//! ```
31//! use rustyqlib::core::solvers::{Method, Problem, Solver1d};
32//! let f = |x: f64| x * x - 2.0;
33//! let problem = Problem::new(&f, 1.0).with_bracket(0.0, 2.0);
34//! for method in [
35//!     Method::Bisection,
36//!     Method::NewtonRaphson,
37//!     Method::Secant,
38//!     Method::Halley,
39//!     Method::NewtonSafeguarded,
40//! ] {
41//!     let root = Solver1d::default().solve(method, &problem).unwrap();
42//!     assert!((root.x - 2.0_f64.sqrt()).abs() < 1e-9, "{method:?}");
43//! }
44//! ```
45//!
46//! Convergence is on the residual: a solve is converged when
47//! `|f(x)| <= tol`. The bracketed methods additionally stop when the
48//! bracket collapses to machine width. Non-bracketed methods never error:
49//! they return a [`Root`] whose `converged` flag says whether the tolerance
50//! was met, leaving the retry/fallback policy to the caller.
51
52pub mod bisection;
53pub mod halley;
54pub mod newton_raphson;
55pub mod newton_safeguarded;
56pub mod secant;
57pub mod solver_1d;
58
59pub use solver_1d::{Method, Problem, Root, Solver1d};