Path: blob/main/crates/polars-compute/src/min_max/scalar.rs
6939 views
use arrow::array::{1Array, BinaryArray, BinaryViewArray, BooleanArray, PrimitiveArray, Utf8Array, Utf8ViewArray,2};3use arrow::types::{NativeType, Offset};4use polars_utils::min_max::MinMax;56use super::MinMaxKernel;78fn min_max_ignore_nan<T: NativeType>((cur_min, cur_max): (T, T), (min, max): (T, T)) -> (T, T) {9(10MinMax::min_ignore_nan(cur_min, min),11MinMax::max_ignore_nan(cur_max, max),12)13}1415fn min_max_propagate_nan<T: NativeType>((cur_min, cur_max): (T, T), (min, max): (T, T)) -> (T, T) {16(17MinMax::min_propagate_nan(cur_min, min),18MinMax::max_propagate_nan(cur_max, max),19)20}2122fn reduce_vals<T, F>(v: &PrimitiveArray<T>, f: F) -> Option<T>23where24T: NativeType,25F: Fn(T, T) -> T,26{27if v.null_count() == 0 {28v.values_iter().copied().reduce(f)29} else {30v.non_null_values_iter().reduce(f)31}32}3334fn reduce_tuple_vals<T, F>(v: &PrimitiveArray<T>, f: F) -> Option<(T, T)>35where36T: NativeType,37F: Fn((T, T), (T, T)) -> (T, T),38{39if v.null_count() == 0 {40v.values_iter().copied().map(|v| (v, v)).reduce(f)41} else {42v.non_null_values_iter().map(|v| (v, v)).reduce(f)43}44}4546impl<T: NativeType + MinMax + super::NotSimdPrimitive> MinMaxKernel for PrimitiveArray<T> {47type Scalar<'a> = T;4849fn min_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {50reduce_vals(self, MinMax::min_ignore_nan)51}5253fn max_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {54reduce_vals(self, MinMax::max_ignore_nan)55}5657fn min_max_ignore_nan_kernel(&self) -> Option<(Self::Scalar<'_>, Self::Scalar<'_>)> {58reduce_tuple_vals(self, min_max_ignore_nan)59}6061fn min_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {62reduce_vals(self, MinMax::min_propagate_nan)63}6465fn max_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {66reduce_vals(self, MinMax::max_propagate_nan)67}6869fn min_max_propagate_nan_kernel(&self) -> Option<(Self::Scalar<'_>, Self::Scalar<'_>)> {70reduce_tuple_vals(self, min_max_propagate_nan)71}72}7374impl<T: NativeType + MinMax + super::NotSimdPrimitive> MinMaxKernel for [T] {75type Scalar<'a> = T;7677fn min_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {78self.iter().copied().reduce(MinMax::min_ignore_nan)79}8081fn max_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {82self.iter().copied().reduce(MinMax::max_ignore_nan)83}8485fn min_max_ignore_nan_kernel(&self) -> Option<(Self::Scalar<'_>, Self::Scalar<'_>)> {86self.iter()87.copied()88.map(|v| (v, v))89.reduce(min_max_ignore_nan)90}9192fn min_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {93self.iter().copied().reduce(MinMax::min_propagate_nan)94}9596fn max_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {97self.iter().copied().reduce(MinMax::max_propagate_nan)98}99100fn min_max_propagate_nan_kernel(&self) -> Option<(Self::Scalar<'_>, Self::Scalar<'_>)> {101self.iter()102.copied()103.map(|v| (v, v))104.reduce(min_max_propagate_nan)105}106}107108impl MinMaxKernel for BooleanArray {109type Scalar<'a> = bool;110111fn min_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {112if self.len() - self.null_count() == 0 {113return None;114}115116let unset_bits = self.values().unset_bits();117Some(unset_bits == 0)118}119120fn max_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {121if self.len() - self.null_count() == 0 {122return None;123}124125let set_bits = self.values().set_bits();126Some(set_bits > 0)127}128129#[inline(always)]130fn min_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {131self.min_ignore_nan_kernel()132}133134#[inline(always)]135fn max_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {136self.max_ignore_nan_kernel()137}138}139140impl MinMaxKernel for BinaryViewArray {141type Scalar<'a> = &'a [u8];142143fn min_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {144if self.null_count() == 0 {145self.values_iter().reduce(MinMax::min_ignore_nan)146} else {147self.non_null_values_iter().reduce(MinMax::min_ignore_nan)148}149}150151fn max_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {152if self.null_count() == 0 {153self.values_iter().reduce(MinMax::max_ignore_nan)154} else {155self.non_null_values_iter().reduce(MinMax::max_ignore_nan)156}157}158159#[inline(always)]160fn min_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {161self.min_ignore_nan_kernel()162}163164#[inline(always)]165fn max_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {166self.max_ignore_nan_kernel()167}168}169170impl MinMaxKernel for Utf8ViewArray {171type Scalar<'a> = &'a str;172173#[inline(always)]174fn min_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {175self.to_binview().min_ignore_nan_kernel().map(|s| unsafe {176// SAFETY: the lifetime is the same, and it is valid UTF-8.177#[allow(clippy::transmute_bytes_to_str)]178std::mem::transmute::<&[u8], &str>(s)179})180}181182#[inline(always)]183fn max_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {184self.to_binview().max_ignore_nan_kernel().map(|s| unsafe {185// SAFETY: the lifetime is the same, and it is valid UTF-8.186#[allow(clippy::transmute_bytes_to_str)]187std::mem::transmute::<&[u8], &str>(s)188})189}190191#[inline(always)]192fn min_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {193self.min_ignore_nan_kernel()194}195196#[inline(always)]197fn max_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {198self.max_ignore_nan_kernel()199}200}201202impl<O: Offset> MinMaxKernel for BinaryArray<O> {203type Scalar<'a> = &'a [u8];204205fn min_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {206if self.null_count() == 0 {207self.values_iter().reduce(MinMax::min_ignore_nan)208} else {209self.non_null_values_iter().reduce(MinMax::min_ignore_nan)210}211}212213fn max_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {214if self.null_count() == 0 {215self.values_iter().reduce(MinMax::max_ignore_nan)216} else {217self.non_null_values_iter().reduce(MinMax::max_ignore_nan)218}219}220221#[inline(always)]222fn min_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {223self.min_ignore_nan_kernel()224}225226#[inline(always)]227fn max_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {228self.max_ignore_nan_kernel()229}230}231232impl<O: Offset> MinMaxKernel for Utf8Array<O> {233type Scalar<'a> = &'a str;234235#[inline(always)]236fn min_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {237self.to_binary().min_ignore_nan_kernel().map(|s| unsafe {238// SAFETY: the lifetime is the same, and it is valid UTF-8.239#[allow(clippy::transmute_bytes_to_str)]240std::mem::transmute::<&[u8], &str>(s)241})242}243244#[inline(always)]245fn max_ignore_nan_kernel(&self) -> Option<Self::Scalar<'_>> {246self.to_binary().max_ignore_nan_kernel().map(|s| unsafe {247// SAFETY: the lifetime is the same, and it is valid UTF-8.248#[allow(clippy::transmute_bytes_to_str)]249std::mem::transmute::<&[u8], &str>(s)250})251}252253#[inline(always)]254fn min_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {255self.min_ignore_nan_kernel()256}257258#[inline(always)]259fn max_propagate_nan_kernel(&self) -> Option<Self::Scalar<'_>> {260self.max_ignore_nan_kernel()261}262}263264265