Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-plan/src/plans/aexpr/function_expr/range.rs
7889 views
1
use std::fmt::{Display, Formatter};
2
3
use polars_core::prelude::*;
4
use polars_ops::series::ClosedInterval;
5
#[cfg(feature = "temporal")]
6
use polars_time::{ClosedWindow, Duration};
7
8
use super::{FunctionOptions, IRFunctionExpr};
9
#[cfg(any(feature = "dtype-date", feature = "dtype-datetime"))]
10
use crate::dsl::function_expr::DateRangeArgs;
11
use crate::plans::aexpr::function_expr::FieldsMapper;
12
use crate::prelude::FunctionFlags;
13
14
#[cfg_attr(feature = "ir_serde", derive(serde::Serialize, serde::Deserialize))]
15
#[derive(Clone, PartialEq, Debug, Eq, Hash)]
16
pub enum IRRangeFunction {
17
IntRange {
18
step: i64,
19
dtype: DataType,
20
},
21
IntRanges {
22
dtype: DataType,
23
},
24
LinearSpace {
25
closed: ClosedInterval,
26
},
27
LinearSpaces {
28
closed: ClosedInterval,
29
array_width: Option<usize>,
30
},
31
#[cfg(feature = "dtype-date")]
32
DateRange {
33
interval: Option<Duration>,
34
closed: ClosedWindow,
35
arg_type: DateRangeArgs,
36
},
37
#[cfg(feature = "dtype-date")]
38
DateRanges {
39
interval: Option<Duration>,
40
closed: ClosedWindow,
41
arg_type: DateRangeArgs,
42
},
43
#[cfg(feature = "dtype-datetime")]
44
DatetimeRange {
45
interval: Option<Duration>,
46
closed: ClosedWindow,
47
time_unit: Option<TimeUnit>,
48
time_zone: Option<TimeZone>,
49
arg_type: DateRangeArgs,
50
},
51
#[cfg(feature = "dtype-datetime")]
52
DatetimeRanges {
53
interval: Option<Duration>,
54
closed: ClosedWindow,
55
time_unit: Option<TimeUnit>,
56
time_zone: Option<TimeZone>,
57
arg_type: DateRangeArgs,
58
},
59
#[cfg(feature = "dtype-time")]
60
TimeRange {
61
interval: Duration,
62
closed: ClosedWindow,
63
},
64
#[cfg(feature = "dtype-time")]
65
TimeRanges {
66
interval: Duration,
67
closed: ClosedWindow,
68
},
69
}
70
71
fn map_linspace_dtype(mapper: &FieldsMapper) -> PolarsResult<DataType> {
72
let fields = mapper.args();
73
let start_dtype = fields[0].dtype();
74
let end_dtype = fields[1].dtype();
75
Ok(match (start_dtype, end_dtype) {
76
#[cfg(feature = "dtype-f16")]
77
(&DataType::Float16, &DataType::Float16) => DataType::Float16,
78
(&DataType::Float32, &DataType::Float32) => DataType::Float32,
79
// A linear space of a Date produces a sequence of Datetimes
80
(dt1, dt2) if dt1.is_temporal() && dt1 == dt2 => {
81
if dt1 == &DataType::Date {
82
DataType::Datetime(TimeUnit::Microseconds, None)
83
} else {
84
dt1.clone()
85
}
86
},
87
(dt1, dt2) if !dt1.is_primitive_numeric() || !dt2.is_primitive_numeric() => {
88
polars_bail!(ComputeError:
89
"'start' and 'end' have incompatible dtypes, got {:?} and {:?}",
90
dt1, dt2
91
)
92
},
93
_ => DataType::Float64,
94
})
95
}
96
97
impl IRRangeFunction {
98
pub(super) fn get_field(&self, mapper: FieldsMapper) -> PolarsResult<Field> {
99
use IRRangeFunction::*;
100
match self {
101
IntRange { dtype, .. } => mapper.with_dtype(dtype.clone()),
102
IntRanges { dtype } => mapper.with_dtype(DataType::List(Box::new(dtype.clone()))),
103
LinearSpace { .. } => mapper.with_dtype(map_linspace_dtype(&mapper)?),
104
LinearSpaces {
105
closed: _,
106
array_width,
107
} => {
108
let inner = Box::new(map_linspace_dtype(&mapper)?);
109
let dt = match array_width {
110
Some(width) => DataType::Array(inner, *width),
111
None => DataType::List(inner),
112
};
113
mapper.with_dtype(dt)
114
},
115
#[cfg(feature = "dtype-date")]
116
DateRange {
117
interval: _,
118
closed: _,
119
arg_type: _,
120
} => mapper.with_dtype(DataType::Date),
121
#[cfg(feature = "dtype-date")]
122
DateRanges {
123
interval: _,
124
closed: _,
125
arg_type: _,
126
} => mapper.with_dtype(DataType::List(Box::new(DataType::Date))),
127
#[cfg(feature = "dtype-datetime")]
128
DatetimeRange {
129
interval: _,
130
closed: _,
131
time_unit,
132
time_zone,
133
arg_type: _,
134
} => {
135
// Output dtype may change based on `interval`, `time_unit`, and `time_zone`.
136
let dtype =
137
mapper.map_to_datetime_range_dtype(time_unit.as_ref(), time_zone.as_ref())?;
138
mapper.with_dtype(dtype)
139
},
140
#[cfg(feature = "dtype-datetime")]
141
DatetimeRanges {
142
interval: _,
143
closed: _,
144
time_unit,
145
time_zone,
146
arg_type: _,
147
} => {
148
// output dtype may change based on `interval`, `time_unit`, and `time_zone`
149
let inner_dtype =
150
mapper.map_to_datetime_range_dtype(time_unit.as_ref(), time_zone.as_ref())?;
151
mapper.with_dtype(DataType::List(Box::new(inner_dtype)))
152
},
153
#[cfg(feature = "dtype-time")]
154
TimeRange { .. } => mapper.with_dtype(DataType::Time),
155
#[cfg(feature = "dtype-time")]
156
TimeRanges { .. } => mapper.with_dtype(DataType::List(Box::new(DataType::Time))),
157
}
158
}
159
160
pub fn function_options(&self) -> FunctionOptions {
161
use IRRangeFunction as R;
162
match self {
163
R::IntRange { .. } => {
164
FunctionOptions::row_separable().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)
165
},
166
R::LinearSpace { .. } => {
167
FunctionOptions::row_separable().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)
168
},
169
#[cfg(feature = "dtype-date")]
170
R::DateRange { .. } => {
171
FunctionOptions::row_separable().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)
172
},
173
#[cfg(feature = "dtype-date")]
174
R::DateRanges { .. } => {
175
FunctionOptions::elementwise().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)
176
},
177
#[cfg(feature = "dtype-datetime")]
178
R::DatetimeRange { .. } => {
179
FunctionOptions::row_separable().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)
180
},
181
#[cfg(feature = "dtype-datetime")]
182
R::DatetimeRanges { .. } => {
183
FunctionOptions::elementwise().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)
184
},
185
#[cfg(feature = "dtype-time")]
186
R::TimeRange { .. } => {
187
FunctionOptions::row_separable().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)
188
},
189
R::IntRanges { .. } => {
190
FunctionOptions::elementwise().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)
191
},
192
R::LinearSpaces { .. } => {
193
FunctionOptions::elementwise().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)
194
},
195
#[cfg(feature = "dtype-time")]
196
R::TimeRanges { .. } => {
197
FunctionOptions::elementwise().with_flags(|f| f | FunctionFlags::ALLOW_RENAME)
198
},
199
}
200
}
201
}
202
203
impl Display for IRRangeFunction {
204
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
205
use IRRangeFunction::*;
206
let s = match self {
207
IntRange { .. } => "int_range",
208
IntRanges { .. } => "int_ranges",
209
LinearSpace { .. } => "linear_space",
210
LinearSpaces { .. } => "linear_spaces",
211
#[cfg(feature = "dtype-date")]
212
DateRange { .. } => "date_range",
213
#[cfg(feature = "dtype-date")]
214
DateRanges { .. } => "date_ranges",
215
#[cfg(feature = "dtype-datetime")]
216
DatetimeRange { .. } => "datetime_range",
217
#[cfg(feature = "dtype-datetime")]
218
DatetimeRanges { .. } => "datetime_ranges",
219
#[cfg(feature = "dtype-time")]
220
TimeRange { .. } => "time_range",
221
#[cfg(feature = "dtype-time")]
222
TimeRanges { .. } => "time_ranges",
223
};
224
write!(f, "{s}")
225
}
226
}
227
228
impl From<IRRangeFunction> for IRFunctionExpr {
229
fn from(value: IRRangeFunction) -> Self {
230
Self::Range(value)
231
}
232
}
233
234
impl FieldsMapper<'_> {
235
pub fn map_to_datetime_range_dtype(
236
&self,
237
time_unit: Option<&TimeUnit>,
238
time_zone: Option<&TimeZone>,
239
) -> PolarsResult<DataType> {
240
let data_dtype = self.map_to_supertype()?.dtype;
241
242
let (data_tu, data_tz) = if let DataType::Datetime(tu, tz) = data_dtype {
243
(tu, tz)
244
} else {
245
(TimeUnit::Microseconds, None)
246
};
247
248
let tu = match time_unit {
249
Some(tu) => *tu,
250
None => data_tu,
251
};
252
253
let tz = time_zone.cloned().or(data_tz);
254
255
Ok(DataType::Datetime(tu, tz))
256
}
257
}
258
259