Skip to content

Commit 7df0728

Browse files
jturner314LukeMathWalker
authored andcommitted
Clarify which (arg)min/max index/value is returned (#32)
* Clarify which (arg)min/max index/value is returned For performance, it's beneficial to avoid guaranteeing a particular iteration order. For example, the current implementation of `min` may return any of the minima because the iteration order of `ArrayBase.fold()` is unspecified. The current implementation of `argmin` does always return the first minimum (in logical order) since `ArrayBase.indexed_iter()` always iterates in logical order, but we may want to optimize the iteration order in the future. * Replace some tests with argmin/max_matches_min/max See discussion at #32 (comment)
1 parent e6426a6 commit 7df0728

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed

src/quantile.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,18 @@ where
182182
S: Data<Elem = A>,
183183
D: Dimension,
184184
{
185-
/// Finds the first index of the minimum value of the array.
185+
/// Finds the index of the minimum value of the array.
186186
///
187187
/// Returns `None` if any of the pairwise orderings tested by the function
188188
/// are undefined. (For example, this occurs if there are any
189189
/// floating-point NaN values in the array.)
190190
///
191191
/// Returns `None` if the array is empty.
192192
///
193+
/// Even if there are multiple (equal) elements that are minima, only one
194+
/// index is returned. (Which one is returned is unspecified and may depend
195+
/// on the memory layout of the array.)
196+
///
193197
/// # Example
194198
///
195199
/// ```
@@ -214,12 +218,20 @@ where
214218
/// floating-point NaN values in the array.)
215219
///
216220
/// Additionally, returns `None` if the array is empty.
221+
///
222+
/// Even if there are multiple (equal) elements that are minima, only one
223+
/// is returned. (Which one is returned is unspecified and may depend on
224+
/// the memory layout of the array.)
217225
fn min(&self) -> Option<&A>
218226
where
219227
A: PartialOrd;
220228

221229
/// Finds the elementwise minimum of the array, skipping NaN values.
222230
///
231+
/// Even if there are multiple (equal) elements that are minima, only one
232+
/// is returned. (Which one is returned is unspecified and may depend on
233+
/// the memory layout of the array.)
234+
///
223235
/// **Warning** This method will return a NaN value if none of the values
224236
/// in the array are non-NaN values. Note that the NaN value might not be
225237
/// in the array.
@@ -228,14 +240,18 @@ where
228240
A: MaybeNan,
229241
A::NotNan: Ord;
230242

231-
/// Finds the first index of the maximum value of the array.
243+
/// Finds the index of the maximum value of the array.
232244
///
233245
/// Returns `None` if any of the pairwise orderings tested by the function
234246
/// are undefined. (For example, this occurs if there are any
235247
/// floating-point NaN values in the array.)
236248
///
237249
/// Returns `None` if the array is empty.
238250
///
251+
/// Even if there are multiple (equal) elements that are maxima, only one
252+
/// index is returned. (Which one is returned is unspecified and may depend
253+
/// on the memory layout of the array.)
254+
///
239255
/// # Example
240256
///
241257
/// ```
@@ -260,12 +276,20 @@ where
260276
/// floating-point NaN values in the array.)
261277
///
262278
/// Additionally, returns `None` if the array is empty.
279+
///
280+
/// Even if there are multiple (equal) elements that are maxima, only one
281+
/// is returned. (Which one is returned is unspecified and may depend on
282+
/// the memory layout of the array.)
263283
fn max(&self) -> Option<&A>
264284
where
265285
A: PartialOrd;
266286

267287
/// Finds the elementwise maximum of the array, skipping NaN values.
268288
///
289+
/// Even if there are multiple (equal) elements that are maxima, only one
290+
/// is returned. (Which one is returned is unspecified and may depend on
291+
/// the memory layout of the array.)
292+
///
269293
/// **Warning** This method will return a NaN value if none of the values
270294
/// in the array are non-NaN values. Note that the NaN value might not be
271295
/// in the array.

tests/quantile.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#[macro_use(array)]
22
extern crate ndarray;
33
extern crate ndarray_stats;
4+
extern crate quickcheck;
45

56
use ndarray::prelude::*;
67
use ndarray_stats::{
78
interpolate::{Higher, Linear, Lower, Midpoint, Nearest},
89
Quantile1dExt, QuantileExt,
910
};
11+
use quickcheck::quickcheck;
1012

1113
#[test]
1214
fn test_argmin() {
@@ -19,13 +21,17 @@ fn test_argmin() {
1921
let a = array![[1., 5., 3.], [2., ::std::f64::NAN, 6.]];
2022
assert_eq!(a.argmin(), None);
2123

22-
let a = array![[1, 0, 3], [2, 0, 6]];
23-
assert_eq!(a.argmin(), Some((0, 1)));
24-
2524
let a: Array2<i32> = array![[], []];
2625
assert_eq!(a.argmin(), None);
2726
}
2827

28+
quickcheck! {
29+
fn argmin_matches_min(data: Vec<f32>) -> bool {
30+
let a = Array1::from(data);
31+
a.argmin().map(|i| a[i]) == a.min().cloned()
32+
}
33+
}
34+
2935
#[test]
3036
fn test_min() {
3137
let a = array![[1, 5, 3], [2, 0, 6]];
@@ -64,13 +70,17 @@ fn test_argmax() {
6470
let a = array![[1., 5., 3.], [2., ::std::f64::NAN, 6.]];
6571
assert_eq!(a.argmax(), None);
6672

67-
let a = array![[1, 5, 6], [2, 0, 6]];
68-
assert_eq!(a.argmax(), Some((0, 2)));
69-
7073
let a: Array2<i32> = array![[], []];
7174
assert_eq!(a.argmax(), None);
7275
}
7376

77+
quickcheck! {
78+
fn argmax_matches_max(data: Vec<f32>) -> bool {
79+
let a = Array1::from(data);
80+
a.argmax().map(|i| a[i]) == a.max().cloned()
81+
}
82+
}
83+
7484
#[test]
7585
fn test_max() {
7686
let a = array![[1, 5, 7], [2, 0, 6]];

0 commit comments

Comments
 (0)