1use super::FloatType;
26use std::error::Error;
27use std::fmt;
28
29#[derive(Debug, PartialEq)]
31pub struct Sample<F>
32where
33    F: FloatType,
34{
35    x: F,
37    y: F,
39}
40
41impl<F> Sample<F>
42where
43    F: FloatType,
44{
45    fn is_bracketed_with(&self, other: &Self) -> bool {
46        self.y * other.y <= F::zero()
47    }
48}
49
50#[derive(Debug, PartialEq)]
52pub struct Interval<F>
53where
54    F: FloatType,
55{
56    begin: Sample<F>,
58    end: Sample<F>,
60}
61
62impl<F> Interval<F>
63where
64    F: FloatType,
65{
66    fn is_bracketed(&self) -> bool {
67        self.begin.is_bracketed_with(&self.end)
68    }
69    fn is_converged(&self, convergency: &mut dyn Convergency<F>) -> bool {
70        convergency.is_converged(self.begin.x, self.end.x)
71    }
72    fn contains_x(&self, x: &F) -> bool {
74        *x <= self.end.x && *x >= self.begin.x
75    }
76    fn middle(&self) -> F {
82        let _2 = F::from(2i16);
83        let _26 = F::from(26i16);
84        let _27 = F::from(27i16);
85
86        if self.is_bracketed() && self.begin.y != self.end.y {
87            let mut shift = -self.begin.y * (self.end.x - self.begin.x) / (self.end.y - self.begin.y);
88            if shift < (self.end.x - self.begin.x) / _27 {
89                shift = (self.end.x - self.begin.x) / _27;
90            }
91            if shift > (self.end.x - self.begin.x) * _26 / _27 {
92                shift = (self.end.x - self.begin.x) * _26 / _27;
93            }
94            self.begin.x + shift
95        } else {
96            (self.begin.x + self.end.x) / _2
97        }
98    }
99}
100
101#[derive(Debug, PartialEq)]
103pub enum SearchError {
104    NoConvergency,
106    NoBracketing,
108    ZeroDerivative,
110}
111
112impl fmt::Display for SearchError {
113    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114        match self {
115            SearchError::NoConvergency => write!(f, "Convergency Error"),
116            SearchError::NoBracketing => write!(f, "Bracketing Error"),
117            SearchError::ZeroDerivative => write!(f, "Zero Derivative Error"),
118        }
119    }
120}
121impl Error for SearchError {
122    fn description(&self) -> &str {
123        match self {
124            SearchError::NoConvergency => "The algorithm could not converge within the given number of iterations",
125            SearchError::NoBracketing => "Initial values do not bracket zero",
126            SearchError::ZeroDerivative => "The algorithm cannot continue from the point where the derivative is zero",
127        }
128    }
129}
130
131pub trait Convergency<F: FloatType> {
134    fn is_root_found(&mut self, y: F) -> bool;
136    fn is_converged(&mut self, x1: F, x2: F) -> bool;
138    fn is_iteration_limit_reached(&mut self, iter: usize) -> bool;
140}
141
142impl<F: FloatType> Convergency<F> for F {
143    fn is_root_found(&mut self, y: F) -> bool {
145        y.abs() < self.abs()
146    }
147    fn is_converged(&mut self, x1: F, x2: F) -> bool {
149        (x1 - x2).abs() < self.abs()
150    }
151    fn is_iteration_limit_reached(&mut self, iter: usize) -> bool {
153        iter >= 30
154    }
155}
156
157pub mod brent;
158pub mod eigen;
159pub mod inverse_quadratic;
160pub mod newton_raphson;
161pub mod polynom;
162pub mod regula_falsi;
163pub mod secant;
164
165pub mod debug_convergency;
166pub mod simple_convergency;
167
168#[cfg(test)]
169mod test {
170    use super::*;
171
172    #[test]
173    fn sample_bracketed() {
174        let sample1 = Sample { x: 0f64, y: 0f64 };
175        let sample2 = Sample { x: 1f64, y: 1f64 };
176        let sample3 = Sample { x: 1f64, y: -1f64 };
177        let sample4 = Sample { x: -1f64, y: 0f64 };
178        let sample5 = Sample { x: -1f64, y: 1f64 };
179        assert_eq!(true, sample1.is_bracketed_with(&sample2));
180        assert_eq!(true, sample1.is_bracketed_with(&sample3));
181        assert_eq!(true, sample1.is_bracketed_with(&sample4));
182        assert_eq!(true, sample1.is_bracketed_with(&sample5));
183        assert_eq!(true, sample2.is_bracketed_with(&sample3));
184        assert_eq!(true, sample2.is_bracketed_with(&sample4));
185        assert_eq!(false, sample2.is_bracketed_with(&sample5));
186        assert_eq!(true, sample3.is_bracketed_with(&sample4));
187        assert_eq!(true, sample3.is_bracketed_with(&sample5));
188        assert_eq!(true, sample4.is_bracketed_with(&sample5));
189    }
190
191    #[test]
192    fn root_interval_bracketed() {
193        let sut1 = Interval {
194            begin: Sample { x: 0f64, y: 0f64 },
195            end: Sample { x: 0f64, y: 0f64 },
196        };
197        let sut2 = Interval {
198            begin: Sample { x: 0f32, y: 0f32 },
199            end: Sample { x: 1f32, y: 0f32 },
200        };
201        let sut3 = Interval {
202            begin: Sample { x: 0f64, y: 0f64 },
203            end: Sample { x: 0f64, y: 1f64 },
204        };
205        let sut4 = Interval {
206            begin: Sample { x: -1f64, y: 0f64 },
207            end: Sample { x: 0f64, y: 0f64 },
208        };
209        let sut5 = Interval {
210            begin: Sample { x: -1f64, y: 0f64 },
211            end: Sample { x: 0f64, y: 1f64 },
212        };
213        let sut6 = Interval {
214            begin: Sample { x: -1f32, y: -1f32 },
215            end: Sample { x: 0f32, y: 1f32 },
216        };
217        let sut7 = Interval {
218            begin: Sample { x: 0f64, y: 1f64 },
219            end: Sample { x: 1f64, y: -1f64 },
220        };
221        assert_eq!(true, sut1.is_bracketed());
222        assert_eq!(true, sut2.is_bracketed());
223        assert_eq!(true, sut3.is_bracketed());
224        assert_eq!(true, sut4.is_bracketed());
225        assert_eq!(true, sut5.is_bracketed());
226        assert_eq!(true, sut6.is_bracketed());
227        assert_eq!(true, sut7.is_bracketed());
228    }
229
230    #[test]
231    fn root_interval_not_bracketed() {
232        let sut1 = Interval {
233            begin: Sample { x: 0f64, y: 1f64 },
234            end: Sample { x: 1f64, y: 1f64 },
235        };
236        let sut2 = Interval {
237            begin: Sample { x: -1f64, y: -1f64 },
238            end: Sample { x: 1f64, y: -1f64 },
239        };
240        assert_eq!(false, sut1.is_bracketed());
241        assert_eq!(false, sut2.is_bracketed());
242    }
243
244    #[test]
245    fn root_interval_middle() {
246        let sut1 = Interval {
247            begin: Sample { x: 0f64, y: 1f64 },
248            end: Sample { x: 2f64, y: -3f64 },
249        };
250        let sut2 = Interval {
251            begin: Sample { x: -1f64, y: 0f64 },
252            end: Sample { x: 1f64, y: 0f64 },
253        };
254        assert_eq!(0.5f64, sut1.middle());
255        assert_eq!(0f64, sut2.middle());
256    }
257}