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