From b9f88e9c3b4b194314bba713ac17231f6c1ea89e Mon Sep 17 00:00:00 2001
From: Son <leson.phung@gmail.com>
Date: Sat, 9 Mar 2019 13:33:44 +1100
Subject: [PATCH 1/8] A rough impl for argmin

---
 src/quantile.rs | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/src/quantile.rs b/src/quantile.rs
index 5c9b01d2..484b8e17 100644
--- a/src/quantile.rs
+++ b/src/quantile.rs
@@ -182,6 +182,13 @@ where
     S: Data<Elem = A>,
     D: Dimension,
 {
+    /// Finds the indices of the minimum values along an axis.
+    ///
+    /// Returns `None` if the array is empty.
+    fn argmin(&self) -> Option<Vec<D::Pattern>>
+    where
+        A: PartialOrd;
+
     /// Finds the elementwise minimum of the array.
     ///
     /// Returns `None` if any of the pairwise orderings tested by the function
@@ -278,6 +285,22 @@ where
     S: Data<Elem = A>,
     D: Dimension,
 {
+    fn argmin(&self) -> Option<Vec<D::Pattern>>
+    where
+        A: PartialOrd,
+    {
+        let min = self.min()?;
+        let mut args = Vec::<D::Pattern>::new();
+
+        self.indexed_iter().for_each(|(pattern, elem)| {
+            if elem.partial_cmp(min) == Some(cmp::Ordering::Equal) {
+                args.push(pattern)
+            }
+        });
+
+        Some(args)
+    }
+
     fn min(&self) -> Option<&A>
     where
         A: PartialOrd,

From b69a9d02a7335ba13f62f40ddf087862167fe07b Mon Sep 17 00:00:00 2001
From: Son <leson.phung@gmail.com>
Date: Sat, 9 Mar 2019 21:13:04 +1100
Subject: [PATCH 2/8] A tests for argmin

---
 tests/quantile.rs | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/tests/quantile.rs b/tests/quantile.rs
index 66d3c64c..af69a0e6 100644
--- a/tests/quantile.rs
+++ b/tests/quantile.rs
@@ -8,6 +8,24 @@ use ndarray_stats::{
     Quantile1dExt, QuantileExt,
 };
 
+#[test]
+fn test_argmin() {
+    let a = array![[1, 5, 3], [2, 0, 6]];
+    assert_eq!(a.argmin(), Some(vec![(1, 1)]));
+
+    let a = array![[1., 5., 3.], [2., 0., 6.]];
+    assert_eq!(a.argmin(), Some(vec![(1, 1)]));
+
+    let a = array![[1., 5., 3.], [2., ::std::f64::NAN, 6.]];
+    assert_eq!(a.argmin(), None);
+}
+
+#[test]
+fn test_argmin_multiple_values() {
+    let a = array![[1, 5, 3], [2, 0, 6], [0, 1, 2]];
+    assert_eq!(a.argmin(), Some(vec![(1, 1), (2, 0)]));
+}
+
 #[test]
 fn test_min() {
     let a = array![[1, 5, 3], [2, 0, 6]];

From 3cba684bd9e61a753a3552be54d3272d68668a17 Mon Sep 17 00:00:00 2001
From: Son <leson.phung@gmail.com>
Date: Sat, 9 Mar 2019 21:21:42 +1100
Subject: [PATCH 3/8] Add argmax

---
 src/quantile.rs   | 33 ++++++++++++++++++++++++++++++++-
 tests/quantile.rs | 18 ++++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/src/quantile.rs b/src/quantile.rs
index 484b8e17..ec52dda2 100644
--- a/src/quantile.rs
+++ b/src/quantile.rs
@@ -182,7 +182,11 @@ where
     S: Data<Elem = A>,
     D: Dimension,
 {
-    /// Finds the indices of the minimum values along an axis.
+    /// Finds the indices of the minimum values of the array.
+    ///
+    /// Returns `None` if any of the pairwise orderings tested by the function
+    /// are undefined. (For example, this occurs if there are any
+    /// floating-point NaN values in the array.)
     ///
     /// Returns `None` if the array is empty.
     fn argmin(&self) -> Option<Vec<D::Pattern>>
@@ -210,6 +214,17 @@ where
         A: MaybeNan,
         A::NotNan: Ord;
 
+    /// Finds the indices of the maximum values of the array.
+    ///
+    /// Returns `None` if any of the pairwise orderings tested by the function
+    /// are undefined. (For example, this occurs if there are any
+    /// floating-point NaN values in the array.)
+    ///
+    /// Returns `None` if the array is empty.
+    fn argmax(&self) -> Option<Vec<D::Pattern>>
+    where
+        A: PartialOrd;
+
     /// Finds the elementwise maximum of the array.
     ///
     /// Returns `None` if any of the pairwise orderings tested by the function
@@ -326,6 +341,22 @@ where
         }))
     }
 
+    fn argmax(&self) -> Option<Vec<D::Pattern>>
+    where
+        A: PartialOrd,
+    {
+        let max = self.max()?;
+        let mut args = Vec::<D::Pattern>::new();
+
+        self.indexed_iter().for_each(|(pattern, elem)| {
+            if elem.partial_cmp(max) == Some(cmp::Ordering::Equal) {
+                args.push(pattern)
+            }
+        });
+
+        Some(args)
+    }
+
     fn max(&self) -> Option<&A>
     where
         A: PartialOrd,
diff --git a/tests/quantile.rs b/tests/quantile.rs
index af69a0e6..555501d3 100644
--- a/tests/quantile.rs
+++ b/tests/quantile.rs
@@ -53,6 +53,24 @@ fn test_min_skipnan_all_nan() {
     assert!(a.min_skipnan().is_nan());
 }
 
+#[test]
+fn test_argmax() {
+    let a = array![[1, 5, 3], [2, 0, 6]];
+    assert_eq!(a.argmax(), Some(vec![(1, 2)]));
+
+    let a = array![[1., 5., 3.], [2., 0., 6.]];
+    assert_eq!(a.argmax(), Some(vec![(1, 2)]));
+
+    let a = array![[1., 5., 3.], [2., ::std::f64::NAN, 6.]];
+    assert_eq!(a.argmax(), None);
+}
+
+#[test]
+fn test_argmax_multiple_values() {
+    let a = array![[1, 6, 3], [2, 6, 6], [6, 1, 2]];
+    assert_eq!(a.argmax(), Some(vec![(0, 1), (1, 1), (1, 2), (2, 0)]));
+}
+
 #[test]
 fn test_max() {
     let a = array![[1, 5, 7], [2, 0, 6]];

From 0f23e3731f54f12c237ea3586e9a442bf743df8e Mon Sep 17 00:00:00 2001
From: Son <leson.phung@gmail.com>
Date: Sat, 9 Mar 2019 22:41:11 +1100
Subject: [PATCH 4/8] Make the implementation closer to numpy and Julia.

---
 src/quantile.rs   | 54 ++++++++++++++++++++++++++++-------------------
 tests/quantile.rs | 20 ++++--------------
 2 files changed, 36 insertions(+), 38 deletions(-)

diff --git a/src/quantile.rs b/src/quantile.rs
index ec52dda2..1f8bfe3e 100644
--- a/src/quantile.rs
+++ b/src/quantile.rs
@@ -182,14 +182,14 @@ where
     S: Data<Elem = A>,
     D: Dimension,
 {
-    /// Finds the indices of the minimum values of the array.
+    /// Finds the first index of the minimum value of the array.
     ///
     /// Returns `None` if any of the pairwise orderings tested by the function
     /// are undefined. (For example, this occurs if there are any
     /// floating-point NaN values in the array.)
     ///
     /// Returns `None` if the array is empty.
-    fn argmin(&self) -> Option<Vec<D::Pattern>>
+    fn argmin(&self) -> Option<D::Pattern>
     where
         A: PartialOrd;
 
@@ -214,14 +214,14 @@ where
         A: MaybeNan,
         A::NotNan: Ord;
 
-    /// Finds the indices of the maximum values of the array.
+    /// Finds the first index of the maximum value of the array.
     ///
     /// Returns `None` if any of the pairwise orderings tested by the function
     /// are undefined. (For example, this occurs if there are any
     /// floating-point NaN values in the array.)
     ///
     /// Returns `None` if the array is empty.
-    fn argmax(&self) -> Option<Vec<D::Pattern>>
+    fn argmax(&self) -> Option<D::Pattern>
     where
         A: PartialOrd;
 
@@ -300,20 +300,25 @@ where
     S: Data<Elem = A>,
     D: Dimension,
 {
-    fn argmin(&self) -> Option<Vec<D::Pattern>>
+    fn argmin(&self) -> Option<D::Pattern>
     where
         A: PartialOrd,
     {
-        let min = self.min()?;
-        let mut args = Vec::<D::Pattern>::new();
+        let min = self.first()?;
+        let mut pattern_min = self.dim();
 
-        self.indexed_iter().for_each(|(pattern, elem)| {
-            if elem.partial_cmp(min) == Some(cmp::Ordering::Equal) {
-                args.push(pattern)
-            }
-        });
+        self.indexed_iter()
+            .fold(Some(min), |acc, (pattern, elem)| {
+                match elem.partial_cmp(acc?)? {
+                    cmp::Ordering::Less => {
+                        pattern_min = pattern;
+                        Some(elem)
+                    }
+                    _ => acc,
+                }
+            })?;
 
-        Some(args)
+        Some(pattern_min)
     }
 
     fn min(&self) -> Option<&A>
@@ -341,20 +346,25 @@ where
         }))
     }
 
-    fn argmax(&self) -> Option<Vec<D::Pattern>>
+    fn argmax(&self) -> Option<D::Pattern>
     where
         A: PartialOrd,
     {
-        let max = self.max()?;
-        let mut args = Vec::<D::Pattern>::new();
+        let max = self.first()?;
+        let mut pattern_max = self.dim();
 
-        self.indexed_iter().for_each(|(pattern, elem)| {
-            if elem.partial_cmp(max) == Some(cmp::Ordering::Equal) {
-                args.push(pattern)
-            }
-        });
+        self.indexed_iter()
+            .fold(Some(max), |acc, (pattern, elem)| {
+                match elem.partial_cmp(acc?)? {
+                    cmp::Ordering::Greater => {
+                        pattern_max = pattern;
+                        Some(elem)
+                    }
+                    _ => acc,
+                }
+            })?;
 
-        Some(args)
+        Some(pattern_max)
     }
 
     fn max(&self) -> Option<&A>
diff --git a/tests/quantile.rs b/tests/quantile.rs
index 555501d3..e77403c2 100644
--- a/tests/quantile.rs
+++ b/tests/quantile.rs
@@ -11,21 +11,15 @@ use ndarray_stats::{
 #[test]
 fn test_argmin() {
     let a = array![[1, 5, 3], [2, 0, 6]];
-    assert_eq!(a.argmin(), Some(vec![(1, 1)]));
+    assert_eq!(a.argmin(), Some((1, 1)));
 
     let a = array![[1., 5., 3.], [2., 0., 6.]];
-    assert_eq!(a.argmin(), Some(vec![(1, 1)]));
+    assert_eq!(a.argmin(), Some((1, 1)));
 
     let a = array![[1., 5., 3.], [2., ::std::f64::NAN, 6.]];
     assert_eq!(a.argmin(), None);
 }
 
-#[test]
-fn test_argmin_multiple_values() {
-    let a = array![[1, 5, 3], [2, 0, 6], [0, 1, 2]];
-    assert_eq!(a.argmin(), Some(vec![(1, 1), (2, 0)]));
-}
-
 #[test]
 fn test_min() {
     let a = array![[1, 5, 3], [2, 0, 6]];
@@ -56,21 +50,15 @@ fn test_min_skipnan_all_nan() {
 #[test]
 fn test_argmax() {
     let a = array![[1, 5, 3], [2, 0, 6]];
-    assert_eq!(a.argmax(), Some(vec![(1, 2)]));
+    assert_eq!(a.argmax(), Some((1, 2)));
 
     let a = array![[1., 5., 3.], [2., 0., 6.]];
-    assert_eq!(a.argmax(), Some(vec![(1, 2)]));
+    assert_eq!(a.argmax(), Some((1, 2)));
 
     let a = array![[1., 5., 3.], [2., ::std::f64::NAN, 6.]];
     assert_eq!(a.argmax(), None);
 }
 
-#[test]
-fn test_argmax_multiple_values() {
-    let a = array![[1, 6, 3], [2, 6, 6], [6, 1, 2]];
-    assert_eq!(a.argmax(), Some(vec![(0, 1), (1, 1), (1, 2), (2, 0)]));
-}
-
 #[test]
 fn test_max() {
     let a = array![[1, 5, 7], [2, 0, 6]];

From dd218f303d6883da2ae5c3519e43cf36f3c97934 Mon Sep 17 00:00:00 2001
From: Son <leson.phung@gmail.com>
Date: Sat, 9 Mar 2019 23:09:08 +1100
Subject: [PATCH 5/8] Correctly initialize pattern

---
 src/quantile.rs   | 4 ++--
 tests/quantile.rs | 8 ++++----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/quantile.rs b/src/quantile.rs
index 1f8bfe3e..c15678f3 100644
--- a/src/quantile.rs
+++ b/src/quantile.rs
@@ -305,7 +305,7 @@ where
         A: PartialOrd,
     {
         let min = self.first()?;
-        let mut pattern_min = self.dim();
+        let mut pattern_min = D::zeros(self.ndim()).into_pattern();
 
         self.indexed_iter()
             .fold(Some(min), |acc, (pattern, elem)| {
@@ -351,7 +351,7 @@ where
         A: PartialOrd,
     {
         let max = self.first()?;
-        let mut pattern_max = self.dim();
+        let mut pattern_max = D::zeros(self.ndim()).into_pattern();
 
         self.indexed_iter()
             .fold(Some(max), |acc, (pattern, elem)| {
diff --git a/tests/quantile.rs b/tests/quantile.rs
index e77403c2..cf88dc1d 100644
--- a/tests/quantile.rs
+++ b/tests/quantile.rs
@@ -10,8 +10,8 @@ use ndarray_stats::{
 
 #[test]
 fn test_argmin() {
-    let a = array![[1, 5, 3], [2, 0, 6]];
-    assert_eq!(a.argmin(), Some((1, 1)));
+    let a = array![[0, 5, 3], [2, 0, 6]];
+    assert_eq!(a.argmin(), Some((0, 0)));
 
     let a = array![[1., 5., 3.], [2., 0., 6.]];
     assert_eq!(a.argmin(), Some((1, 1)));
@@ -49,8 +49,8 @@ fn test_min_skipnan_all_nan() {
 
 #[test]
 fn test_argmax() {
-    let a = array![[1, 5, 3], [2, 0, 6]];
-    assert_eq!(a.argmax(), Some((1, 2)));
+    let a = array![[7, 5, 3], [2, 0, 6]];
+    assert_eq!(a.argmax(), Some((0, 0)));
 
     let a = array![[1., 5., 3.], [2., 0., 6.]];
     assert_eq!(a.argmax(), Some((1, 2)));

From 9e41f77f54c111e638101715a664f04b3da4c0bc Mon Sep 17 00:00:00 2001
From: Son <leson.phung@gmail.com>
Date: Sun, 10 Mar 2019 21:51:00 +1100
Subject: [PATCH 6/8] Simplify argmin argmax and add a test case

---
 src/quantile.rs   | 44 ++++++++++++++++++--------------------------
 tests/quantile.rs | 14 ++++++++++----
 2 files changed, 28 insertions(+), 30 deletions(-)

diff --git a/src/quantile.rs b/src/quantile.rs
index c15678f3..637ca3e7 100644
--- a/src/quantile.rs
+++ b/src/quantile.rs
@@ -304,21 +304,17 @@ where
     where
         A: PartialOrd,
     {
-        let min = self.first()?;
-        let mut pattern_min = D::zeros(self.ndim()).into_pattern();
+        let mut current_min = self.first()?;
+        let mut current_pattern_min = D::zeros(self.ndim()).into_pattern();
 
-        self.indexed_iter()
-            .fold(Some(min), |acc, (pattern, elem)| {
-                match elem.partial_cmp(acc?)? {
-                    cmp::Ordering::Less => {
-                        pattern_min = pattern;
-                        Some(elem)
-                    }
-                    _ => acc,
-                }
-            })?;
+        for (pattern, elem) in self.indexed_iter() {
+            if elem.partial_cmp(current_min)? == cmp::Ordering::Less {
+                current_pattern_min = pattern;
+                current_min = elem
+            }
+        }
 
-        Some(pattern_min)
+        Some(current_pattern_min)
     }
 
     fn min(&self) -> Option<&A>
@@ -350,21 +346,17 @@ where
     where
         A: PartialOrd,
     {
-        let max = self.first()?;
-        let mut pattern_max = D::zeros(self.ndim()).into_pattern();
+        let mut current_max = self.first()?;
+        let mut current_pattern_max = D::zeros(self.ndim()).into_pattern();
 
-        self.indexed_iter()
-            .fold(Some(max), |acc, (pattern, elem)| {
-                match elem.partial_cmp(acc?)? {
-                    cmp::Ordering::Greater => {
-                        pattern_max = pattern;
-                        Some(elem)
-                    }
-                    _ => acc,
-                }
-            })?;
+        for (pattern, elem) in self.indexed_iter() {
+            if elem.partial_cmp(current_max)? == cmp::Ordering::Greater {
+                current_pattern_max = pattern;
+                current_max = elem
+            }
+        }
 
-        Some(pattern_max)
+        Some(current_pattern_max)
     }
 
     fn max(&self) -> Option<&A>
diff --git a/tests/quantile.rs b/tests/quantile.rs
index cf88dc1d..62c091a9 100644
--- a/tests/quantile.rs
+++ b/tests/quantile.rs
@@ -10,14 +10,17 @@ use ndarray_stats::{
 
 #[test]
 fn test_argmin() {
-    let a = array![[0, 5, 3], [2, 0, 6]];
-    assert_eq!(a.argmin(), Some((0, 0)));
+    let a = array![[1, 5, 3], [2, 0, 6]];
+    assert_eq!(a.argmin(), Some((1, 1)));
 
     let a = array![[1., 5., 3.], [2., 0., 6.]];
     assert_eq!(a.argmin(), Some((1, 1)));
 
     let a = array![[1., 5., 3.], [2., ::std::f64::NAN, 6.]];
     assert_eq!(a.argmin(), None);
+
+    let a = array![[1, 0, 3], [2, 0, 6]];
+    assert_eq!(a.argmin(), Some((0, 1)));
 }
 
 #[test]
@@ -49,14 +52,17 @@ fn test_min_skipnan_all_nan() {
 
 #[test]
 fn test_argmax() {
-    let a = array![[7, 5, 3], [2, 0, 6]];
-    assert_eq!(a.argmax(), Some((0, 0)));
+    let a = array![[1, 5, 3], [2, 0, 6]];
+    assert_eq!(a.argmax(), Some((1, 2)));
 
     let a = array![[1., 5., 3.], [2., 0., 6.]];
     assert_eq!(a.argmax(), Some((1, 2)));
 
     let a = array![[1., 5., 3.], [2., ::std::f64::NAN, 6.]];
     assert_eq!(a.argmax(), None);
+
+    let a = array![[1, 5, 6], [2, 0, 6]];
+    assert_eq!(a.argmax(), Some((0, 2)));
 }
 
 #[test]

From f9bd4b4afbc4866efc7438c770832cf8907ab7f6 Mon Sep 17 00:00:00 2001
From: Son <leson.phung@gmail.com>
Date: Sun, 10 Mar 2019 21:58:32 +1100
Subject: [PATCH 7/8] Add a test case of empty array

---
 tests/quantile.rs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/tests/quantile.rs b/tests/quantile.rs
index 62c091a9..4e799d2f 100644
--- a/tests/quantile.rs
+++ b/tests/quantile.rs
@@ -21,6 +21,9 @@ fn test_argmin() {
 
     let a = array![[1, 0, 3], [2, 0, 6]];
     assert_eq!(a.argmin(), Some((0, 1)));
+
+    let a: Array2<i32> = array![[], []];
+    assert_eq!(a.argmin(), None);
 }
 
 #[test]
@@ -63,6 +66,9 @@ fn test_argmax() {
 
     let a = array![[1, 5, 6], [2, 0, 6]];
     assert_eq!(a.argmax(), Some((0, 2)));
+
+    let a: Array2<i32> = array![[], []];
+    assert_eq!(a.argmax(), None);
 }
 
 #[test]

From a9b3826956578cf0286c79ca5545ba6c394d7ea0 Mon Sep 17 00:00:00 2001
From: Son <leson.phung@gmail.com>
Date: Sun, 10 Mar 2019 22:20:50 +1100
Subject: [PATCH 8/8] Add examples for docs

---
 src/quantile.rs | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/src/quantile.rs b/src/quantile.rs
index 637ca3e7..a396edde 100644
--- a/src/quantile.rs
+++ b/src/quantile.rs
@@ -189,6 +189,20 @@ where
     /// floating-point NaN values in the array.)
     ///
     /// Returns `None` if the array is empty.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// extern crate ndarray;
+    /// extern crate ndarray_stats;
+    ///
+    /// use ndarray::array;
+    /// use ndarray_stats::QuantileExt;
+    ///
+    /// let a = array![[1., 3., 5.],
+    ///                [2., 0., 6.]];
+    /// assert_eq!(a.argmin(), Some((1, 1)));
+    /// ```
     fn argmin(&self) -> Option<D::Pattern>
     where
         A: PartialOrd;
@@ -221,6 +235,20 @@ where
     /// floating-point NaN values in the array.)
     ///
     /// Returns `None` if the array is empty.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// extern crate ndarray;
+    /// extern crate ndarray_stats;
+    ///
+    /// use ndarray::array;
+    /// use ndarray_stats::QuantileExt;
+    ///
+    /// let a = array![[1., 3., 7.],
+    ///                [2., 5., 6.]];
+    /// assert_eq!(a.argmax(), Some((0, 2)));
+    /// ```
     fn argmax(&self) -> Option<D::Pattern>
     where
         A: PartialOrd;