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 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 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 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 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 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 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 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 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\"`.**");