1#[cfg(feature = "approx")]
2mod approx_methods
3{
4 use crate::imp_prelude::*;
5
6 impl<A, D: Dimension> ArrayRef<A, D>
7 {
8 pub fn abs_diff_eq<B>(&self, other: &ArrayRef<B, D>, epsilon: A::Epsilon) -> bool
11 where
12 A: ::approx::AbsDiffEq<B>,
13 A::Epsilon: Clone,
14 {
15 <Self as ::approx::AbsDiffEq<_>>::abs_diff_eq(self, other, epsilon)
16 }
17
18 pub fn relative_eq<B>(&self, other: &ArrayRef<B, D>, epsilon: A::Epsilon, max_relative: A::Epsilon) -> bool
21 where
22 A: ::approx::RelativeEq<B>,
23 A::Epsilon: Clone,
24 {
25 <Self as ::approx::RelativeEq<_>>::relative_eq(self, other, epsilon, max_relative)
26 }
27 }
28}
29
30macro_rules! impl_approx_traits {
31 ($approx:ident, $doc:expr) => {
32 mod $approx {
33 use crate::imp_prelude::*;
34 use crate::Zip;
35 use $approx::{AbsDiffEq, RelativeEq, UlpsEq};
36
37 #[doc = $doc]
38 impl<A, B, D> AbsDiffEq<ArrayRef<B, D>> for ArrayRef<A, D>
39 where
40 A: AbsDiffEq<B>,
41 A::Epsilon: Clone,
42 D: Dimension,
43 {
44 type Epsilon = A::Epsilon;
45
46 fn default_epsilon() -> A::Epsilon {
47 A::default_epsilon()
48 }
49
50 fn abs_diff_eq(&self, other: &ArrayRef<B, D>, epsilon: A::Epsilon) -> bool {
51 if self.shape() != other.shape() {
52 return false;
53 }
54
55 Zip::from(self)
56 .and(other)
57 .all(move |a, b| A::abs_diff_eq(a, b, epsilon.clone()))
58 }
59 }
60
61 #[doc = $doc]
62 impl<A, B, S, S2, D> AbsDiffEq<ArrayBase<S2, D>> for ArrayBase<S, D>
63 where
64 A: AbsDiffEq<B>,
65 A::Epsilon: Clone,
66 S: Data<Elem = A>,
67 S2: Data<Elem = B>,
68 D: Dimension,
69 {
70 type Epsilon = A::Epsilon;
71
72 fn default_epsilon() -> A::Epsilon {
73 A::default_epsilon()
74 }
75
76 fn abs_diff_eq(&self, other: &ArrayBase<S2, D>, epsilon: A::Epsilon) -> bool {
77 (**self).abs_diff_eq(other, epsilon)
78 }
79 }
80
81 #[doc = $doc]
82 impl<A, B, D> RelativeEq<ArrayRef<B, D>> for ArrayRef<A, D>
83 where
84 A: RelativeEq<B>,
85 A::Epsilon: Clone,
86 D: Dimension,
87 {
88 fn default_max_relative() -> A::Epsilon {
89 A::default_max_relative()
90 }
91
92 fn relative_eq(
93 &self,
94 other: &ArrayRef<B, D>,
95 epsilon: A::Epsilon,
96 max_relative: A::Epsilon,
97 ) -> bool {
98 if self.shape() != other.shape() {
99 return false;
100 }
101
102 Zip::from(self).and(other).all(move |a, b| {
103 A::relative_eq(a, b, epsilon.clone(), max_relative.clone())
104 })
105 }
106 }
107
108 #[doc = $doc]
109 impl<A, B, S, S2, D> RelativeEq<ArrayBase<S2, D>> for ArrayBase<S, D>
110 where
111 A: RelativeEq<B>,
112 A::Epsilon: Clone,
113 S: Data<Elem = A>,
114 S2: Data<Elem = B>,
115 D: Dimension,
116 {
117 fn default_max_relative() -> A::Epsilon {
118 A::default_max_relative()
119 }
120
121 fn relative_eq(
122 &self,
123 other: &ArrayBase<S2, D>,
124 epsilon: A::Epsilon,
125 max_relative: A::Epsilon,
126 ) -> bool {
127 (**self).relative_eq(other, epsilon, max_relative)
128 }
129 }
130
131 #[doc = $doc]
132 impl<A, B, D> UlpsEq<ArrayRef<B, D>> for ArrayRef<A, D>
133 where
134 A: UlpsEq<B>,
135 A::Epsilon: Clone,
136 D: Dimension,
137 {
138 fn default_max_ulps() -> u32 {
139 A::default_max_ulps()
140 }
141
142 fn ulps_eq(
143 &self,
144 other: &ArrayRef<B, D>,
145 epsilon: A::Epsilon,
146 max_ulps: u32,
147 ) -> bool {
148 if self.shape() != other.shape() {
149 return false;
150 }
151
152 Zip::from(self)
153 .and(other)
154 .all(move |a, b| A::ulps_eq(a, b, epsilon.clone(), max_ulps))
155 }
156 }
157
158 #[doc = $doc]
159 impl<A, B, S, S2, D> UlpsEq<ArrayBase<S2, D>> for ArrayBase<S, D>
160 where
161 A: UlpsEq<B>,
162 A::Epsilon: Clone,
163 S: Data<Elem = A>,
164 S2: Data<Elem = B>,
165 D: Dimension,
166 {
167 fn default_max_ulps() -> u32 {
168 A::default_max_ulps()
169 }
170
171 fn ulps_eq(
172 &self,
173 other: &ArrayBase<S2, D>,
174 epsilon: A::Epsilon,
175 max_ulps: u32,
176 ) -> bool {
177 (**self).ulps_eq(other, epsilon, max_ulps)
178 }
179 }
180
181 #[cfg(test)]
182 mod tests {
183 use crate::prelude::*;
184 use alloc::vec;
185 use $approx::{
186 assert_abs_diff_eq, assert_abs_diff_ne, assert_relative_eq, assert_relative_ne,
187 assert_ulps_eq, assert_ulps_ne,
188 };
189
190 #[test]
191 fn abs_diff_eq() {
192 let a: Array2<f32> = array![[0., 2.], [-0.000010001, 100000000.]];
193 let mut b: Array2<f32> = array![[0., 1.], [-0.000010002, 100000001.]];
194 assert_abs_diff_ne!(a, b);
195 b[(0, 1)] = 2.;
196 assert_abs_diff_eq!(a, b);
197
198 assert_abs_diff_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
200 assert_abs_diff_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
201
202 let c = array![[1., 2.]];
204 assert_abs_diff_ne!(a, c);
205 }
206
207 #[test]
208 fn relative_eq() {
209 let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
210 let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
211 assert_relative_ne!(a, b);
212 b[(0, 1)] = 2.;
213 assert_relative_eq!(a, b);
214
215 assert_relative_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
217 assert_relative_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
218
219 let c = array![[1., 2.]];
221 assert_relative_ne!(a, c);
222 }
223
224 #[test]
225 fn ulps_eq() {
226 let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
227 let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
228 assert_ulps_ne!(a, b);
229 b[(0, 1)] = 2.;
230 assert_ulps_eq!(a, b);
231
232 assert_ulps_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
234 assert_ulps_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
235
236 let c = array![[1., 2.]];
238 assert_ulps_ne!(a, c);
239 }
240 }
241 }
242 };
243}
244
245#[cfg(feature = "approx")]
246impl_approx_traits!(approx, "**Requires crate feature `\"approx\"`.**");