Path: blob/main/crates/polars-arrow/src/compute/boolean_kleene.rs
6939 views
//! Boolean operators of [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics).1use crate::array::{Array, BooleanArray};2use crate::bitmap::{Bitmap, binary, quaternary, ternary, unary};3use crate::datatypes::ArrowDataType;4use crate::scalar::BooleanScalar;56/// Logical 'or' operation on two arrays with [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics)7/// # Panics8/// This function panics iff the arrays have a different length9/// # Example10///11/// ```rust12/// use polars_arrow::array::BooleanArray;13/// use polars_arrow::compute::boolean_kleene::or;14///15/// let a = BooleanArray::from(&[Some(true), Some(false), None]);16/// let b = BooleanArray::from(&[None, None, None]);17/// let or_ab = or(&a, &b);18/// assert_eq!(or_ab, BooleanArray::from(&[Some(true), None, None]));19/// ```20pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray {21assert_eq!(22lhs.len(),23rhs.len(),24"lhs and rhs must have the same length"25);2627let lhs_values = lhs.values();28let rhs_values = rhs.values();2930let lhs_validity = lhs.validity();31let rhs_validity = rhs.validity();3233let validity = match (lhs_validity, rhs_validity) {34(Some(lhs_validity), Some(rhs_validity)) => {35Some(quaternary(36lhs_values,37rhs_values,38lhs_validity,39rhs_validity,40// see https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics41|lhs, rhs, lhs_v, rhs_v| {42// A = T43(lhs & lhs_v) |44// B = T45(rhs & rhs_v) |46// A = F & B = F47(!lhs & lhs_v) & (!rhs & rhs_v)48},49))50},51(Some(lhs_validity), None) => {52// B != U53Some(ternary(54lhs_values,55rhs_values,56lhs_validity,57// see https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics58|lhs, rhs, lhs_v| {59// A = T60(lhs & lhs_v) |61// B = T62rhs |63// A = F & B = F64(!lhs & lhs_v) & !rhs65},66))67},68(None, Some(rhs_validity)) => {69Some(ternary(70lhs_values,71rhs_values,72rhs_validity,73// see https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics74|lhs, rhs, rhs_v| {75// A = T76lhs |77// B = T78(rhs & rhs_v) |79// A = F & B = F80!lhs & (!rhs & rhs_v)81},82))83},84(None, None) => None,85};86BooleanArray::new(ArrowDataType::Boolean, lhs_values | rhs_values, validity)87}8889/// Logical 'and' operation on two arrays with [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics)90/// # Panics91/// This function panics iff the arrays have a different length92/// # Example93///94/// ```rust95/// use polars_arrow::array::BooleanArray;96/// use polars_arrow::compute::boolean_kleene::and;97///98/// let a = BooleanArray::from(&[Some(true), Some(false), None]);99/// let b = BooleanArray::from(&[None, None, None]);100/// let and_ab = and(&a, &b);101/// assert_eq!(and_ab, BooleanArray::from(&[None, Some(false), None]));102/// ```103pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray {104assert_eq!(105lhs.len(),106rhs.len(),107"lhs and rhs must have the same length"108);109110let lhs_values = lhs.values();111let rhs_values = rhs.values();112113let lhs_validity = lhs.validity();114let rhs_validity = rhs.validity();115116let validity = match (lhs_validity, rhs_validity) {117(Some(lhs_validity), Some(rhs_validity)) => {118Some(quaternary(119lhs_values,120rhs_values,121lhs_validity,122rhs_validity,123// see https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics124|lhs, rhs, lhs_v, rhs_v| {125// B = F126(!rhs & rhs_v) |127// A = F128(!lhs & lhs_v) |129// A = T & B = T130(lhs & lhs_v) & (rhs & rhs_v)131},132))133},134(Some(lhs_validity), None) => {135Some(ternary(136lhs_values,137rhs_values,138lhs_validity,139// see https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics140|lhs, rhs, lhs_v| {141// B = F142!rhs |143// A = F144(!lhs & lhs_v) |145// A = T & B = T146(lhs & lhs_v) & rhs147},148))149},150(None, Some(rhs_validity)) => {151Some(ternary(152lhs_values,153rhs_values,154rhs_validity,155// see https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics156|lhs, rhs, rhs_v| {157// B = F158(!rhs & rhs_v) |159// A = F160!lhs |161// A = T & B = T162lhs & (rhs & rhs_v)163},164))165},166(None, None) => None,167};168BooleanArray::new(ArrowDataType::Boolean, lhs_values & rhs_values, validity)169}170171/// Logical 'or' operation on an array and a scalar value with [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics)172/// # Example173///174/// ```rust175/// use polars_arrow::array::BooleanArray;176/// use polars_arrow::scalar::BooleanScalar;177/// use polars_arrow::compute::boolean_kleene::or_scalar;178///179/// let array = BooleanArray::from(&[Some(true), Some(false), None]);180/// let scalar = BooleanScalar::new(Some(false));181/// let result = or_scalar(&array, &scalar);182/// assert_eq!(result, BooleanArray::from(&[Some(true), Some(false), None]));183/// ```184pub fn or_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {185match scalar.value() {186Some(true) => BooleanArray::new(187ArrowDataType::Boolean,188Bitmap::new_with_value(true, array.len()),189None,190),191Some(false) => array.clone(),192None => {193let values = array.values();194let validity = match array.validity() {195Some(validity) => binary(values, validity, |value, validity| validity & value),196None => unary(values, |value| value),197};198BooleanArray::new(ArrowDataType::Boolean, values.clone(), Some(validity))199},200}201}202203/// Logical 'and' operation on an array and a scalar value with [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics)204/// # Example205///206/// ```rust207/// use polars_arrow::array::BooleanArray;208/// use polars_arrow::scalar::BooleanScalar;209/// use polars_arrow::compute::boolean_kleene::and_scalar;210///211/// let array = BooleanArray::from(&[Some(true), Some(false), None]);212/// let scalar = BooleanScalar::new(None);213/// let result = and_scalar(&array, &scalar);214/// assert_eq!(result, BooleanArray::from(&[None, Some(false), None]));215/// ```216pub fn and_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {217match scalar.value() {218Some(true) => array.clone(),219Some(false) => {220let values = Bitmap::new_zeroed(array.len());221BooleanArray::new(ArrowDataType::Boolean, values, None)222},223None => {224let values = array.values();225let validity = match array.validity() {226Some(validity) => binary(values, validity, |value, validity| validity & !value),227None => unary(values, |value| !value),228};229BooleanArray::new(230ArrowDataType::Boolean,231array.values().clone(),232Some(validity),233)234},235}236}237238/// Returns whether any of the values in the array are `true`.239///240/// The output is unknown (`None`) if the array contains any null values and241/// no `true` values.242///243/// # Example244///245/// ```246/// use polars_arrow::array::BooleanArray;247/// use polars_arrow::compute::boolean_kleene::any;248///249/// let a = BooleanArray::from(&[Some(true), Some(false)]);250/// let b = BooleanArray::from(&[Some(false), Some(false)]);251/// let c = BooleanArray::from(&[None, Some(false)]);252///253/// assert_eq!(any(&a), Some(true));254/// assert_eq!(any(&b), Some(false));255/// assert_eq!(any(&c), None);256/// ```257pub fn any(array: &BooleanArray) -> Option<bool> {258if array.is_empty() {259Some(false)260} else if array.null_count() > 0 {261if array.into_iter().any(|v| v == Some(true)) {262Some(true)263} else {264None265}266} else {267let vals = array.values();268Some(vals.unset_bits() != vals.len())269}270}271272/// Returns whether all values in the array are `true`.273///274/// The output is unknown (`None`) if the array contains any null values and275/// no `false` values.276///277/// # Example278///279/// ```280/// use polars_arrow::array::BooleanArray;281/// use polars_arrow::compute::boolean_kleene::all;282///283/// let a = BooleanArray::from(&[Some(true), Some(true)]);284/// let b = BooleanArray::from(&[Some(false), Some(true)]);285/// let c = BooleanArray::from(&[None, Some(true)]);286///287/// assert_eq!(all(&a), Some(true));288/// assert_eq!(all(&b), Some(false));289/// assert_eq!(all(&c), None);290/// ```291pub fn all(array: &BooleanArray) -> Option<bool> {292if array.is_empty() {293Some(true)294} else if array.null_count() > 0 {295if array.into_iter().any(|v| v == Some(false)) {296Some(false)297} else {298None299}300} else {301let vals = array.values();302Some(vals.unset_bits() == 0)303}304}305306307