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}