Skip to content

Commit d06b935

Browse files
committed
Feature-gate approx trait implementations
1 parent 984cf22 commit d06b935

File tree

5 files changed

+168
-148
lines changed

5 files changed

+168
-148
lines changed

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@ bench = false
2828
test = true
2929

3030
[dependencies]
31-
approx = "0.3"
3231
num-integer = "0.1.39"
3332
num-traits = "0.2"
3433
num-complex = "0.2"
3534
itertools = { version = "0.7.0", default-features = false }
3635

3736
rayon = { version = "1.0.3", optional = true }
3837

38+
approx = { version = "0.3", optional = true }
39+
3940
# Use via the `blas` crate feature!
4041
cblas-sys = { version = "0.1.4", optional = true, default-features = false }
4142
blas-src = { version = "0.2.0", optional = true, default-features = false }
@@ -62,7 +63,7 @@ test-blas-openblas-sys = ["blas"]
6263
test = ["test-blas-openblas-sys"]
6364

6465
# This feature is used for docs
65-
docs = ["serde-1", "rayon"]
66+
docs = ["approx", "serde-1", "rayon"]
6667

6768
[profile.release]
6869
[profile.bench]

src/array_approx.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
use crate::imp_prelude::*;
2+
use crate::{FoldWhile, Zip};
3+
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
4+
5+
/// **Requires crate feature `"approx"`**
6+
impl<A, S, D> AbsDiffEq for ArrayBase<S, D>
7+
where
8+
A: AbsDiffEq,
9+
A::Epsilon: Clone,
10+
S: Data<Elem = A>,
11+
D: Dimension,
12+
{
13+
type Epsilon = A::Epsilon;
14+
15+
fn default_epsilon() -> A::Epsilon {
16+
A::default_epsilon()
17+
}
18+
19+
fn abs_diff_eq(&self, other: &ArrayBase<S, D>, epsilon: A::Epsilon) -> bool {
20+
if self.shape() != other.shape() {
21+
return false;
22+
}
23+
Zip::from(self)
24+
.and(other)
25+
.fold_while(true, |_, a, b| {
26+
if A::abs_diff_ne(a, b, epsilon.clone()) {
27+
FoldWhile::Done(false)
28+
} else {
29+
FoldWhile::Continue(true)
30+
}
31+
})
32+
.into_inner()
33+
}
34+
}
35+
36+
/// **Requires crate feature `"approx"`**
37+
impl<A, S, D> RelativeEq for ArrayBase<S, D>
38+
where
39+
A: RelativeEq,
40+
A::Epsilon: Clone,
41+
S: Data<Elem = A>,
42+
D: Dimension,
43+
{
44+
fn default_max_relative() -> A::Epsilon {
45+
A::default_max_relative()
46+
}
47+
48+
fn relative_eq(
49+
&self,
50+
other: &ArrayBase<S, D>,
51+
epsilon: A::Epsilon,
52+
max_relative: A::Epsilon,
53+
) -> bool {
54+
if self.shape() != other.shape() {
55+
return false;
56+
}
57+
Zip::from(self)
58+
.and(other)
59+
.fold_while(true, |_, a, b| {
60+
if A::relative_ne(a, b, epsilon.clone(), max_relative.clone()) {
61+
FoldWhile::Done(false)
62+
} else {
63+
FoldWhile::Continue(true)
64+
}
65+
})
66+
.into_inner()
67+
}
68+
}
69+
70+
/// **Requires crate feature `"approx"`**
71+
impl<A, S, D> UlpsEq for ArrayBase<S, D>
72+
where
73+
A: UlpsEq,
74+
A::Epsilon: Clone,
75+
S: Data<Elem = A>,
76+
D: Dimension,
77+
{
78+
fn default_max_ulps() -> u32 {
79+
A::default_max_ulps()
80+
}
81+
82+
fn ulps_eq(&self, other: &ArrayBase<S, D>, epsilon: A::Epsilon, max_ulps: u32) -> bool {
83+
if self.shape() != other.shape() {
84+
return false;
85+
}
86+
Zip::from(self)
87+
.and(other)
88+
.fold_while(true, |_, a, b| {
89+
if A::ulps_ne(a, b, epsilon.clone(), max_ulps) {
90+
FoldWhile::Done(false)
91+
} else {
92+
FoldWhile::Continue(true)
93+
}
94+
})
95+
.into_inner()
96+
}
97+
}
98+
99+
#[cfg(test)]
100+
mod tests {
101+
use crate::prelude::*;
102+
use approx::{
103+
assert_abs_diff_eq, assert_abs_diff_ne, assert_relative_eq, assert_relative_ne,
104+
assert_ulps_eq, assert_ulps_ne,
105+
};
106+
107+
#[test]
108+
fn abs_diff_eq() {
109+
let a: Array2<f32> = array![[0., 2.], [-0.000010001, 100000000.]];
110+
let mut b: Array2<f32> = array![[0., 1.], [-0.000010002, 100000001.]];
111+
assert_abs_diff_ne!(a, b);
112+
b[(0, 1)] = 2.;
113+
assert_abs_diff_eq!(a, b);
114+
115+
// Check epsilon.
116+
assert_abs_diff_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
117+
assert_abs_diff_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
118+
119+
// Make sure we can compare different shapes without failure.
120+
let c = array![[1., 2.]];
121+
assert_abs_diff_ne!(a, c);
122+
}
123+
124+
#[test]
125+
fn relative_eq() {
126+
let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
127+
let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
128+
assert_relative_ne!(a, b);
129+
b[(0, 1)] = 2.;
130+
assert_relative_eq!(a, b);
131+
132+
// Check epsilon.
133+
assert_relative_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
134+
assert_relative_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
135+
136+
// Make sure we can compare different shapes without failure.
137+
let c = array![[1., 2.]];
138+
assert_relative_ne!(a, c);
139+
}
140+
141+
#[test]
142+
fn ulps_eq() {
143+
let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
144+
let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
145+
assert_ulps_ne!(a, b);
146+
b[(0, 1)] = 2.;
147+
assert_ulps_eq!(a, b);
148+
149+
// Check epsilon.
150+
assert_ulps_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
151+
assert_ulps_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
152+
153+
// Make sure we can compare different shapes without failure.
154+
let c = array![[1., 2.]];
155+
assert_ulps_ne!(a, c);
156+
}
157+
}

src/arraytraits.rs

Lines changed: 0 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -113,92 +113,6 @@ impl<S, D> Eq for ArrayBase<S, D>
113113
S::Elem: Eq,
114114
{ }
115115

116-
impl<A, S, D> approx::AbsDiffEq for ArrayBase<S, D>
117-
where
118-
A: approx::AbsDiffEq,
119-
A::Epsilon: Clone,
120-
S: Data<Elem = A>,
121-
D: Dimension,
122-
{
123-
type Epsilon = A::Epsilon;
124-
125-
fn default_epsilon() -> A::Epsilon {
126-
A::default_epsilon()
127-
}
128-
129-
fn abs_diff_eq(&self, other: &ArrayBase<S, D>, epsilon: A::Epsilon) -> bool {
130-
if self.shape() != other.shape() {
131-
return false;
132-
}
133-
Zip::from(self)
134-
.and(other)
135-
.fold_while(true, |_, a, b| {
136-
if A::abs_diff_ne(a, b, epsilon.clone()) {
137-
FoldWhile::Done(false)
138-
} else {
139-
FoldWhile::Continue(true)
140-
}
141-
})
142-
.into_inner()
143-
}
144-
}
145-
146-
impl<A, S, D> approx::RelativeEq for ArrayBase<S, D>
147-
where
148-
A: approx::RelativeEq,
149-
A::Epsilon: Clone,
150-
S: Data<Elem = A>,
151-
D: Dimension,
152-
{
153-
fn default_max_relative() -> A::Epsilon {
154-
A::default_max_relative()
155-
}
156-
157-
fn relative_eq(&self, other: &ArrayBase<S, D>, epsilon: A::Epsilon, max_relative: A::Epsilon) -> bool {
158-
if self.shape() != other.shape() {
159-
return false;
160-
}
161-
Zip::from(self)
162-
.and(other)
163-
.fold_while(true, |_, a, b| {
164-
if A::relative_ne(a, b, epsilon.clone(), max_relative.clone()) {
165-
FoldWhile::Done(false)
166-
} else {
167-
FoldWhile::Continue(true)
168-
}
169-
})
170-
.into_inner()
171-
}
172-
}
173-
174-
impl<A, S, D> approx::UlpsEq for ArrayBase<S, D>
175-
where
176-
A: approx::UlpsEq,
177-
A::Epsilon: Clone,
178-
S: Data<Elem = A>,
179-
D: Dimension,
180-
{
181-
fn default_max_ulps() -> u32 {
182-
A::default_max_ulps()
183-
}
184-
185-
fn ulps_eq(&self, other: &ArrayBase<S, D>, epsilon: A::Epsilon, max_ulps: u32) -> bool {
186-
if self.shape() != other.shape() {
187-
return false;
188-
}
189-
Zip::from(self)
190-
.and(other)
191-
.fold_while(true, |_, a, b| {
192-
if A::ulps_ne(a, b, epsilon.clone(), max_ulps) {
193-
FoldWhile::Done(false)
194-
} else {
195-
FoldWhile::Continue(true)
196-
}
197-
})
198-
.into_inner()
199-
}
200-
}
201-
202116
impl<A, S> FromIterator<A> for ArrayBase<S, Ix1>
203117
where S: DataOwned<Elem=A>
204118
{

src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@
6868
//! - `rayon`
6969
//! - Optional, compatible with Rust stable
7070
//! - Enables parallel iterators, parallelized methods and [`par_azip!`].
71+
//! - `approx`
72+
//! - Optional, compatible with Rust stable
73+
//! - Enables implementations of traits from the [`approx`] crate.
7174
//! - `blas`
7275
//! - Optional and experimental, compatible with Rust stable
7376
//! - Enable transparent BLAS support for matrix multiplication.
@@ -90,14 +93,16 @@ extern crate serde;
9093
#[cfg(feature="rayon")]
9194
extern crate rayon;
9295

96+
#[cfg(feature="approx")]
97+
extern crate approx;
98+
9399
#[cfg(feature="blas")]
94100
extern crate cblas_sys;
95101
#[cfg(feature="blas")]
96102
extern crate blas_src;
97103

98104
extern crate matrixmultiply;
99105

100-
extern crate approx;
101106
extern crate itertools;
102107
extern crate num_traits;
103108
extern crate num_complex;
@@ -147,6 +152,8 @@ mod aliases;
147152
mod arraytraits;
148153
#[cfg(feature = "serde-1")]
149154
mod array_serde;
155+
#[cfg(feature = "approx")]
156+
mod array_approx;
150157
mod arrayformat;
151158
mod data_traits;
152159

tests/array.rs

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#![allow(non_snake_case)]
22

3-
extern crate approx;
43
extern crate ndarray;
54
extern crate defmac;
65
extern crate itertools;
@@ -13,10 +12,6 @@ use ndarray::{
1312
multislice,
1413
};
1514
use ndarray::indices;
16-
use approx::{
17-
assert_abs_diff_eq, assert_abs_diff_ne, assert_relative_eq, assert_relative_ne, assert_ulps_eq,
18-
assert_ulps_ne,
19-
};
2015
use defmac::defmac;
2116
use itertools::{enumerate, zip};
2217

@@ -1168,60 +1163,6 @@ fn equality()
11681163
assert!(a != c);
11691164
}
11701165

1171-
#[test]
1172-
fn abs_diff_eq()
1173-
{
1174-
let a: Array2<f32> = array![[0., 2.], [-0.000010001, 100000000.]];
1175-
let mut b: Array2<f32> = array![[0., 1.], [-0.000010002, 100000001.]];
1176-
assert_abs_diff_ne!(a, b);
1177-
b[(0, 1)] = 2.;
1178-
assert_abs_diff_eq!(a, b);
1179-
1180-
// Check epsilon.
1181-
assert_abs_diff_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
1182-
assert_abs_diff_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
1183-
1184-
// Make sure we can compare different shapes without failure.
1185-
let c = array![[1., 2.]];
1186-
assert_abs_diff_ne!(a, c);
1187-
}
1188-
1189-
#[test]
1190-
fn relative_eq()
1191-
{
1192-
let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
1193-
let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
1194-
assert_relative_ne!(a, b);
1195-
b[(0, 1)] = 2.;
1196-
assert_relative_eq!(a, b);
1197-
1198-
// Check epsilon.
1199-
assert_relative_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
1200-
assert_relative_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
1201-
1202-
// Make sure we can compare different shapes without failure.
1203-
let c = array![[1., 2.]];
1204-
assert_relative_ne!(a, c);
1205-
}
1206-
1207-
#[test]
1208-
fn ulps_eq()
1209-
{
1210-
let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
1211-
let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
1212-
assert_ulps_ne!(a, b);
1213-
b[(0, 1)] = 2.;
1214-
assert_ulps_eq!(a, b);
1215-
1216-
// Check epsilon.
1217-
assert_ulps_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
1218-
assert_ulps_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);
1219-
1220-
// Make sure we can compare different shapes without failure.
1221-
let c = array![[1., 2.]];
1222-
assert_ulps_ne!(a, c);
1223-
}
1224-
12251166
#[test]
12261167
fn map1()
12271168
{

0 commit comments

Comments
 (0)