arrow2/compute/boolean_kleene.rs
1//! Boolean operators of [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics).
2use crate::datatypes::DataType;
3use crate::scalar::BooleanScalar;
4use crate::{
5 array::{Array, BooleanArray},
6 bitmap::{binary, quaternary, ternary, unary, Bitmap, MutableBitmap},
7};
8
9/// Logical 'or' operation on two arrays with [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics)
10/// # Panics
11/// This function panics iff the arrays have a different length
12/// # Example
13///
14/// ```rust
15/// use arrow2::array::BooleanArray;
16/// use arrow2::compute::boolean_kleene::or;
17///
18/// let a = BooleanArray::from(&[Some(true), Some(false), None]);
19/// let b = BooleanArray::from(&[None, None, None]);
20/// let or_ab = or(&a, &b);
21/// assert_eq!(or_ab, BooleanArray::from(&[Some(true), None, None]));
22/// ```
23pub fn or(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray {
24 assert_eq!(
25 lhs.len(),
26 rhs.len(),
27 "lhs and rhs must have the same length"
28 );
29
30 let lhs_values = lhs.values();
31 let rhs_values = rhs.values();
32
33 let lhs_validity = lhs.validity();
34 let rhs_validity = rhs.validity();
35
36 let validity = match (lhs_validity, rhs_validity) {
37 (Some(lhs_validity), Some(rhs_validity)) => {
38 Some(quaternary(
39 lhs_values,
40 rhs_values,
41 lhs_validity,
42 rhs_validity,
43 // see https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics
44 |lhs, rhs, lhs_v, rhs_v| {
45 // A = T
46 (lhs & lhs_v) |
47 // B = T
48 (rhs & rhs_v) |
49 // A = F & B = F
50 (!lhs & lhs_v) & (!rhs & rhs_v)
51 },
52 ))
53 }
54 (Some(lhs_validity), None) => {
55 // B != U
56 Some(ternary(
57 lhs_values,
58 rhs_values,
59 lhs_validity,
60 // see https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics
61 |lhs, rhs, lhs_v| {
62 // A = T
63 (lhs & lhs_v) |
64 // B = T
65 rhs |
66 // A = F & B = F
67 (!lhs & lhs_v) & !rhs
68 },
69 ))
70 }
71 (None, Some(rhs_validity)) => {
72 Some(ternary(
73 lhs_values,
74 rhs_values,
75 rhs_validity,
76 // see https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics
77 |lhs, rhs, rhs_v| {
78 // A = T
79 lhs |
80 // B = T
81 (rhs & rhs_v) |
82 // A = F & B = F
83 !lhs & (!rhs & rhs_v)
84 },
85 ))
86 }
87 (None, None) => None,
88 };
89 BooleanArray::new(DataType::Boolean, lhs_values | rhs_values, validity)
90}
91
92/// Logical 'and' operation on two arrays with [Kleene logic](https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics)
93/// # Panics
94/// This function panics iff the arrays have a different length
95/// # Example
96///
97/// ```rust
98/// use arrow2::array::BooleanArray;
99/// use arrow2::compute::boolean_kleene::and;
100///
101/// let a = BooleanArray::from(&[Some(true), Some(false), None]);
102/// let b = BooleanArray::from(&[None, None, None]);
103/// let and_ab = and(&a, &b);
104/// assert_eq!(and_ab, BooleanArray::from(&[None, Some(false), None]));
105/// ```
106pub fn and(lhs: &BooleanArray, rhs: &BooleanArray) -> BooleanArray {
107 assert_eq!(
108 lhs.len(),
109 rhs.len(),
110 "lhs and rhs must have the same length"
111 );
112
113 let lhs_values = lhs.values();
114 let rhs_values = rhs.values();
115
116 let lhs_validity = lhs.validity();
117 let rhs_validity = rhs.validity();
118
119 let validity = match (lhs_validity, rhs_validity) {
120 (Some(lhs_validity), Some(rhs_validity)) => {
121 Some(quaternary(
122 lhs_values,
123 rhs_values,
124 lhs_validity,
125 rhs_validity,
126 // see https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics
127 |lhs, rhs, lhs_v, rhs_v| {
128 // B = F
129 (!rhs & rhs_v) |
130 // A = F
131 (!lhs & lhs_v) |
132 // A = T & B = T
133 (lhs & lhs_v) & (rhs & rhs_v)
134 },
135 ))
136 }
137 (Some(lhs_validity), None) => {
138 Some(ternary(
139 lhs_values,
140 rhs_values,
141 lhs_validity,
142 // see https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics
143 |lhs, rhs, lhs_v| {
144 // B = F
145 !rhs |
146 // A = F
147 (!lhs & lhs_v) |
148 // A = T & B = T
149 (lhs & lhs_v) & rhs
150 },
151 ))
152 }
153 (None, Some(rhs_validity)) => {
154 Some(ternary(
155 lhs_values,
156 rhs_values,
157 rhs_validity,
158 // see https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics
159 |lhs, rhs, rhs_v| {
160 // B = F
161 (!rhs & rhs_v) |
162 // A = F
163 !lhs |
164 // A = T & B = T
165 lhs & (rhs & rhs_v)
166 },
167 ))
168 }
169 (None, None) => None,
170 };
171 BooleanArray::new(DataType::Boolean, lhs_values & rhs_values, validity)
172}
173
174/// 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)
175/// # Example
176///
177/// ```rust
178/// use arrow2::array::BooleanArray;
179/// use arrow2::scalar::BooleanScalar;
180/// use arrow2::compute::boolean_kleene::or_scalar;
181///
182/// let array = BooleanArray::from(&[Some(true), Some(false), None]);
183/// let scalar = BooleanScalar::new(Some(false));
184/// let result = or_scalar(&array, &scalar);
185/// assert_eq!(result, BooleanArray::from(&[Some(true), Some(false), None]));
186/// ```
187pub fn or_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {
188 match scalar.value() {
189 Some(true) => {
190 let mut values = MutableBitmap::new();
191 values.extend_constant(array.len(), true);
192 BooleanArray::new(DataType::Boolean, values.into(), None)
193 }
194 Some(false) => array.clone(),
195 None => {
196 let values = array.values();
197 let validity = match array.validity() {
198 Some(validity) => binary(values, validity, |value, validity| validity & value),
199 None => unary(values, |value| value),
200 };
201 BooleanArray::new(DataType::Boolean, values.clone(), Some(validity))
202 }
203 }
204}
205
206/// 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)
207/// # Example
208///
209/// ```rust
210/// use arrow2::array::BooleanArray;
211/// use arrow2::scalar::BooleanScalar;
212/// use arrow2::compute::boolean_kleene::and_scalar;
213///
214/// let array = BooleanArray::from(&[Some(true), Some(false), None]);
215/// let scalar = BooleanScalar::new(None);
216/// let result = and_scalar(&array, &scalar);
217/// assert_eq!(result, BooleanArray::from(&[None, Some(false), None]));
218/// ```
219pub fn and_scalar(array: &BooleanArray, scalar: &BooleanScalar) -> BooleanArray {
220 match scalar.value() {
221 Some(true) => array.clone(),
222 Some(false) => {
223 let values = Bitmap::new_zeroed(array.len());
224 BooleanArray::new(DataType::Boolean, values, None)
225 }
226 None => {
227 let values = array.values();
228 let validity = match array.validity() {
229 Some(validity) => binary(values, validity, |value, validity| validity & !value),
230 None => unary(values, |value| !value),
231 };
232 BooleanArray::new(DataType::Boolean, array.values().clone(), Some(validity))
233 }
234 }
235}
236
237/// Returns whether any of the values in the array are `true`.
238///
239/// The output is unknown (`None`) if the array contains any null values and
240/// no `true` values.
241///
242/// # Example
243///
244/// ```
245/// use arrow2::array::BooleanArray;
246/// use arrow2::compute::boolean_kleene::any;
247///
248/// let a = BooleanArray::from(&[Some(true), Some(false)]);
249/// let b = BooleanArray::from(&[Some(false), Some(false)]);
250/// let c = BooleanArray::from(&[None, Some(false)]);
251///
252/// assert_eq!(any(&a), Some(true));
253/// assert_eq!(any(&b), Some(false));
254/// assert_eq!(any(&c), None);
255/// ```
256pub fn any(array: &BooleanArray) -> Option<bool> {
257 if array.is_empty() {
258 Some(false)
259 } else if array.null_count() > 0 {
260 if array.into_iter().any(|v| v == Some(true)) {
261 Some(true)
262 } else {
263 None
264 }
265 } else {
266 let vals = array.values();
267 Some(vals.unset_bits() != vals.len())
268 }
269}
270
271/// Returns whether all values in the array are `true`.
272///
273/// The output is unknown (`None`) if the array contains any null values and
274/// no `false` values.
275///
276/// # Example
277///
278/// ```
279/// use arrow2::array::BooleanArray;
280/// use arrow2::compute::boolean_kleene::all;
281///
282/// let a = BooleanArray::from(&[Some(true), Some(true)]);
283/// let b = BooleanArray::from(&[Some(false), Some(true)]);
284/// let c = BooleanArray::from(&[None, Some(true)]);
285///
286/// assert_eq!(all(&a), Some(true));
287/// assert_eq!(all(&b), Some(false));
288/// assert_eq!(all(&c), None);
289/// ```
290pub fn all(array: &BooleanArray) -> Option<bool> {
291 if array.is_empty() {
292 Some(true)
293 } else if array.null_count() > 0 {
294 if array.into_iter().any(|v| v == Some(false)) {
295 Some(false)
296 } else {
297 None
298 }
299 } else {
300 let vals = array.values();
301 Some(vals.unset_bits() == 0)
302 }
303}