vortex_array/arrays/constant/compute/
boolean.rs1use vortex_dtype::DType;
5use vortex_error::VortexResult;
6use vortex_error::vortex_bail;
7use vortex_error::vortex_err;
8use vortex_scalar::Scalar;
9
10use crate::Array;
11use crate::ArrayRef;
12use crate::IntoArray;
13use crate::arrays::ConstantArray;
14use crate::arrays::ConstantVTable;
15use crate::compute::BooleanKernel;
16use crate::compute::BooleanKernelAdapter;
17use crate::compute::BooleanOperator;
18use crate::register_kernel;
19
20impl BooleanKernel for ConstantVTable {
21 fn boolean(
22 &self,
23 lhs: &ConstantArray,
24 rhs: &dyn Array,
25 op: BooleanOperator,
26 ) -> VortexResult<Option<ArrayRef>> {
27 if !rhs.is_constant() {
30 return Ok(None);
31 }
32
33 let length = lhs.len();
34 let nullable = lhs.dtype().is_nullable() || rhs.dtype().is_nullable();
35 let lhs = lhs.scalar().as_bool().value();
36 let Some(rhs) = rhs.as_constant() else {
37 vortex_bail!("Binary boolean operation requires both sides to be constant");
38 };
39 let rhs = rhs
40 .as_bool_opt()
41 .ok_or_else(|| vortex_err!("expected rhs to be boolean"))?
42 .value();
43
44 let result = match op {
45 BooleanOperator::And => and(lhs, rhs),
46 BooleanOperator::AndKleene => kleene_and(lhs, rhs),
47 BooleanOperator::Or => or(lhs, rhs),
48 BooleanOperator::OrKleene => kleene_or(lhs, rhs),
49 };
50
51 let scalar = result
52 .map(|b| Scalar::bool(b, nullable.into()))
53 .unwrap_or_else(|| Scalar::null(DType::Bool(nullable.into())));
54
55 Ok(Some(ConstantArray::new(scalar, length).into_array()))
56 }
57}
58
59register_kernel!(BooleanKernelAdapter(ConstantVTable).lift());
60
61fn and(left: Option<bool>, right: Option<bool>) -> Option<bool> {
62 left.zip(right).map(|(l, r)| l & r)
63}
64
65fn kleene_and(left: Option<bool>, right: Option<bool>) -> Option<bool> {
66 match (left, right) {
67 (Some(false), _) => Some(false),
68 (_, Some(false)) => Some(false),
69 (None, _) => None,
70 (_, None) => None,
71 (Some(l), Some(r)) => Some(l & r),
72 }
73}
74
75fn or(left: Option<bool>, right: Option<bool>) -> Option<bool> {
76 left.zip(right).map(|(l, r)| l | r)
77}
78
79fn kleene_or(left: Option<bool>, right: Option<bool>) -> Option<bool> {
80 match (left, right) {
81 (Some(true), _) => Some(true),
82 (_, Some(true)) => Some(true),
83 (None, _) => None,
84 (_, None) => None,
85 (Some(l), Some(r)) => Some(l | r),
86 }
87}
88
89#[cfg(test)]
90mod test {
91 use rstest::rstest;
92
93 use crate::Array;
94 use crate::ArrayRef;
95 use crate::IntoArray;
96 use crate::arrays::BoolArray;
97 use crate::arrays::constant::ConstantArray;
98 use crate::canonical::ToCanonical;
99 use crate::compute::and;
100 use crate::compute::or;
101
102 #[rstest]
103 #[case(ConstantArray::new(true, 4).into_array(), BoolArray::from_iter([Some(true), Some(false), Some(true), Some(false)].into_iter()).into_array()
104 )]
105 #[case(BoolArray::from_iter([Some(true), Some(false), Some(true), Some(false)].into_iter()).into_array(), ConstantArray::new(true, 4).into_array()
106 )]
107 fn test_or(#[case] lhs: ArrayRef, #[case] rhs: ArrayRef) {
108 let r = or(&lhs, &rhs).unwrap().to_bool().into_array();
109
110 let v0 = r.scalar_at(0).as_bool().value();
111 let v1 = r.scalar_at(1).as_bool().value();
112 let v2 = r.scalar_at(2).as_bool().value();
113 let v3 = r.scalar_at(3).as_bool().value();
114
115 assert!(v0.unwrap());
116 assert!(v1.unwrap());
117 assert!(v2.unwrap());
118 assert!(v3.unwrap());
119 }
120
121 #[rstest]
122 #[case(ConstantArray::new(true, 4).into_array(), BoolArray::from_iter([Some(true), Some(false), Some(true), Some(false)].into_iter()).into_array()
123 )]
124 #[case(BoolArray::from_iter([Some(true), Some(false), Some(true), Some(false)].into_iter()).into_array(),
125 ConstantArray::new(true, 4).into_array())]
126 fn test_and(#[case] lhs: ArrayRef, #[case] rhs: ArrayRef) {
127 let r = and(&lhs, &rhs).unwrap().to_bool().into_array();
128
129 let v0 = r.scalar_at(0).as_bool().value();
130 let v1 = r.scalar_at(1).as_bool().value();
131 let v2 = r.scalar_at(2).as_bool().value();
132 let v3 = r.scalar_at(3).as_bool().value();
133
134 assert!(v0.unwrap());
135 assert!(!v1.unwrap());
136 assert!(v2.unwrap());
137 assert!(!v3.unwrap());
138 }
139}