vortex_array/scalar_fn/fns/mask/
mod.rs1mod kernel;
5
6pub use kernel::*;
7use vortex_error::VortexExpect;
8use vortex_error::VortexResult;
9use vortex_error::vortex_ensure;
10use vortex_session::VortexSession;
11use vortex_session::registry::CachedId;
12
13use crate::ArrayRef;
14use crate::Canonical;
15use crate::ExecutionCtx;
16use crate::IntoArray;
17use crate::arrays::Constant;
18use crate::arrays::ConstantArray;
19use crate::arrays::ScalarFnArray;
20use crate::arrays::masked::mask_validity_canonical;
21use crate::builtins::ArrayBuiltins;
22use crate::child_to_validity;
23use crate::dtype::DType;
24use crate::dtype::Nullability;
25use crate::expr::Expression;
26use crate::expr::and;
27use crate::expr::lit;
28use crate::scalar::Scalar;
29use crate::scalar_fn::Arity;
30use crate::scalar_fn::ChildName;
31use crate::scalar_fn::EmptyOptions;
32use crate::scalar_fn::ExecutionArgs;
33use crate::scalar_fn::ScalarFnId;
34use crate::scalar_fn::ScalarFnVTable;
35use crate::scalar_fn::ScalarFnVTableExt;
36use crate::scalar_fn::SimplifyCtx;
37use crate::scalar_fn::fns::literal::Literal;
38
39#[derive(Clone)]
44pub struct Mask;
45
46impl Mask {
47 pub fn try_new(input: ArrayRef, mask: ArrayRef) -> VortexResult<ScalarFnArray> {
54 ScalarFnArray::try_new(Mask.bind(EmptyOptions), vec![input, mask])
55 }
56}
57
58impl ScalarFnVTable for Mask {
59 type Options = EmptyOptions;
60
61 fn id(&self) -> ScalarFnId {
62 static ID: CachedId = CachedId::new("vortex.mask");
63 *ID
64 }
65
66 fn serialize(&self, _options: &Self::Options) -> VortexResult<Option<Vec<u8>>> {
67 Ok(Some(vec![]))
68 }
69
70 fn deserialize(
71 &self,
72 _metadata: &[u8],
73 _session: &VortexSession,
74 ) -> VortexResult<Self::Options> {
75 Ok(EmptyOptions)
76 }
77
78 fn arity(&self, _options: &Self::Options) -> Arity {
79 Arity::Exact(2)
80 }
81
82 fn child_name(&self, _options: &Self::Options, child_idx: usize) -> ChildName {
83 match child_idx {
84 0 => ChildName::from("input"),
85 1 => ChildName::from("mask"),
86 _ => unreachable!("Invalid child index {} for Mask expression", child_idx),
87 }
88 }
89
90 fn return_dtype(&self, _options: &Self::Options, arg_dtypes: &[DType]) -> VortexResult<DType> {
91 vortex_ensure!(
92 arg_dtypes[1] == DType::Bool(Nullability::NonNullable),
93 "The mask argument to 'mask' must be a non-nullable boolean array, got {}",
94 arg_dtypes[1]
95 );
96 Ok(arg_dtypes[0].as_nullable())
97 }
98
99 fn execute(
100 &self,
101 _options: &Self::Options,
102 args: &dyn ExecutionArgs,
103 ctx: &mut ExecutionCtx,
104 ) -> VortexResult<ArrayRef> {
105 let input = args.get(0)?;
106 let mask_array = args.get(1)?;
107
108 if let Some(result) = execute_constant(&input, &mask_array)? {
109 return Ok(result);
110 }
111
112 execute_canonical(input, mask_array, ctx)
113 }
114
115 fn simplify(
116 &self,
117 _options: &Self::Options,
118 expr: &Expression,
119 ctx: &dyn SimplifyCtx,
120 ) -> VortexResult<Option<Expression>> {
121 let Some(mask_lit) = expr.child(1).as_opt::<Literal>() else {
122 return Ok(None);
123 };
124
125 let mask_lit = mask_lit
126 .as_bool()
127 .value()
128 .vortex_expect("Mask must be non-nullable");
129
130 if mask_lit {
131 Ok(Some(expr.child(0).clone()))
133 } else {
134 let input_dtype = ctx.return_dtype(expr.child(0))?;
136 Ok(Some(lit(Scalar::null(input_dtype.as_nullable()))))
137 }
138 }
139
140 fn validity(
141 &self,
142 _options: &Self::Options,
143 expression: &Expression,
144 ) -> VortexResult<Option<Expression>> {
145 Ok(Some(and(
146 expression.child(0).validity()?,
147 expression.child(1).clone(),
148 )))
149 }
150
151 fn is_strict(&self, _options: &Self::Options) -> bool {
152 true
153 }
154}
155
156fn execute_constant(input: &ArrayRef, mask_array: &ArrayRef) -> VortexResult<Option<ArrayRef>> {
160 let len = input.len();
161
162 if let Some(constant_mask) = mask_array.as_opt::<Constant>() {
163 let mask_value = constant_mask.scalar().as_bool().value().unwrap_or(false);
164 return if mask_value {
165 input.cast(input.dtype().as_nullable()).map(Some)
166 } else {
167 Ok(Some(
168 ConstantArray::new(Scalar::null(input.dtype().as_nullable()), len).into_array(),
169 ))
170 };
171 }
172
173 if let Some(constant_input) = input.as_opt::<Constant>()
174 && constant_input.scalar().is_null()
175 {
176 return Ok(Some(
177 ConstantArray::new(Scalar::null(input.dtype().as_nullable()), len).into_array(),
178 ));
179 }
180
181 Ok(None)
182}
183
184fn execute_canonical(
186 input: ArrayRef,
187 mask_array: ArrayRef,
188 ctx: &mut ExecutionCtx,
189) -> VortexResult<ArrayRef> {
190 let validity = child_to_validity(Some(&mask_array), Nullability::Nullable);
191 let canonical = input.execute::<Canonical>(ctx)?;
192 Ok(mask_validity_canonical(canonical, validity, ctx)?.into_array())
193}
194
195#[cfg(test)]
196mod test {
197 use vortex_error::VortexExpect;
198
199 use crate::dtype::DType;
200 use crate::dtype::Nullability::Nullable;
201 use crate::dtype::PType;
202 use crate::expr::lit;
203 use crate::expr::mask;
204 use crate::scalar::Scalar;
205
206 #[test]
207 fn test_simplify() {
208 let input_expr = lit(42u32);
209 let true_mask_expr = lit(true);
210 let false_mask_expr = lit(false);
211
212 let mask_true_expr = mask(input_expr.clone(), true_mask_expr);
213 let simplified_true = mask_true_expr
214 .optimize(&DType::Null)
215 .vortex_expect("Simplification");
216 assert_eq!(&simplified_true, &input_expr);
217
218 let mask_false_expr = mask(input_expr, false_mask_expr);
219 let simplified_false = mask_false_expr
220 .optimize(&DType::Null)
221 .vortex_expect("Simplification");
222 let expected_null_expr = lit(Scalar::null(DType::Primitive(PType::U32, Nullable)));
223 assert_eq!(&simplified_false, &expected_null_expr);
224 }
225}