Implementation:Avhz RustQuant Bisection Method
| Knowledge Sources | |
|---|---|
| Domains | Numerical_Methods, Mathematics |
| Last Updated | 2026-02-07 19:00 GMT |
Overview
Concrete implementation of the Bisection root-finding algorithm provided by the RustQuant library.
Description
The Bisection struct implements the classic bisection method for finding roots of continuous functions. The algorithm works by repeatedly halving an interval that is known to contain a root (identified by a sign change in the function values at the endpoints). At each step, the midpoint is evaluated and the sub-interval that still brackets the root is selected. This guarantees convergence at a linear rate, reducing the interval width by half on every iteration.
The implementation follows a two-phase approach. The solve() method first performs a bracket-search phase: starting from the 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 endpoints where y_min * y_max <= 0 (a sign change). Once a valid bracket is established, it delegates to solve_impl() which executes the core bisection loop. The search is oriented so that f > 0 lies at root + dx, and in each iteration dx is halved. The loop terminates when |dx| < accuracy or when f(x_mid) is close to zero (using RootfinderData::close).
The struct is generic over the objective function F: Fn(f64) -> f64 and implements the Rootfinder trait. The derivative() method returns 0.0 since bisection does not require derivative information. The maximum number of iterations is inherited from the trait constant MAX_ITERATIONS = 1000.
Usage
Use the Bisection method when you need a simple, reliable, and guaranteed-to-converge root finder. It is the safest choice when the function is continuous and you can identify a bracket, but it converges more slowly than Brent's method or Newton-Raphson. It is well-suited for situations where robustness is more important than speed, or as a baseline reference implementation.
Code Reference
Source Location
- Repository: RustQuant
- File: crates/RustQuant_math/src/rootfinding/bisection.rs
- Lines: 1-193
Signature
pub struct Bisection<F>
where
F: Fn(f64) -> f64,
{
function: F,
guess: f64,
data: RootfinderData,
}
impl<F> Bisection<F>
where
F: Fn(f64) -> f64,
{
pub fn new(function: F, guess: f64, data: RootfinderData) -> Self;
}
impl<F> Rootfinder<F> for Bisection<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::{Bisection, 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::{Bisection, 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 Bisection solver with initial guess = 1.0
let mut solver = Bisection::new(f, 1.0, data);
let root = solver.solve();
// root is approximately sqrt(2)
assert!((root - SQRT_2).abs() < 1e-15);