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