ndarray/
array_approx.rs

1#[cfg(feature = "approx")]
2mod approx_methods {
3    use crate::imp_prelude::*;
4
5    impl<A, S, D> ArrayBase<S, D>
6    where
7        S: Data<Elem = A>,
8        D: Dimension,
9    {
10        /// A test for equality that uses the elementwise absolute difference to compute the
11        /// approximate equality of two arrays.
12        ///
13        /// **Requires crate feature `"approx"`**
14        pub fn abs_diff_eq<S2>(&self, other: &ArrayBase<S2, D>, epsilon: A::Epsilon) -> bool
15        where
16            A: ::approx::AbsDiffEq<S2::Elem>,
17            A::Epsilon: Clone,
18            S2: Data,
19        {
20            <Self as ::approx::AbsDiffEq<_>>::abs_diff_eq(self, other, epsilon)
21        }
22
23        /// A test for equality that uses an elementwise relative comparison if the values are far
24        /// apart; and the absolute difference otherwise.
25        ///
26        /// **Requires crate feature `"approx"`**
27        pub fn relative_eq<S2>(
28            &self,
29            other: &ArrayBase<S2, D>,
30            epsilon: A::Epsilon,
31            max_relative: A::Epsilon,
32        ) -> bool
33        where
34            A: ::approx::RelativeEq<S2::Elem>,
35            A::Epsilon: Clone,
36            S2: Data,
37        {
38            <Self as ::approx::RelativeEq<_>>::relative_eq(self, other, epsilon, max_relative)
39        }
40    }
41}
42
43macro_rules! impl_approx_traits {
44    ($approx:ident, $doc:expr) => {
45        mod $approx {
46            use crate::imp_prelude::*;
47            use crate::Zip;
48            use $approx::{AbsDiffEq, RelativeEq, UlpsEq};
49
50            #[doc = $doc]
51            impl<A, B, S, S2, D> AbsDiffEq<ArrayBase<S2, D>> for ArrayBase<S, D>
52            where
53                A: AbsDiffEq<B>,
54                A::Epsilon: Clone,
55                S: Data<Elem = A>,
56                S2: Data<Elem = B>,
57                D: Dimension,
58            {
59                type Epsilon = A::Epsilon;
60
61                fn default_epsilon() -> A::Epsilon {
62                    A::default_epsilon()
63                }
64
65                fn abs_diff_eq(&self, other: &ArrayBase<S2, D>, epsilon: A::Epsilon) -> bool {
66                    if self.shape() != other.shape() {
67                        return false;
68                    }
69
70                    Zip::from(self)
71                        .and(other)
72                        .all(move |a, b| A::abs_diff_eq(a, b, epsilon.clone()))
73                }
74            }
75
76            #[doc = $doc]
77            impl<A, B, S, S2, D> RelativeEq<ArrayBase<S2, D>> for ArrayBase<S, D>
78            where
79                A: RelativeEq<B>,
80                A::Epsilon: Clone,
81                S: Data<Elem = A>,
82                S2: Data<Elem = B>,
83                D: Dimension,
84            {
85                fn default_max_relative() -> A::Epsilon {
86                    A::default_max_relative()
87                }
88
89                fn relative_eq(
90                    &self,
91                    other: &ArrayBase<S2, D>,
92                    epsilon: A::Epsilon,
93                    max_relative: A::Epsilon,
94                ) -> bool {
95                    if self.shape() != other.shape() {
96                        return false;
97                    }
98
99                    Zip::from(self).and(other).all(move |a, b| {
100                        A::relative_eq(a, b, epsilon.clone(), max_relative.clone())
101                    })
102                }
103            }
104
105            #[doc = $doc]
106            impl<A, B, S, S2, D> UlpsEq<ArrayBase<S2, D>> for ArrayBase<S, D>
107            where
108                A: UlpsEq<B>,
109                A::Epsilon: Clone,
110                S: Data<Elem = A>,
111                S2: Data<Elem = B>,
112                D: Dimension,
113            {
114                fn default_max_ulps() -> u32 {
115                    A::default_max_ulps()
116                }
117
118                fn ulps_eq(
119                    &self,
120                    other: &ArrayBase<S2, D>,
121                    epsilon: A::Epsilon,
122                    max_ulps: u32,
123                ) -> bool {
124                    if self.shape() != other.shape() {
125                        return false;
126                    }
127
128                    Zip::from(self)
129                        .and(other)
130                        .all(move |a, b| A::ulps_eq(a, b, epsilon.clone(), max_ulps))
131                }
132            }
133
134            #[cfg(test)]
135            mod tests {
136                use crate::prelude::*;
137                use alloc::vec;
138                use $approx::{
139                    assert_abs_diff_eq, assert_abs_diff_ne, assert_relative_eq, assert_relative_ne,
140                    assert_ulps_eq, assert_ulps_ne,
141                };
142
143                #[test]
144                fn abs_diff_eq() {
145                    let a: Array2<f32> = array![[0., 2.], [-0.000010001, 100000000.]];
146                    let mut b: Array2<f32> = array![[0., 1.], [-0.000010002, 100000001.]];
147                    assert_abs_diff_ne!(a, b);
148                    b[(0, 1)] = 2.;
149                    assert_abs_diff_eq!(a, b);
150
151                    // Check epsilon.
152                    assert_abs_diff_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
153                    assert_abs_diff_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
154
155                    // Make sure we can compare different shapes without failure.
156                    let c = array![[1., 2.]];
157                    assert_abs_diff_ne!(a, c);
158                }
159
160                #[test]
161                fn relative_eq() {
162                    let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
163                    let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
164                    assert_relative_ne!(a, b);
165                    b[(0, 1)] = 2.;
166                    assert_relative_eq!(a, b);
167
168                    // Check epsilon.
169                    assert_relative_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
170                    assert_relative_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
171
172                    // Make sure we can compare different shapes without failure.
173                    let c = array![[1., 2.]];
174                    assert_relative_ne!(a, c);
175                }
176
177                #[test]
178                fn ulps_eq() {
179                    let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
180                    let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
181                    assert_ulps_ne!(a, b);
182                    b[(0, 1)] = 2.;
183                    assert_ulps_eq!(a, b);
184
185                    // Check epsilon.
186                    assert_ulps_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
187                    assert_ulps_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
188
189                    // Make sure we can compare different shapes without failure.
190                    let c = array![[1., 2.]];
191                    assert_ulps_ne!(a, c);
192                }
193            }
194        }
195    };
196}
197
198#[cfg(feature = "approx")]
199impl_approx_traits!(approx, "**Requires crate feature `\"approx\"`.**");
200
201#[cfg(feature = "approx-0_5")]
202impl_approx_traits!(approx_0_5, "**Requires crate feature `\"approx-0_5\"`.**");