diff --git a/benches/numeric.rs b/benches/numeric.rs index db0252c8a..493e79958 100644 --- a/benches/numeric.rs +++ b/benches/numeric.rs @@ -6,6 +6,7 @@ use test::Bencher; extern crate ndarray; use ndarray::prelude::*; +use ndarray::{Zip, FoldWhile}; const N: usize = 1024; const X: usize = 64; @@ -25,3 +26,52 @@ fn clip(bench: &mut Bencher) }) }); } + +#[bench] +fn max_early_return(bench: &mut Bencher) +{ + fn max(arr: &Array2) -> Option<&f64> + { + if let Some(mut max) = arr.first() { + if let Some(slc) = arr.as_slice_memory_order() { + for item in slc.iter().skip(1) { + match max.partial_cmp(item) { + None => return None, + Some(::std::cmp::Ordering::Less) => max = item, + _ => {}, + } + } + Some(max) + } else { + Zip::from(arr).fold_while(Some(max), |acc, x| + match acc.partial_cmp(&Some(x)) { + None => FoldWhile::Done(None), + Some(::std::cmp::Ordering::Less) => FoldWhile::Continue(Some(x)), + _ => FoldWhile::Continue(acc), + }).into_inner() + } + } else { + None + } + } + let mut a = Array::linspace(0., 127., N * 2).into_shape([X, Y * 2]).unwrap(); + bench.iter(|| max(&a)); +} + +#[bench] +fn max_short(bench: &mut Bencher) { + fn max(arr: &Array2) -> Option<&f64> { + if let Some(first) = arr.first() { + let max = arr.fold(first, |acc, x| if x>acc {x} else {acc}); + if max == max { + Some(max) + } else { + None + } + } else { + None + } + } + let mut a = Array::linspace(0., 127., N * 2).into_shape([X, Y * 2]).unwrap(); + bench.iter(|| max(&a)); +} \ No newline at end of file diff --git a/src/numeric/impl_numeric.rs b/src/numeric/impl_numeric.rs index 9e229b46a..43ee6010c 100644 --- a/src/numeric/impl_numeric.rs +++ b/src/numeric/impl_numeric.rs @@ -72,6 +72,149 @@ impl ArrayBase sum } + /// Return a reference to a maximum of all values. + /// Return None if a comparison fails or if self is empty. + /// + /// # Example + /// ``` + /// use ndarray::{arr2, Array2}; + /// use std::f64; + /// + /// let a = arr2(&[[1., 2.], [3., 4.]]); + /// assert_eq!(a.max(), Some(&4.)); + /// + /// let b = arr2(&[[1., f64::NAN], [3., 4.]]); + /// assert_eq!(b.max(), None); + /// + /// let c = arr2(&[[f64::NAN]]); + /// assert_eq!(c.max(), None); + /// + /// let d: Array2 = arr2(&[[]]); + /// assert_eq!(d.max(), None); + /// ``` + pub fn max(&self) -> Option<&A> + where A: PartialOrd + { + if let Some(first) = self.first() { + let max = self.fold(first, |acc, x| if acc == acc && !(x < acc) {x} else {acc}); + if max == max { + Some(max) + } else { + None + } + } else { + None + } + + } + + /// Return a reference to a maximum of all values, ignoring + /// incomparable elements. Returns None if `self` is empty, + /// or contains only incomparable elements. + /// + /// # Example + /// ``` + /// use ndarray::{arr2, Array2}; + /// use std::f64; + /// + /// let a = arr2(&[[1., 2.], [3., 4.]]); + /// assert_eq!(a.nanmax(), Some(&4.)); + /// + /// let b = arr2(&[[1., f64::NAN], [3., f64::NAN]]); + /// assert_eq!(b.nanmax(), Some(&3.)); + /// + /// let c: Array2 = arr2(&[[]]); + /// assert_eq!(c.nanmax(), None); + /// + /// let d = arr2(&[[f64::NAN, f64::NAN],[f64::NAN, f64::NAN]]); + /// assert_eq!(d.nanmax(), None); + /// ``` + pub fn nanmax(&self) -> Option<&A> + where A: PartialOrd, + { + if let Some(first) = self.first() { + let max = self.fold(first, |acc, x| if acc == acc && !(x > acc) {acc} else {x}); + if max == max { + Some(max) + } else { + None + } + } else { + None + } + } + + /// Return a reference to a minimum of all values. + /// Return None if a comparison fails or if self is empty. + /// + /// # Example + /// ``` + /// use ndarray::{arr2, Array2}; + /// use std::f64; + /// + /// let a = arr2(&[[1., 2.], [3., 4.]]); + /// assert_eq!(a.min(), Some(&1.)); + /// + /// let b = arr2(&[[1., f64::NAN], [3., 4.]]); + /// assert_eq!(b.min(), None); + /// + /// let c = arr2(&[[f64::NAN]]); + /// assert_eq!(c.min(), None); + /// + /// let d: Array2 = arr2(&[[]]); + /// assert_eq!(d.min(), None); + /// ``` + pub fn min(&self) -> Option<&A> + where A: PartialOrd + { + if let Some(first) = self.first() { + let min = self.fold(first, |acc, x| if acc == acc && !(acc < x) {x} else {acc}); + if min == min { + Some(min) + } else { + None + } + } else { + None + } + } + + /// Return a reference to a minimum of all values, ignoring + /// incomparable elements. Returns None if `self` is empty, + /// or contains only incomparable elements. + /// + /// # Example + /// ``` + /// use ndarray::{arr2, Array2}; + /// use std::f64; + /// + /// let a = arr2(&[[1., 2.], [3., 4.]]); + /// assert_eq!(a.nanmin(), Some(&1.)); + /// + /// let b = arr2(&[[f64::NAN, 2.], [3., f64::NAN]]); + /// assert_eq!(b.nanmin(), Some(&2.)); + /// + /// let c: Array2 = arr2(&[[]]); + /// assert_eq!(c.nanmin(), None); + /// + /// let d = arr2(&[[f64::NAN, f64::NAN],[f64::NAN, f64::NAN]]); + /// assert_eq!(d.nanmin(), None); + /// ``` + pub fn nanmin(&self) -> Option<&A> + where A: PartialOrd, + { + if let Some(first) = self.first() { + let min = self.fold(first, |acc, x| if acc == acc && !(x < acc) {acc} else {x}); + if min == min { + Some(min) + } else { + None + } + } else { + None + } + } + /// Return sum along `axis`. /// /// ```