use super::*;
pub struct RootFinderBuilder<'a> {
method: RootFindingMethod,
initial_guess: Option<f64>,
boundaries: Option<(f64, f64)>,
tolerance: Option<f64>,
max_iterations: Option<usize>,
log_convergence: Option<bool>,
function: Option<&'a F>, derivative: Option<&'a F>, }
impl<'a> RootFinderBuilder<'a> {
pub fn new(method: RootFindingMethod) -> Self {
Self {
method,
initial_guess: None,
boundaries: None,
tolerance: None,
max_iterations: None,
log_convergence: None,
function: None,
derivative: None,
}
}
pub fn initial_guess(mut self, guess: f64) -> Self {
self.initial_guess = Some(guess);
self
}
pub fn boundaries(mut self, x0: f64, x1: f64) -> Self {
self.boundaries = Some((x0, x1));
self
}
pub fn tolerance(mut self, tol: f64) -> Self {
self.tolerance = Some(tol);
self
}
pub fn max_iterations(mut self, max: usize) -> Self {
self.max_iterations = Some(max);
self
}
pub fn log_convergence(mut self, log: bool) -> Self {
self.log_convergence = Some(log);
self
}
pub fn function(mut self, function: &'a F) -> Self {
self.function = Some(function);
self
}
pub fn derivative(mut self, derivative: &'a F) -> Self {
self.derivative = Some(derivative);
self
}
pub fn build(self) -> Result<RootFindingIterationDecorator<'a>, String> {
let function = self.function.ok_or("Function must be specified")?;
let tolerance = self.tolerance.ok_or("Tolerance must be specified.")?;
let max_iterations = self
.max_iterations
.ok_or("Max iterations must be specified.")?;
let log_convergence = self.log_convergence.unwrap_or(false);
let rf: Result<Box<dyn RootFinder + 'a>, String> = match self.method {
RootFindingMethod::NewtonRaphson => {
let initial_guess = self
.initial_guess
.ok_or("Initial guess must be specified")?;
Ok(Box::new(newton_raphson::NewtonRaphsonRootFinder {
x0: initial_guess,
tolerance,
}))
}
RootFindingMethod::Secant => {
let boundaries = self
.boundaries
.ok_or("Derivative must be specified for Secant method.")?;
Ok(Box::new(secant::SecantRootFinder {
x0: boundaries.0,
x1: boundaries.1,
x2: f64::NAN,
tolerance,
}))
}
RootFindingMethod::Bisection => {
let boundaries = self
.boundaries
.ok_or("Derivative must be specified for Bisection method.")?;
Ok(Box::new(bisection::BisectionRootFinder {
x0: boundaries.0,
x1: boundaries.1,
tolerance,
search_left: true,
}))
}
_ => Err("Unsupported method in this example.".to_string()),
};
Ok(RootFindingIterationDecorator::new(
function,
self.derivative,
rf?,
max_iterations,
log_convergence,
))
}
}