1#[cfg(test)]
2use std::f64::{MIN_POSITIVE, MAX};
3
4
5pub fn is_saddle_point(gradient: &[f64], tolerance: f64) -> bool {
8 gradient.iter().all(|dx| dx.abs() <= tolerance)
9}
10
11
12#[cfg(test)]
15#[allow(clippy::float_cmp)]
16pub fn are_close(a: f64, b: f64, eps: f64) -> bool {
17 assert!(eps.is_finite());
18
19 let d = (a - b).abs();
20
21 a == b
23
24 || ((a == 0.0 || b == 0.0 || d < MIN_POSITIVE) &&
27 d < eps * MIN_POSITIVE)
28
29 || d / (a + b).min(MAX) < eps
31}
32
33
34#[cfg(test)]
35mod tests {
36 use std::f64::{INFINITY, NAN};
37
38 use super::{is_saddle_point, are_close};
39
40 #[test]
41 fn test_is_saddle_point() {
42 assert!(is_saddle_point(&[1.0, 2.0], 2.0));
43 assert!(is_saddle_point(&[1.0, -2.0], 2.0));
44 assert!(!is_saddle_point(&[1.0, 2.1], 2.0));
45 assert!(!is_saddle_point(&[1.0, -2.1], 2.0));
46 }
47
48 #[test]
49 fn test_are_close() {
50 assert!(are_close(1.0, 1.0, 0.00001));
51 assert!(are_close(INFINITY, INFINITY, 0.00001));
52 assert!(are_close(1.0e-1000, 0.0, 0.1));
53 assert!(!are_close(1.0e-40, 0.0, 0.000_001));
54 assert!(!are_close(2.0, 1.0, 0.00001));
55 assert!(!are_close(NAN, NAN, 0.00001));
56 }
57}