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