Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-expr/src/reduce/sum.rs
6940 views
1
use std::borrow::Cow;
2
3
use arrow::array::PrimitiveArray;
4
use num_traits::Zero;
5
use polars_core::with_match_physical_numeric_polars_type;
6
use polars_utils::float::IsFloat;
7
8
use super::*;
9
10
pub trait SumCast: Sized {
11
type Sum: NumericNative + From<Self>;
12
}
13
14
macro_rules! impl_sum_cast {
15
($($x:ty),*) => {
16
$(impl SumCast for $x { type Sum = $x; })*
17
};
18
($($from:ty as $to:ty),*) => {
19
$(impl SumCast for $from { type Sum = $to; })*
20
};
21
}
22
23
impl_sum_cast!(
24
bool as IdxSize,
25
u8 as i64,
26
u16 as i64,
27
i8 as i64,
28
i16 as i64
29
);
30
impl_sum_cast!(u32, u64, i32, i64, f32, f64);
31
#[cfg(feature = "dtype-i128")]
32
impl_sum_cast!(i128);
33
34
fn out_dtype(in_dtype: &DataType) -> DataType {
35
use DataType::*;
36
match in_dtype {
37
Boolean => IDX_DTYPE,
38
Int8 | UInt8 | Int16 | UInt16 => Int64,
39
dt => dt.clone(),
40
}
41
}
42
43
pub fn new_sum_reduction(dtype: DataType) -> Box<dyn GroupedReduction> {
44
use DataType::*;
45
use VecGroupedReduction as VGR;
46
match dtype {
47
Boolean => Box::new(VGR::new(dtype, BoolSumReducer)),
48
_ if dtype.is_primitive_numeric() => {
49
with_match_physical_numeric_polars_type!(dtype.to_physical(), |$T| {
50
Box::new(VGR::new(dtype, NumSumReducer::<$T>(PhantomData)))
51
})
52
},
53
#[cfg(feature = "dtype-decimal")]
54
Decimal(_, _) => Box::new(VGR::new(dtype, NumSumReducer::<Int128Type>(PhantomData))),
55
Duration(_) => Box::new(VGR::new(dtype, NumSumReducer::<Int64Type>(PhantomData))),
56
// For compatibility with the current engine, should probably be an error.
57
String | Binary => Box::new(super::NullGroupedReduction::new(dtype)),
58
_ => unimplemented!("{dtype:?} is not supported by sum reduction"),
59
}
60
}
61
62
struct NumSumReducer<T>(PhantomData<T>);
63
impl<T> Clone for NumSumReducer<T> {
64
fn clone(&self) -> Self {
65
Self(PhantomData)
66
}
67
}
68
69
impl<T> Reducer for NumSumReducer<T>
70
where
71
T: PolarsNumericType,
72
<T as PolarsNumericType>::Native: SumCast,
73
ChunkedArray<T>: ChunkAgg<T::Native>,
74
{
75
type Dtype = T;
76
type Value = <T::Native as SumCast>::Sum;
77
78
#[inline(always)]
79
fn init(&self) -> Self::Value {
80
Zero::zero()
81
}
82
83
fn cast_series<'a>(&self, s: &'a Series) -> Cow<'a, Series> {
84
s.to_physical_repr()
85
}
86
87
#[inline(always)]
88
fn combine(&self, a: &mut Self::Value, b: &Self::Value) {
89
*a += *b;
90
}
91
92
#[inline(always)]
93
fn reduce_one(&self, a: &mut Self::Value, b: Option<T::Native>, _seq_id: u64) {
94
*a += b.map(Into::into).unwrap_or(Zero::zero());
95
}
96
97
fn reduce_ca(&self, v: &mut Self::Value, ca: &ChunkedArray<Self::Dtype>, _seq_id: u64) {
98
if T::Native::is_float() {
99
*v += ChunkAgg::sum(ca).map(Into::into).unwrap_or(Zero::zero());
100
} else {
101
for arr in ca.downcast_iter() {
102
if arr.has_nulls() {
103
for x in arr.iter() {
104
*v += x.copied().map(Into::into).unwrap_or(Zero::zero());
105
}
106
} else {
107
for x in arr.values_iter().copied() {
108
*v += x.into();
109
}
110
}
111
}
112
}
113
}
114
115
fn finish(
116
&self,
117
v: Vec<Self::Value>,
118
m: Option<Bitmap>,
119
dtype: &DataType,
120
) -> PolarsResult<Series> {
121
assert!(m.is_none());
122
let arr = Box::new(PrimitiveArray::from_vec(v));
123
Ok(unsafe {
124
Series::from_chunks_and_dtype_unchecked(PlSmallStr::EMPTY, vec![arr], &out_dtype(dtype))
125
})
126
}
127
}
128
129
#[derive(Clone)]
130
struct BoolSumReducer;
131
132
impl Reducer for BoolSumReducer {
133
type Dtype = BooleanType;
134
type Value = IdxSize;
135
136
#[inline(always)]
137
fn init(&self) -> Self::Value {
138
0
139
}
140
141
#[inline(always)]
142
fn combine(&self, a: &mut Self::Value, b: &Self::Value) {
143
*a += *b;
144
}
145
146
#[inline(always)]
147
fn reduce_one(&self, a: &mut Self::Value, b: Option<bool>, _seq_id: u64) {
148
*a += b.unwrap_or(false) as IdxSize;
149
}
150
151
fn reduce_ca(&self, v: &mut Self::Value, ca: &ChunkedArray<Self::Dtype>, _seq_id: u64) {
152
*v += ca.sum().unwrap_or(0) as IdxSize;
153
}
154
155
fn finish(
156
&self,
157
v: Vec<Self::Value>,
158
m: Option<Bitmap>,
159
dtype: &DataType,
160
) -> PolarsResult<Series> {
161
assert!(m.is_none());
162
assert!(dtype == &DataType::Boolean);
163
Ok(IdxCa::from_vec(PlSmallStr::EMPTY, v).into_series())
164
}
165
}
166
167