pub use crate::traits::{Number, Signed, Zero, One};
pub use crate::complex::Complex;
pub use crate::vector::{Vector, Vec64};
pub use crate::matrix::{Matrix, Mat64};
pub struct Newton<T> {
tol: f64,
delta: f64,
max_iter: usize,
guess: T,
}
impl<T> Newton<T> {
#[inline]
pub const fn new( guess: T ) -> Self {
let tol: f64 = 1.0e-8;
let delta: f64 = 1.0e-8;
let max_iter: usize = 20;
Newton { tol, delta, max_iter, guess }
}
#[inline]
pub fn tolerance(&mut self, tolerance: f64 ) {
self.tol = tolerance;
}
#[inline]
pub fn delta(&mut self, delta: f64 ) {
self.delta = delta;
}
#[inline]
pub fn iterations(&mut self, iterations: usize ) {
self.max_iter = iterations;
}
#[inline]
pub fn guess(&mut self, guess: T ) {
self.guess = guess;
}
}
impl<T: Copy> Newton<T> {
#[inline]
pub fn parameters(&self) -> ( f64, f64, usize, T ) {
let parameters = ( self.tol, self.delta, self.max_iter, self.guess );
parameters
}
}
impl Newton<f64> {
#[inline]
pub fn solve(&self, func: &dyn Fn(f64) -> f64 ) -> Result<f64, f64> {
let mut current: f64 = self.guess;
for _ in 0..self.max_iter {
let deriv = ( func( current + self.delta ) -
func( current - self.delta ) ) / ( 2.0 * self.delta );
let dx = func(current) / deriv;
current -= dx;
if dx.abs() <= self.tol {
return Ok( current );
}
}
Err( current )
}
}
impl Newton<Vec64> {
#[inline]
pub fn solve(&self, func: &dyn Fn(Vec64) -> Vec64) -> Result<Vec64, Vec64> {
let mut current: Vec64 = self.guess.clone();
for _ in 0..self.max_iter {
let f: Vec64 = func( current.clone() );
let max_residual = f.norm_inf();
let mut j = Mat64::jacobian( current.clone(), func, self.delta );
let dx: Vec64 = j.solve_basic( f );
current -= dx;
if max_residual <= self.tol {
return Ok( current )
}
}
Err( current )
}
#[inline]
pub fn solve_jacobian(&self, func: &dyn Fn(Vec64) -> Vec64,
jac: &dyn Fn(Vec64) -> Mat64 ) -> Result<Vec64, Vec64> {
let mut current: Vec64 = self.guess.clone();
for _ in 0..self.max_iter {
let f: Vec64 = func( current.clone() );
let max_residual = f.norm_inf();
let mut j: Mat64 = jac( current.clone() );
let dx: Vec64 = j.solve_basic( f );
current -= dx;
if max_residual <= self.tol {
return Ok( current )
}
}
Err( current )
}
}