-
Notifications
You must be signed in to change notification settings - Fork 180
Expand file tree
/
Copy pathmin_max.rs
More file actions
93 lines (85 loc) · 3.01 KB
/
Copy pathmin_max.rs
File metadata and controls
93 lines (85 loc) · 3.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use itertools::Itertools;
use vortex_dtype::{DType, NativePType, match_each_native_ptype};
use vortex_error::VortexResult;
use vortex_mask::Mask;
use vortex_scalar::{Scalar, ScalarValue};
use crate::Array;
use crate::arrays::{PrimitiveArray, PrimitiveEncoding};
use crate::compute::{MinMaxFn, MinMaxResult};
use crate::variants::PrimitiveArrayTrait;
impl MinMaxFn<&PrimitiveArray> for PrimitiveEncoding {
fn min_max(&self, array: &PrimitiveArray) -> VortexResult<Option<MinMaxResult>> {
match_each_native_ptype!(array.ptype(), |$T| {
compute_min_max_with_validity::<$T>(array)
})
}
}
#[inline]
fn compute_min_max_with_validity<T>(array: &PrimitiveArray) -> VortexResult<Option<MinMaxResult>>
where
T: Into<ScalarValue> + NativePType,
{
Ok(match array.validity_mask()? {
Mask::AllTrue(_) => compute_min_max(array.as_slice::<T>().iter(), array.dtype()),
Mask::AllFalse(_) => None,
Mask::Values(v) => compute_min_max(
array
.as_slice::<T>()
.iter()
.zip(v.boolean_buffer().iter())
.filter_map(|(v, m)| m.then_some(v)),
array.dtype(),
),
})
}
fn compute_min_max<'a, T>(iter: impl Iterator<Item = &'a T>, dtype: &DType) -> Option<MinMaxResult>
where
T: Into<ScalarValue> + NativePType,
{
// `total_compare` function provides a total ordering (even for NaN values).
// However, we exclude NaNs from min max as they're not useful for any purpose where min/max would be used
match iter
.filter(|v| !v.is_nan())
.minmax_by(|a, b| a.total_compare(**b))
{
itertools::MinMaxResult::NoElements => None,
itertools::MinMaxResult::OneElement(&x) => {
let scalar = Scalar::new(dtype.clone(), x.into());
Some(MinMaxResult {
min: scalar.clone(),
max: scalar,
})
}
itertools::MinMaxResult::MinMax(&min, &max) => Some(MinMaxResult {
min: Scalar::new(dtype.clone(), min.into()),
max: Scalar::new(dtype.clone(), max.into()),
}),
}
}
#[cfg(test)]
mod tests {
use vortex_buffer::buffer;
use crate::arrays::PrimitiveArray;
use crate::compute::min_max;
use crate::validity::Validity;
#[test]
fn min_max_nan() {
let array = PrimitiveArray::new(
buffer![f32::NAN, -f32::NAN, -1.0, 1.0],
Validity::NonNullable,
);
let min_max = min_max(&array).unwrap().unwrap();
assert_eq!(f32::try_from(min_max.min).unwrap(), -1.0);
assert_eq!(f32::try_from(min_max.max).unwrap(), 1.0);
}
#[test]
fn min_max_inf() {
let array = PrimitiveArray::new(
buffer![f32::INFINITY, f32::NEG_INFINITY, -1.0, 1.0],
Validity::NonNullable,
);
let min_max = min_max(&array).unwrap().unwrap();
assert_eq!(f32::try_from(min_max.min).unwrap(), f32::NEG_INFINITY);
assert_eq!(f32::try_from(min_max.max).unwrap(), f32::INFINITY);
}
}