Skip to content

Commit

Permalink
Feature-gate approx trait implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
jturner314 committed Jan 14, 2019
1 parent 984cf22 commit d06b935
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 148 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Expand Up @@ -28,14 +28,15 @@ bench = false
test = true

[dependencies]
approx = "0.3"
num-integer = "0.1.39"
num-traits = "0.2"
num-complex = "0.2"
itertools = { version = "0.7.0", default-features = false }

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

approx = { version = "0.3", optional = true }

# Use via the `blas` crate feature!
cblas-sys = { version = "0.1.4", optional = true, default-features = false }
blas-src = { version = "0.2.0", optional = true, default-features = false }
Expand All @@ -62,7 +63,7 @@ test-blas-openblas-sys = ["blas"]
test = ["test-blas-openblas-sys"]

# This feature is used for docs
docs = ["serde-1", "rayon"]
docs = ["approx", "serde-1", "rayon"]

[profile.release]
[profile.bench]
Expand Down
157 changes: 157 additions & 0 deletions src/array_approx.rs
@@ -0,0 +1,157 @@
use crate::imp_prelude::*;
use crate::{FoldWhile, Zip};
use approx::{AbsDiffEq, RelativeEq, UlpsEq};

/// **Requires crate feature `"approx"`**
impl<A, S, D> AbsDiffEq for ArrayBase<S, D>
where
A: AbsDiffEq,
A::Epsilon: Clone,
S: Data<Elem = A>,
D: Dimension,
{
type Epsilon = A::Epsilon;

fn default_epsilon() -> A::Epsilon {
A::default_epsilon()
}

fn abs_diff_eq(&self, other: &ArrayBase<S, D>, epsilon: A::Epsilon) -> bool {
if self.shape() != other.shape() {
return false;
}
Zip::from(self)
.and(other)
.fold_while(true, |_, a, b| {
if A::abs_diff_ne(a, b, epsilon.clone()) {
FoldWhile::Done(false)
} else {
FoldWhile::Continue(true)
}
})
.into_inner()
}
}

/// **Requires crate feature `"approx"`**
impl<A, S, D> RelativeEq for ArrayBase<S, D>
where
A: RelativeEq,
A::Epsilon: Clone,
S: Data<Elem = A>,
D: Dimension,
{
fn default_max_relative() -> A::Epsilon {
A::default_max_relative()
}

fn relative_eq(
&self,
other: &ArrayBase<S, D>,
epsilon: A::Epsilon,
max_relative: A::Epsilon,
) -> bool {
if self.shape() != other.shape() {
return false;
}
Zip::from(self)
.and(other)
.fold_while(true, |_, a, b| {
if A::relative_ne(a, b, epsilon.clone(), max_relative.clone()) {
FoldWhile::Done(false)
} else {
FoldWhile::Continue(true)
}
})
.into_inner()
}
}

/// **Requires crate feature `"approx"`**
impl<A, S, D> UlpsEq for ArrayBase<S, D>
where
A: UlpsEq,
A::Epsilon: Clone,
S: Data<Elem = A>,
D: Dimension,
{
fn default_max_ulps() -> u32 {
A::default_max_ulps()
}

fn ulps_eq(&self, other: &ArrayBase<S, D>, epsilon: A::Epsilon, max_ulps: u32) -> bool {
if self.shape() != other.shape() {
return false;
}
Zip::from(self)
.and(other)
.fold_while(true, |_, a, b| {
if A::ulps_ne(a, b, epsilon.clone(), max_ulps) {
FoldWhile::Done(false)
} else {
FoldWhile::Continue(true)
}
})
.into_inner()
}
}

#[cfg(test)]
mod tests {
use crate::prelude::*;
use approx::{
assert_abs_diff_eq, assert_abs_diff_ne, assert_relative_eq, assert_relative_ne,
assert_ulps_eq, assert_ulps_ne,
};

#[test]
fn abs_diff_eq() {
let a: Array2<f32> = array![[0., 2.], [-0.000010001, 100000000.]];
let mut b: Array2<f32> = array![[0., 1.], [-0.000010002, 100000001.]];
assert_abs_diff_ne!(a, b);
b[(0, 1)] = 2.;
assert_abs_diff_eq!(a, b);

// Check epsilon.
assert_abs_diff_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
assert_abs_diff_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);

// Make sure we can compare different shapes without failure.
let c = array![[1., 2.]];
assert_abs_diff_ne!(a, c);
}

#[test]
fn relative_eq() {
let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
assert_relative_ne!(a, b);
b[(0, 1)] = 2.;
assert_relative_eq!(a, b);

// Check epsilon.
assert_relative_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
assert_relative_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);

// Make sure we can compare different shapes without failure.
let c = array![[1., 2.]];
assert_relative_ne!(a, c);
}

#[test]
fn ulps_eq() {
let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
assert_ulps_ne!(a, b);
b[(0, 1)] = 2.;
assert_ulps_eq!(a, b);

// Check epsilon.
assert_ulps_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
assert_ulps_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);

// Make sure we can compare different shapes without failure.
let c = array![[1., 2.]];
assert_ulps_ne!(a, c);
}
}
86 changes: 0 additions & 86 deletions src/arraytraits.rs
Expand Up @@ -113,92 +113,6 @@ impl<S, D> Eq for ArrayBase<S, D>
S::Elem: Eq,
{ }

impl<A, S, D> approx::AbsDiffEq for ArrayBase<S, D>
where
A: approx::AbsDiffEq,
A::Epsilon: Clone,
S: Data<Elem = A>,
D: Dimension,
{
type Epsilon = A::Epsilon;

fn default_epsilon() -> A::Epsilon {
A::default_epsilon()
}

fn abs_diff_eq(&self, other: &ArrayBase<S, D>, epsilon: A::Epsilon) -> bool {
if self.shape() != other.shape() {
return false;
}
Zip::from(self)
.and(other)
.fold_while(true, |_, a, b| {
if A::abs_diff_ne(a, b, epsilon.clone()) {
FoldWhile::Done(false)
} else {
FoldWhile::Continue(true)
}
})
.into_inner()
}
}

impl<A, S, D> approx::RelativeEq for ArrayBase<S, D>
where
A: approx::RelativeEq,
A::Epsilon: Clone,
S: Data<Elem = A>,
D: Dimension,
{
fn default_max_relative() -> A::Epsilon {
A::default_max_relative()
}

fn relative_eq(&self, other: &ArrayBase<S, D>, epsilon: A::Epsilon, max_relative: A::Epsilon) -> bool {
if self.shape() != other.shape() {
return false;
}
Zip::from(self)
.and(other)
.fold_while(true, |_, a, b| {
if A::relative_ne(a, b, epsilon.clone(), max_relative.clone()) {
FoldWhile::Done(false)
} else {
FoldWhile::Continue(true)
}
})
.into_inner()
}
}

impl<A, S, D> approx::UlpsEq for ArrayBase<S, D>
where
A: approx::UlpsEq,
A::Epsilon: Clone,
S: Data<Elem = A>,
D: Dimension,
{
fn default_max_ulps() -> u32 {
A::default_max_ulps()
}

fn ulps_eq(&self, other: &ArrayBase<S, D>, epsilon: A::Epsilon, max_ulps: u32) -> bool {
if self.shape() != other.shape() {
return false;
}
Zip::from(self)
.and(other)
.fold_while(true, |_, a, b| {
if A::ulps_ne(a, b, epsilon.clone(), max_ulps) {
FoldWhile::Done(false)
} else {
FoldWhile::Continue(true)
}
})
.into_inner()
}
}

impl<A, S> FromIterator<A> for ArrayBase<S, Ix1>
where S: DataOwned<Elem=A>
{
Expand Down
9 changes: 8 additions & 1 deletion src/lib.rs
Expand Up @@ -68,6 +68,9 @@
//! - `rayon`
//! - Optional, compatible with Rust stable
//! - Enables parallel iterators, parallelized methods and [`par_azip!`].
//! - `approx`
//! - Optional, compatible with Rust stable
//! - Enables implementations of traits from the [`approx`] crate.
//! - `blas`
//! - Optional and experimental, compatible with Rust stable
//! - Enable transparent BLAS support for matrix multiplication.
Expand All @@ -90,14 +93,16 @@ extern crate serde;
#[cfg(feature="rayon")]
extern crate rayon;

#[cfg(feature="approx")]
extern crate approx;

#[cfg(feature="blas")]
extern crate cblas_sys;
#[cfg(feature="blas")]
extern crate blas_src;

extern crate matrixmultiply;

extern crate approx;
extern crate itertools;
extern crate num_traits;
extern crate num_complex;
Expand Down Expand Up @@ -147,6 +152,8 @@ mod aliases;
mod arraytraits;
#[cfg(feature = "serde-1")]
mod array_serde;
#[cfg(feature = "approx")]
mod array_approx;
mod arrayformat;
mod data_traits;

Expand Down
59 changes: 0 additions & 59 deletions tests/array.rs
@@ -1,6 +1,5 @@
#![allow(non_snake_case)]

extern crate approx;
extern crate ndarray;
extern crate defmac;
extern crate itertools;
Expand All @@ -13,10 +12,6 @@ use ndarray::{
multislice,
};
use ndarray::indices;
use approx::{
assert_abs_diff_eq, assert_abs_diff_ne, assert_relative_eq, assert_relative_ne, assert_ulps_eq,
assert_ulps_ne,
};
use defmac::defmac;
use itertools::{enumerate, zip};

Expand Down Expand Up @@ -1168,60 +1163,6 @@ fn equality()
assert!(a != c);
}

#[test]
fn abs_diff_eq()
{
let a: Array2<f32> = array![[0., 2.], [-0.000010001, 100000000.]];
let mut b: Array2<f32> = array![[0., 1.], [-0.000010002, 100000001.]];
assert_abs_diff_ne!(a, b);
b[(0, 1)] = 2.;
assert_abs_diff_eq!(a, b);

// Check epsilon.
assert_abs_diff_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
assert_abs_diff_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);

// Make sure we can compare different shapes without failure.
let c = array![[1., 2.]];
assert_abs_diff_ne!(a, c);
}

#[test]
fn relative_eq()
{
let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
assert_relative_ne!(a, b);
b[(0, 1)] = 2.;
assert_relative_eq!(a, b);

// Check epsilon.
assert_relative_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
assert_relative_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);

// Make sure we can compare different shapes without failure.
let c = array![[1., 2.]];
assert_relative_ne!(a, c);
}

#[test]
fn ulps_eq()
{
let a: Array2<f32> = array![[1., 2.], [-0.000010001, 100000000.]];
let mut b: Array2<f32> = array![[1., 1.], [-0.000010002, 100000001.]];
assert_ulps_ne!(a, b);
b[(0, 1)] = 2.;
assert_ulps_eq!(a, b);

// Check epsilon.
assert_ulps_eq!(array![0.0f32], array![1e-40f32], epsilon = 1e-40f32);
assert_ulps_ne!(array![0.0f32], array![1e-40f32], epsilon = 1e-41f32);

// Make sure we can compare different shapes without failure.
let c = array![[1., 2.]];
assert_ulps_ne!(a, c);
}

#[test]
fn map1()
{
Expand Down

0 comments on commit d06b935

Please sign in to comment.