Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-expr/src/dispatch/horizontal.rs
7884 views
1
use std::borrow::Cow;
2
3
use polars_core::error::{PolarsResult, polars_bail, polars_ensure};
4
use polars_core::prelude::{Column, DataType, IntoColumn};
5
use polars_core::series::Series;
6
use polars_core::utils::try_get_supertype;
7
use polars_plan::callback::PlanCallback;
8
9
pub fn fold(
10
c: &[Column],
11
callback: &PlanCallback<(Series, Series), Series>,
12
returns_scalar: bool,
13
return_dtype: Option<&DataType>,
14
) -> PolarsResult<Column> {
15
let mut acc = c[0].clone().take_materialized_series();
16
let first_dtype = acc.dtype().clone();
17
for c in &c[1..] {
18
acc = callback.call((acc.clone(), c.clone().take_materialized_series()))?;
19
}
20
polars_ensure!(
21
!returns_scalar || acc.len() == 1,
22
InvalidOperation: "`fold` is said to return scalar but returned {} elements", acc.len(),
23
);
24
polars_ensure!(
25
return_dtype.is_none_or(|dt| dt == acc.dtype()),
26
ComputeError: "`fold` did not return given return_dtype ({} != {})", return_dtype.unwrap(), acc.dtype()
27
);
28
29
if return_dtype.is_none() && acc.dtype() != &first_dtype {
30
acc = acc.cast(&first_dtype)?;
31
}
32
33
Ok(acc.into_column())
34
}
35
36
pub fn reduce(
37
c: &[Column],
38
callback: &PlanCallback<(Series, Series), Series>,
39
returns_scalar: bool,
40
return_dtype: Option<&DataType>,
41
) -> PolarsResult<Column> {
42
let Some(acc) = c.first() else {
43
polars_bail!(ComputeError: "`reduce` did not have any expressions to fold");
44
};
45
46
let output_dtype = match return_dtype {
47
None => {
48
let mut supertype = acc.dtype().clone();
49
for c in &c[1..] {
50
supertype = try_get_supertype(&supertype, c.dtype())?;
51
}
52
Cow::Owned(supertype)
53
},
54
Some(dt) => Cow::Borrowed(dt),
55
};
56
let output_dtype = output_dtype.as_ref();
57
58
let mut acc = acc.clone().take_materialized_series();
59
for c in &c[1..] {
60
acc = callback.call((acc.clone(), c.clone().take_materialized_series()))?;
61
}
62
63
polars_ensure!(
64
!returns_scalar || acc.len() == 1,
65
InvalidOperation: "`reduce` is said to return scalar but returned {} elements", acc.len(),
66
);
67
polars_ensure!(
68
return_dtype.is_none_or(|dt| dt == acc.dtype()),
69
ComputeError: "`reduce` did not return given return_dtype ({} != {})", return_dtype.unwrap(), acc.dtype()
70
);
71
72
if acc.dtype() != output_dtype {
73
acc = acc.cast(output_dtype)?;
74
}
75
76
Ok(acc.into_column())
77
}
78
79
#[cfg(feature = "dtype-struct")]
80
pub fn cum_reduce(
81
c: &[Column],
82
callback: &PlanCallback<(Series, Series), Series>,
83
returns_scalar: bool,
84
return_dtype: Option<&DataType>,
85
) -> PolarsResult<Column> {
86
use polars_core::prelude::StructChunked;
87
88
let Some(acc) = c.first() else {
89
polars_bail!(ComputeError: "`cum_reduce` did not have any expressions to fold");
90
};
91
92
let output_dtype = match return_dtype {
93
None => {
94
let mut supertype = acc.dtype().clone();
95
for c in &c[1..] {
96
supertype = try_get_supertype(&supertype, c.dtype())?;
97
}
98
Cow::Owned(supertype)
99
},
100
Some(dt) => Cow::Borrowed(dt),
101
};
102
let output_dtype = output_dtype.as_ref();
103
104
let mut result = Vec::with_capacity(c.len());
105
let mut acc = acc.clone().take_materialized_series();
106
result.push(acc.clone());
107
for c in &c[1..] {
108
let name = c.name().clone();
109
acc = callback.call((acc.clone(), c.clone().take_materialized_series()))?;
110
111
polars_ensure!(
112
!returns_scalar || acc.len() == 1,
113
InvalidOperation: "`cum_reduce` is said to return scalar but returned {} elements", acc.len(),
114
);
115
polars_ensure!(
116
return_dtype.is_none_or(|dt| dt == acc.dtype()),
117
ComputeError: "`cum_reduce` did not return given return_dtype ({} != {})", return_dtype.unwrap(), acc.dtype()
118
);
119
120
if acc.dtype() != output_dtype {
121
acc = acc.cast(output_dtype)?;
122
}
123
124
acc.rename(name);
125
result.push(acc.clone());
126
}
127
128
StructChunked::from_series(acc.name().clone(), result[0].len(), result.iter())
129
.map(|ca| ca.into_column())
130
}
131
132
#[cfg(feature = "dtype-struct")]
133
pub fn cum_fold(
134
c: &[Column],
135
callback: &PlanCallback<(Series, Series), Series>,
136
returns_scalar: bool,
137
return_dtype: Option<&DataType>,
138
include_init: bool,
139
) -> PolarsResult<Column> {
140
use polars_core::prelude::StructChunked;
141
142
let mut result = Vec::with_capacity(c.len());
143
let mut acc = c[0].clone().take_materialized_series();
144
145
let output_dtype = return_dtype.map_or_else(|| Cow::Owned(acc.dtype().clone()), Cow::Borrowed);
146
let output_dtype = output_dtype.as_ref();
147
148
if include_init {
149
result.push(acc.clone())
150
}
151
152
for c in &c[1..] {
153
let name = c.name().clone();
154
acc = callback.call((acc.clone(), c.clone().take_materialized_series()))?;
155
156
polars_ensure!(
157
!returns_scalar || acc.len() == 1,
158
InvalidOperation: "`cum_fold` is said to return scalar but returned {} elements", acc.len(),
159
);
160
polars_ensure!(
161
return_dtype.is_none_or(|dt| dt == acc.dtype()),
162
ComputeError: "`cum_fold` did not return given return_dtype ({} != {})", return_dtype.unwrap(), acc.dtype()
163
);
164
165
if acc.dtype() != output_dtype {
166
acc = acc.cast(output_dtype)?;
167
}
168
169
acc.rename(name);
170
result.push(acc.clone());
171
}
172
173
StructChunked::from_series(acc.name().clone(), result[0].len(), result.iter())
174
.map(|ca| ca.into_column())
175
}
176
177