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
8420 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
#[cfg(feature = "dtype-f16")]
8
use polars_utils::float16::pf16;
9
10
use super::*;
11
12
pub trait SumCast: Sized {
13
type Sum: NumericNative + From<Self>;
14
}
15
16
macro_rules! impl_sum_cast {
17
($($x:ty),*) => {
18
$(impl SumCast for $x { type Sum = $x; })*
19
};
20
($($from:ty as $to:ty),*) => {
21
$(impl SumCast for $from { type Sum = $to; })*
22
};
23
}
24
25
impl_sum_cast!(
26
bool as IdxSize,
27
u8 as i64,
28
u16 as i64,
29
i8 as i64,
30
i16 as i64
31
);
32
impl_sum_cast!(u32, u64, i32, i64, f32, f64);
33
#[cfg(feature = "dtype-f16")]
34
impl_sum_cast!(pf16);
35
#[cfg(feature = "dtype-i128")]
36
impl_sum_cast!(i128);
37
#[cfg(feature = "dtype-u128")]
38
impl_sum_cast!(u128);
39
40
fn out_dtype(in_dtype: &DataType) -> DataType {
41
use DataType::*;
42
match in_dtype {
43
Boolean => IDX_DTYPE,
44
Int8 | UInt8 | Int16 | UInt16 => Int64,
45
dt => dt.clone(),
46
}
47
}
48
49
pub fn new_sum_reduction(dtype: DataType) -> PolarsResult<Box<dyn GroupedReduction>> {
50
// TODO: Move the error checks up and make this function infallible
51
use DataType::*;
52
use VecGroupedReduction as VGR;
53
Ok(match dtype {
54
Boolean => Box::new(VGR::new(dtype, BoolSumReducer)),
55
_ if dtype.is_primitive_numeric() => {
56
with_match_physical_numeric_polars_type!(dtype.to_physical(), |$T| {
57
Box::new(VGR::new(dtype, NumSumReducer::<$T>(PhantomData)))
58
})
59
},
60
#[cfg(feature = "dtype-decimal")]
61
Decimal(_, _) => Box::new(VGR::new(dtype, NumSumReducer::<Int128Type>(PhantomData))),
62
Duration(_) => Box::new(VGR::new(dtype, NumSumReducer::<Int64Type>(PhantomData))),
63
Null => Box::new(super::NullGroupedReduction::new(Scalar::null(
64
DataType::Null,
65
))),
66
String => {
67
polars_bail!(
68
op = "`sum`",
69
DataType::String,
70
hint = "you may mean to call `str.join` or `list.join`"
71
);
72
},
73
_ => polars_bail!(op = "`sum`", dtype),
74
})
75
}
76
77
struct NumSumReducer<T>(PhantomData<T>);
78
impl<T> Clone for NumSumReducer<T> {
79
fn clone(&self) -> Self {
80
Self(PhantomData)
81
}
82
}
83
84
impl<T> Reducer for NumSumReducer<T>
85
where
86
T: PolarsNumericType,
87
<T as PolarsNumericType>::Native: SumCast,
88
ChunkedArray<T>: ChunkAgg<T::Native>,
89
{
90
type Dtype = T;
91
type Value = <T::Native as SumCast>::Sum;
92
93
#[inline(always)]
94
fn init(&self) -> Self::Value {
95
Zero::zero()
96
}
97
98
fn cast_series<'a>(&self, s: &'a Series) -> Cow<'a, Series> {
99
s.to_physical_repr()
100
}
101
102
#[inline(always)]
103
fn combine(&self, a: &mut Self::Value, b: &Self::Value) {
104
*a += *b;
105
}
106
107
#[inline(always)]
108
fn reduce_one(&self, a: &mut Self::Value, b: Option<T::Native>, _seq_id: u64) {
109
*a += b.map(Into::into).unwrap_or(Zero::zero());
110
}
111
112
fn reduce_ca(&self, v: &mut Self::Value, ca: &ChunkedArray<Self::Dtype>, _seq_id: u64) {
113
if T::Native::is_float() {
114
*v += ChunkAgg::sum(ca).map(Into::into).unwrap_or(Zero::zero());
115
} else {
116
for arr in ca.downcast_iter() {
117
if arr.has_nulls() {
118
for x in arr.iter() {
119
*v += x.copied().map(Into::into).unwrap_or(Zero::zero());
120
}
121
} else {
122
for x in arr.values_iter().copied() {
123
*v += x.into();
124
}
125
}
126
}
127
}
128
}
129
130
fn finish(
131
&self,
132
v: Vec<Self::Value>,
133
m: Option<Bitmap>,
134
dtype: &DataType,
135
) -> PolarsResult<Series> {
136
assert!(m.is_none());
137
let arr = Box::new(PrimitiveArray::from_vec(v));
138
Ok(unsafe {
139
Series::from_chunks_and_dtype_unchecked(PlSmallStr::EMPTY, vec![arr], &out_dtype(dtype))
140
})
141
}
142
}
143
144
#[derive(Clone)]
145
struct BoolSumReducer;
146
147
impl Reducer for BoolSumReducer {
148
type Dtype = BooleanType;
149
type Value = IdxSize;
150
151
#[inline(always)]
152
fn init(&self) -> Self::Value {
153
0
154
}
155
156
#[inline(always)]
157
fn combine(&self, a: &mut Self::Value, b: &Self::Value) {
158
*a += *b;
159
}
160
161
#[inline(always)]
162
fn reduce_one(&self, a: &mut Self::Value, b: Option<bool>, _seq_id: u64) {
163
*a += b.unwrap_or(false) as IdxSize;
164
}
165
166
fn reduce_ca(&self, v: &mut Self::Value, ca: &ChunkedArray<Self::Dtype>, _seq_id: u64) {
167
*v += ca.sum().unwrap_or(0) as IdxSize;
168
}
169
170
fn finish(
171
&self,
172
v: Vec<Self::Value>,
173
m: Option<Bitmap>,
174
dtype: &DataType,
175
) -> PolarsResult<Series> {
176
assert!(m.is_none());
177
assert!(dtype == &DataType::Boolean);
178
Ok(IdxCa::from_vec(PlSmallStr::EMPTY, v).into_series())
179
}
180
}
181
182