Implementation:Avhz RustQuant Brent Method
| Knowledge Sources | |
|---|---|
| Domains | Numerical_Methods, Mathematics |
| Last Updated | 2026-02-07 19:00 GMT |
Overview
Concrete implementation of the Brent root-finding algorithm provided by the RustQuant library.
Description
The Brent struct implements a hybrid root-finding method that combines bisection, secant, and inverse quadratic interpolation. Brent's method is renowned for its guaranteed convergence (like bisection) while typically achieving superlinear convergence speed (like the secant method). The implementation follows the classic Brent algorithm: at each iteration it evaluates whether to use inverse quadratic interpolation or the secant step, falling back to bisection whenever those faster methods would step outside the bracketing interval or fail to reduce the interval sufficiently.
The solver first performs a bracket-search phase in the solve() method. Starting from an initial guess, it expands the search interval using a growth factor of 1.6, alternating expansion direction via a flip-flop mechanism, until it finds a sign change (i.e., y_min * y_max <= 0). Once a valid bracket is established, it delegates to solve_impl() which runs the core Brent iteration. The convergence check uses a tolerance of 2 * EPSILON * |root| + 0.5 * accuracy and also checks whether f(root) is close to zero using the RootfinderData::close utility.
The struct is generic over the objective function F: Fn(f64) -> f64 and implements the Rootfinder trait. It stores the function, an initial guess, and a RootfinderData configuration that holds accuracy, step size, bounds, and iteration state. The derivative() method returns 0.0 since Brent's method does not require derivative information.
Usage
Use the Brent method when you need a robust, derivative-free root finder that combines guaranteed convergence with fast performance. It is particularly well-suited for implied volatility calculations and other quantitative finance problems where the function is continuous but the derivative is unavailable or expensive to compute. The included test suite demonstrates using it for both a simple polynomial root (x^2 - 2) and Black-Scholes implied volatility recovery.
Code Reference
Source Location
- Repository: RustQuant
- File: crates/RustQuant_math/src/rootfinding/brent.rs
- Lines: 1-301
Signature
pub struct Brent<F>
where
F: Fn(f64) -> f64,
{
function: F,
guess: f64,
data: RootfinderData,
}
impl<F> Brent<F>
where
F: Fn(f64) -> f64,
{
pub fn new(function: F, guess: f64, data: RootfinderData) -> Self;
}
impl<F> Rootfinder<F> for Brent<F>
where
F: Fn(f64) -> f64,
{
fn value(&self, x: f64) -> f64;
fn derivative(&self, _: f64) -> f64; // returns 0.0 (not used)
fn solve_impl(&mut self) -> f64;
fn solve(&mut self) -> f64;
}
Import
use RustQuant::math::rootfinding::{Brent, RootfinderData, Rootfinder};
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| function | F: Fn(f64) -> f64 |
Yes | The objective function whose root is sought |
| guess | f64 |
Yes | Initial guess for the root location |
| data | RootfinderData |
Yes | Configuration containing accuracy, step size, bounds, and interval enforcement flag |
Outputs
| Name | Type | Description |
|---|---|---|
| root | f64 |
The computed root of the objective function, or 0.0 if maximum iterations exceeded
|
Usage Examples
use RustQuant::math::rootfinding::{Brent, RootfinderData, Rootfinder};
use std::f64::consts::SQRT_2;
// Define the objective function: f(x) = x^2 - 2
let f = |x: f64| x.powi(2) - 2.0;
// Create root-finder configuration:
// accuracy = 1e-15, step_size = 1e-5,
// lower_bound = 0.0, upper_bound = 2.0,
// interval_enforced = true
let data = RootfinderData::new(1e-15, 1e-5, 0.0, 2.0, true);
// Construct the Brent solver with initial guess = 1.0
let mut solver = Brent::new(f, 1.0, data);
let root = solver.solve();
// root is approximately sqrt(2)
assert!((root - SQRT_2).abs() < 1e-15);