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