vortex_array/expr/exprs/
not.rs1use std::fmt::Formatter;
5
6use vortex_compute::logical::LogicalNot;
7use vortex_dtype::DType;
8use vortex_error::VortexExpect;
9use vortex_error::VortexResult;
10use vortex_error::vortex_bail;
11use vortex_vector::Datum;
12
13use crate::ArrayRef;
14use crate::compute::invert;
15use crate::expr::Arity;
16use crate::expr::ChildName;
17use crate::expr::EmptyOptions;
18use crate::expr::ExecutionArgs;
19use crate::expr::ExprId;
20use crate::expr::Expression;
21use crate::expr::VTable;
22use crate::expr::VTableExt;
23
24pub struct Not;
26
27impl VTable for Not {
28 type Options = EmptyOptions;
29
30 fn id(&self) -> ExprId {
31 ExprId::from("vortex.not")
32 }
33
34 fn serialize(&self, _options: &Self::Options) -> VortexResult<Option<Vec<u8>>> {
35 Ok(Some(vec![]))
36 }
37
38 fn deserialize(&self, _metadata: &[u8]) -> VortexResult<Self::Options> {
39 Ok(EmptyOptions)
40 }
41
42 fn arity(&self, _options: &Self::Options) -> Arity {
43 Arity::Exact(1)
44 }
45
46 fn child_name(&self, _options: &Self::Options, child_idx: usize) -> ChildName {
47 match child_idx {
48 0 => ChildName::from("input"),
49 _ => unreachable!("Invalid child index {} for Not expression", child_idx),
50 }
51 }
52
53 fn fmt_sql(
54 &self,
55 _options: &Self::Options,
56 expr: &Expression,
57 f: &mut Formatter<'_>,
58 ) -> std::fmt::Result {
59 write!(f, "not(")?;
60 expr.child(0).fmt_sql(f)?;
61 write!(f, ")")
62 }
63
64 fn return_dtype(&self, _options: &Self::Options, arg_dtypes: &[DType]) -> VortexResult<DType> {
65 let child_dtype = &arg_dtypes[0];
66 if !matches!(child_dtype, DType::Bool(_)) {
67 vortex_bail!(
68 "Not expression expects a boolean child, got: {}",
69 child_dtype
70 );
71 }
72 Ok(child_dtype.clone())
73 }
74
75 fn evaluate(
76 &self,
77 _options: &Self::Options,
78 expr: &Expression,
79 scope: &ArrayRef,
80 ) -> VortexResult<ArrayRef> {
81 let child_result = expr.child(0).evaluate(scope)?;
82 invert(&child_result)
83 }
84
85 fn execute(&self, _data: &Self::Options, mut args: ExecutionArgs) -> VortexResult<Datum> {
86 let child = args.datums.pop().vortex_expect("Missing input child");
87 Ok(child.into_bool().not().into())
88 }
89
90 fn is_null_sensitive(&self, _options: &Self::Options) -> bool {
91 false
92 }
93
94 fn is_fallible(&self, _options: &Self::Options) -> bool {
95 false
96 }
97}
98
99pub fn not(operand: Expression) -> Expression {
108 Not.new_expr(EmptyOptions, vec![operand])
109}
110
111#[cfg(test)]
112mod tests {
113 use vortex_dtype::DType;
114 use vortex_dtype::Nullability;
115
116 use super::not;
117 use crate::ToCanonical;
118 use crate::arrays::BoolArray;
119 use crate::expr::exprs::get_item::col;
120 use crate::expr::exprs::get_item::get_item;
121 use crate::expr::exprs::root::root;
122 use crate::expr::test_harness;
123
124 #[test]
125 fn invert_booleans() {
126 let not_expr = not(root());
127 let bools = BoolArray::from_iter([false, true, false, false, true, true]);
128 assert_eq!(
129 not_expr
130 .evaluate(&bools.to_array())
131 .unwrap()
132 .to_bool()
133 .bit_buffer()
134 .iter()
135 .collect::<Vec<_>>(),
136 vec![true, false, true, true, false, false]
137 );
138 }
139
140 #[test]
141 fn test_display_order_of_operations() {
142 let a = not(get_item("a", root()));
143 let b = get_item("a", not(root()));
144 assert_ne!(a.to_string(), b.to_string());
145 assert_eq!(a.to_string(), "not($.a)");
146 assert_eq!(b.to_string(), "not($).a");
147 }
148
149 #[test]
150 fn dtype() {
151 let not_expr = not(root());
152 let dtype = DType::Bool(Nullability::NonNullable);
153 assert_eq!(
154 not_expr.return_dtype(&dtype).unwrap(),
155 DType::Bool(Nullability::NonNullable)
156 );
157
158 let dtype = test_harness::struct_dtype();
159 assert_eq!(
160 not(col("bool1")).return_dtype(&dtype).unwrap(),
161 DType::Bool(Nullability::NonNullable)
162 );
163 }
164}