Skip to content

Commit 6a50e9d

Browse files
jturner314bluss
authored andcommitted
Add approx-0p5 feature for approx 0.5 support
`approx` 0.5 updates its `num-complex` dependency to 0.4, which is the same version of `num-complex` which `ndarray` depends on. So, it's very useful for `ndarray` to support `approx` 0.5.
1 parent a2b1f18 commit 6a50e9d

File tree

3 files changed

+197
-173
lines changed

3 files changed

+197
-173
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ num-complex = { version = "0.4", default-features = false }
3434
rayon_ = { version = "1.0.3", optional = true, package = "rayon" }
3535

3636
approx = { version = "0.4", optional = true , default-features = false }
37+
approx-0p5 = { package = "approx", version = "0.5", optional = true , default-features = false }
3738

3839
# Use via the `blas` crate feature!
3940
cblas-sys = { version = "0.1.4", optional = true, default-features = false }
@@ -64,7 +65,7 @@ serde-1 = ["serde"]
6465
test = []
6566

6667
# This feature is used for docs
67-
docs = ["approx", "serde", "rayon"]
68+
docs = ["approx", "approx-0p5", "serde", "rayon"]
6869

6970
std = ["num-traits/std", "matrixmultiply/std"]
7071
rayon = ["rayon_", "std"]

src/array_approx.rs

Lines changed: 191 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -1,181 +1,202 @@
1-
use crate::imp_prelude::*;
2-
use crate::Zip;
3-
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
4-
5-
/// **Requires crate feature `"approx"`**
6-
impl<A, B, S, S2, D> AbsDiffEq<ArrayBase<S2, D>> for ArrayBase<S, D>
7-
where
8-
A: AbsDiffEq<B>,
9-
A::Epsilon: Clone,
10-
S: Data<Elem = A>,
11-
S2: Data<Elem = B>,
12-
D: Dimension,
13-
{
14-
type Epsilon = A::Epsilon;
15-
16-
fn default_epsilon() -> A::Epsilon {
17-
A::default_epsilon()
18-
}
1+
#[cfg(feature = "approx")]
2+
mod approx_methods {
3+
use crate::imp_prelude::*;
194

20-
fn abs_diff_eq(&self, other: &ArrayBase<S2, D>, epsilon: A::Epsilon) -> bool {
21-
if self.shape() != other.shape() {
22-
return false;
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)
2321
}
2422

25-
Zip::from(self)
26-
.and(other)
27-
.all(move |a, b| A::abs_diff_eq(a, b, epsilon.clone()))
28-
}
29-
}
30-
31-
/// **Requires crate feature `"approx"`**
32-
impl<A, B, S, S2, D> RelativeEq<ArrayBase<S2, D>> for ArrayBase<S, D>
33-
where
34-
A: RelativeEq<B>,
35-
A::Epsilon: Clone,
36-
S: Data<Elem = A>,
37-
S2: Data<Elem = B>,
38-
D: Dimension,
39-
{
40-
fn default_max_relative() -> A::Epsilon {
41-
A::default_max_relative()
42-
}
43-
44-
fn relative_eq(
45-
&self,
46-
other: &ArrayBase<S2, D>,
47-
epsilon: A::Epsilon,
48-
max_relative: A::Epsilon,
49-
) -> bool {
50-
if self.shape() != other.shape() {
51-
return false;
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)
5239
}
53-
54-
Zip::from(self)
55-
.and(other)
56-
.all(move |a, b| A::relative_eq(a, b, epsilon.clone(), max_relative.clone()))
5740
}
5841
}
5942

60-
/// **Requires crate feature `"approx"`**
61-
impl<A, B, S, S2, D> UlpsEq<ArrayBase<S2, D>> for ArrayBase<S, D>
62-
where
63-
A: UlpsEq<B>,
64-
A::Epsilon: Clone,
65-
S: Data<Elem = A>,
66-
S2: Data<Elem = B>,
67-
D: Dimension,
68-
{
69-
fn default_max_ulps() -> u32 {
70-
A::default_max_ulps()
71-
}
72-
73-
fn ulps_eq(&self, other: &ArrayBase<S2, D>, epsilon: A::Epsilon, max_ulps: u32) -> bool {
74-
if self.shape() != other.shape() {
75-
return false;
43+
macro_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+
}
76194
}
77-
78-
Zip::from(self)
79-
.and(other)
80-
.all(move |a, b| A::ulps_eq(a, b, epsilon.clone(), max_ulps))
81-
}
82-
}
83-
84-
impl<A, S, D> ArrayBase<S, D>
85-
where
86-
S: Data<Elem = A>,
87-
D: Dimension,
88-
{
89-
/// A test for equality that uses the elementwise absolute difference to compute the
90-
/// approximate equality of two arrays.
91-
///
92-
/// **Requires crate feature `"approx"`**
93-
pub fn abs_diff_eq<S2>(&self, other: &ArrayBase<S2, D>, epsilon: A::Epsilon) -> bool
94-
where
95-
A: AbsDiffEq<S2::Elem>,
96-
A::Epsilon: Clone,
97-
S2: Data,
98-
{
99-
<Self as AbsDiffEq<_>>::abs_diff_eq(self, other, epsilon)
100-
}
101-
102-
/// A test for equality that uses an elementwise relative comparison if the values are far
103-
/// apart; and the absolute difference otherwise.
104-
///
105-
/// **Requires crate feature `"approx"`**
106-
pub fn relative_eq<S2>(
107-
&self,
108-
other: &ArrayBase<S2, D>,
109-
epsilon: A::Epsilon,
110-
max_relative: A::Epsilon,
111-
) -> bool
112-
where
113-
A: RelativeEq<S2::Elem>,
114-
A::Epsilon: Clone,
115-
S2: Data
116-
{
117-
<Self as RelativeEq<_>>::relative_eq(self, other, epsilon, max_relative)
118-
}
119-
}
120-
121-
122-
#[cfg(test)]
123-
mod tests {
124-
use crate::prelude::*;
125-
use alloc::vec;
126-
use approx::{
127-
assert_abs_diff_eq, assert_abs_diff_ne, assert_relative_eq, assert_relative_ne,
128-
assert_ulps_eq, assert_ulps_ne,
129195
};
196+
}
130197

131-
#[test]
132-
fn abs_diff_eq() {
133-
let a: Array2<f32> = array![[0., 2.], [-0.000010001, 100000000.]];
134-
let mut b: Array2<f32> = array![[0., 1.], [-0.000010002, 100000001.]];
135-
assert_abs_diff_ne!(a, b);
136-
b[(0, 1)] = 2.;
137-
assert_abs_diff_eq!(a, b);
138-
139-
// Check epsilon.
140-
assert_abs_diff_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
141-
assert_abs_diff_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
142-
143-
// Make sure we can compare different shapes without failure.
144-
let c = array![[1., 2.]];
145-
assert_abs_diff_ne!(a, c);
146-
}
198+
#[cfg(feature = "approx")]
199+
impl_approx_traits!(approx, "**Requires crate feature `\"approx\"`.**");
147200

148-
#[test]
149-
fn relative_eq() {
150-
let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
151-
let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
152-
assert_relative_ne!(a, b);
153-
b[(0, 1)] = 2.;
154-
assert_relative_eq!(a, b);
155-
156-
// Check epsilon.
157-
assert_relative_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
158-
assert_relative_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
159-
160-
// Make sure we can compare different shapes without failure.
161-
let c = array![[1., 2.]];
162-
assert_relative_ne!(a, c);
163-
}
164-
165-
#[test]
166-
fn ulps_eq() {
167-
let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
168-
let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
169-
assert_ulps_ne!(a, b);
170-
b[(0, 1)] = 2.;
171-
assert_ulps_eq!(a, b);
172-
173-
// Check epsilon.
174-
assert_ulps_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
175-
assert_ulps_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
176-
177-
// Make sure we can compare different shapes without failure.
178-
let c = array![[1., 2.]];
179-
assert_ulps_ne!(a, c);
180-
}
181-
}
201+
#[cfg(feature = "approx-0p5")]
202+
impl_approx_traits!(approx_0p5, "**Requires crate feature `\"approx-0p5\"`.**");

0 commit comments

Comments
 (0)