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
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
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> {
    /// Create a new newton object
    #[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 }
    }

    /// Edit the convergence tolerance 
    #[inline]
    pub fn tolerance(&mut self, tolerance: f64 ) {
        self.tol = tolerance;
    }

    /// Edit the finite difference derivative step 
    #[inline]
    pub fn delta(&mut self, delta: f64 ) {
        self.delta = delta;
    }

    /// Edit the maximum number of iterations 
    #[inline]
    pub fn iterations(&mut self, iterations: usize ) {
        self.max_iter = iterations;
    }

    /// Edit the initial guess 
    #[inline]
    pub fn guess(&mut self, guess: T ) {
        self.guess = guess;
    }

}

impl<T: Copy> Newton<T> {
    /// Return the current parameters as a tuple 
    #[inline]
    pub fn parameters(&self) -> ( f64, f64, usize, T ) {
        let parameters = ( self.tol, self.delta, self.max_iter, self.guess );
        parameters
    }
}

impl Newton<f64> {
    /// Solve the equation via Newton iteration 
    #[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> {
    /// Solve the vector equation via Newton iteration 
    #[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 )
    }

    /// Solve the vector equation via Newton iteration using the exact Jacobian
    #[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 )
    }

}