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