Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-expr/src/dispatch/boolean.rs
7884 views
1
use std::ops::{BitAnd, BitOr};
2
use std::sync::Arc;
3
4
use polars_core::POOL;
5
use polars_core::error::PolarsResult;
6
use polars_core::prelude::{BooleanChunked, Column, DataType, IntoColumn, NamedFrom};
7
use polars_plan::dsl::{ColumnsUdf, SpecialEq};
8
use polars_plan::plans::IRBooleanFunction;
9
use polars_utils::pl_str::PlSmallStr;
10
use polars_utils::total_ord::TotalOrdWrap;
11
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
12
13
pub fn function_expr_to_udf(func: IRBooleanFunction) -> SpecialEq<Arc<dyn ColumnsUdf>> {
14
use IRBooleanFunction::*;
15
match func {
16
Any { ignore_nulls } => map!(any, ignore_nulls),
17
All { ignore_nulls } => map!(all, ignore_nulls),
18
IsNull => map!(is_null),
19
IsNotNull => map!(is_not_null),
20
IsFinite => map!(is_finite),
21
IsInfinite => map!(is_infinite),
22
IsNan => map!(is_nan),
23
IsNotNan => map!(is_not_nan),
24
#[cfg(feature = "is_first_distinct")]
25
IsFirstDistinct => map!(is_first_distinct),
26
#[cfg(feature = "is_last_distinct")]
27
IsLastDistinct => map!(is_last_distinct),
28
#[cfg(feature = "is_unique")]
29
IsUnique => map!(is_unique),
30
#[cfg(feature = "is_unique")]
31
IsDuplicated => map!(is_duplicated),
32
#[cfg(feature = "is_between")]
33
IsBetween { closed } => map_as_slice!(is_between, closed),
34
#[cfg(feature = "is_in")]
35
IsIn { nulls_equal } => wrap!(is_in, nulls_equal),
36
#[cfg(feature = "is_close")]
37
IsClose {
38
abs_tol,
39
rel_tol,
40
nans_equal,
41
} => wrap!(is_close, abs_tol, rel_tol, nans_equal),
42
Not => map!(not),
43
AllHorizontal => map_as_slice!(all_horizontal),
44
AnyHorizontal => map_as_slice!(any_horizontal),
45
}
46
}
47
48
fn any(s: &Column, ignore_nulls: bool) -> PolarsResult<Column> {
49
let ca = s.bool()?;
50
if ignore_nulls {
51
Ok(Column::new(s.name().clone(), [ca.any()]))
52
} else {
53
Ok(Column::new(s.name().clone(), [ca.any_kleene()]))
54
}
55
}
56
57
fn all(s: &Column, ignore_nulls: bool) -> PolarsResult<Column> {
58
let ca = s.bool()?;
59
if ignore_nulls {
60
Ok(Column::new(s.name().clone(), [ca.all()]))
61
} else {
62
Ok(Column::new(s.name().clone(), [ca.all_kleene()]))
63
}
64
}
65
66
fn is_null(s: &Column) -> PolarsResult<Column> {
67
Ok(s.is_null().into_column())
68
}
69
70
fn is_not_null(s: &Column) -> PolarsResult<Column> {
71
Ok(s.is_not_null().into_column())
72
}
73
74
fn is_finite(s: &Column) -> PolarsResult<Column> {
75
s.is_finite().map(|ca| ca.into_column())
76
}
77
78
fn is_infinite(s: &Column) -> PolarsResult<Column> {
79
s.is_infinite().map(|ca| ca.into_column())
80
}
81
82
pub(super) fn is_nan(s: &Column) -> PolarsResult<Column> {
83
s.is_nan().map(|ca| ca.into_column())
84
}
85
86
pub(super) fn is_not_nan(s: &Column) -> PolarsResult<Column> {
87
s.is_not_nan().map(|ca| ca.into_column())
88
}
89
90
#[cfg(feature = "is_first_distinct")]
91
fn is_first_distinct(s: &Column) -> PolarsResult<Column> {
92
polars_ops::prelude::is_first_distinct(s.as_materialized_series()).map(|ca| ca.into_column())
93
}
94
95
#[cfg(feature = "is_last_distinct")]
96
fn is_last_distinct(s: &Column) -> PolarsResult<Column> {
97
polars_ops::prelude::is_last_distinct(s.as_materialized_series()).map(|ca| ca.into_column())
98
}
99
100
#[cfg(feature = "is_unique")]
101
fn is_unique(s: &Column) -> PolarsResult<Column> {
102
polars_ops::prelude::is_unique(s.as_materialized_series()).map(|ca| ca.into_column())
103
}
104
105
#[cfg(feature = "is_unique")]
106
fn is_duplicated(s: &Column) -> PolarsResult<Column> {
107
polars_ops::prelude::is_duplicated(s.as_materialized_series()).map(|ca| ca.into_column())
108
}
109
110
#[cfg(feature = "is_between")]
111
fn is_between(s: &[Column], closed: polars_ops::series::ClosedInterval) -> PolarsResult<Column> {
112
let ser = &s[0];
113
let lower = &s[1];
114
let upper = &s[2];
115
polars_ops::prelude::is_between(
116
ser.as_materialized_series(),
117
lower.as_materialized_series(),
118
upper.as_materialized_series(),
119
closed,
120
)
121
.map(|ca| ca.into_column())
122
}
123
124
#[cfg(feature = "is_in")]
125
fn is_in(s: &mut [Column], nulls_equal: bool) -> PolarsResult<Column> {
126
let left = &s[0];
127
let other = &s[1];
128
polars_ops::prelude::is_in(
129
left.as_materialized_series(),
130
other.as_materialized_series(),
131
nulls_equal,
132
)
133
.map(IntoColumn::into_column)
134
}
135
136
#[cfg(feature = "is_close")]
137
fn is_close(
138
s: &mut [Column],
139
abs_tol: TotalOrdWrap<f64>,
140
rel_tol: TotalOrdWrap<f64>,
141
nans_equal: bool,
142
) -> PolarsResult<Column> {
143
let left = &s[0];
144
let right = &s[1];
145
polars_ops::prelude::is_close(
146
left.as_materialized_series(),
147
right.as_materialized_series(),
148
abs_tol.0,
149
rel_tol.0,
150
nans_equal,
151
)
152
.map(IntoColumn::into_column)
153
}
154
155
fn not(s: &Column) -> PolarsResult<Column> {
156
polars_ops::series::negate_bitwise(s.as_materialized_series()).map(Column::from)
157
}
158
159
// We shouldn't hit these often only on very wide dataframes where we don't reduce to & expressions.
160
fn any_horizontal(s: &[Column]) -> PolarsResult<Column> {
161
let out = POOL
162
.install(|| {
163
s.par_iter()
164
.try_fold(
165
|| BooleanChunked::new(PlSmallStr::EMPTY, &[false]),
166
|acc, b| {
167
let b = b.cast(&DataType::Boolean)?;
168
let b = b.bool()?;
169
PolarsResult::Ok((&acc).bitor(b))
170
},
171
)
172
.try_reduce(
173
|| BooleanChunked::new(PlSmallStr::EMPTY, [false]),
174
|a, b| Ok(a.bitor(b)),
175
)
176
})?
177
.with_name(s[0].name().clone());
178
Ok(out.into_column())
179
}
180
181
// We shouldn't hit these often only on very wide dataframes where we don't reduce to & expressions.
182
fn all_horizontal(s: &[Column]) -> PolarsResult<Column> {
183
let out = POOL
184
.install(|| {
185
s.par_iter()
186
.try_fold(
187
|| BooleanChunked::new(PlSmallStr::EMPTY, &[true]),
188
|acc, b| {
189
let b = b.cast(&DataType::Boolean)?;
190
let b = b.bool()?;
191
PolarsResult::Ok((&acc).bitand(b))
192
},
193
)
194
.try_reduce(
195
|| BooleanChunked::new(PlSmallStr::EMPTY, [true]),
196
|a, b| Ok(a.bitand(b)),
197
)
198
})?
199
.with_name(s[0].name().clone());
200
Ok(out.into_column())
201
}
202
203