vortex_array/scalar_fn/fns/mask/
kernel.rs1use vortex_error::VortexResult;
5use vortex_error::vortex_err;
6
7use crate::ArrayRef;
8use crate::ExecutionCtx;
9use crate::array::ArrayView;
10use crate::array::VTable;
11use crate::arrays::Bool;
12use crate::arrays::Constant;
13use crate::arrays::scalar_fn::ExactScalarFn;
14use crate::arrays::scalar_fn::ScalarFnArrayView;
15use crate::kernel::ExecuteParentKernel;
16use crate::optimizer::rules::ArrayParentReduceRule;
17use crate::scalar_fn::fns::mask::Mask as MaskExpr;
18
19pub trait MaskReduce: VTable {
32 fn mask(array: ArrayView<'_, Self>, mask: &ArrayRef) -> VortexResult<Option<ArrayRef>>;
33}
34
35pub trait MaskKernel: VTable {
47 fn mask(
48 array: ArrayView<'_, Self>,
49 mask: &ArrayRef,
50 ctx: &mut ExecutionCtx,
51 ) -> VortexResult<Option<ArrayRef>>;
52}
53
54#[derive(Default, Debug)]
56pub struct MaskReduceAdaptor<V>(pub V);
57
58impl<V> ArrayParentReduceRule<V> for MaskReduceAdaptor<V>
59where
60 V: MaskReduce,
61{
62 type Parent = ExactScalarFn<MaskExpr>;
63
64 fn reduce_parent(
65 &self,
66 array: ArrayView<'_, V>,
67 parent: ScalarFnArrayView<'_, MaskExpr>,
68 child_idx: usize,
69 ) -> VortexResult<Option<ArrayRef>> {
70 if child_idx != 0 {
72 return Ok(None);
73 }
74 let parent_ref: ArrayRef = (*parent).clone();
79 let mask_child = parent_ref
80 .nth_child(1)
81 .ok_or_else(|| vortex_err!("Mask expression must have 2 children"))?;
82 if mask_child.as_opt::<Bool>().is_none() && mask_child.as_opt::<Constant>().is_none() {
83 return Ok(None);
84 }
85 <V as MaskReduce>::mask(array, &mask_child)
86 }
87}
88
89#[derive(Default, Debug)]
91pub struct MaskExecuteAdaptor<V>(pub V);
92
93impl<V> ExecuteParentKernel<V> for MaskExecuteAdaptor<V>
94where
95 V: MaskKernel,
96{
97 type Parent = ExactScalarFn<MaskExpr>;
98
99 fn execute_parent(
100 &self,
101 array: ArrayView<'_, V>,
102 parent: ScalarFnArrayView<'_, MaskExpr>,
103 child_idx: usize,
104 ctx: &mut ExecutionCtx,
105 ) -> VortexResult<Option<ArrayRef>> {
106 if child_idx != 0 {
108 return Ok(None);
109 }
110 let mask_child = parent
111 .nth_child(1)
112 .ok_or_else(|| vortex_err!("Mask expression must have 2 children"))?;
113 <V as MaskKernel>::mask(array, &mask_child, ctx)
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use rstest::rstest;
120 use vortex_buffer::buffer;
121 use vortex_error::VortexResult;
122
123 use crate::IntoArray;
124 use crate::arrays::ConstantArray;
125 use crate::arrays::Primitive;
126 use crate::arrays::PrimitiveArray;
127 use crate::arrays::ScalarFn;
128 use crate::arrays::scalar_fn::ScalarFnFactoryExt;
129 use crate::assert_arrays_eq;
130 use crate::dtype::Nullability;
131 use crate::executor::VortexSessionExecute;
132 use crate::optimizer::ArrayOptimizer;
133 use crate::scalar::Scalar;
134 use crate::scalar_fn::EmptyOptions;
135 use crate::scalar_fn::fns::mask::Mask as MaskExpr;
136
137 #[rstest]
142 #[case(true)]
143 #[case(false)]
144 fn constant_mask_reduces_into_input(#[case] mask_value: bool) -> VortexResult<()> {
145 let input = buffer![1i32, 2, 3, 4, 5].into_array();
146 let mask = ConstantArray::new(
147 Scalar::bool(mask_value, Nullability::NonNullable),
148 input.len(),
149 )
150 .into_array();
151
152 let masked = MaskExpr.try_new_array(input.len(), EmptyOptions, [input, mask])?;
153 assert!(
154 masked.is::<ScalarFn>(),
155 "expected an un-optimized ScalarFn wrapper before optimization"
156 );
157
158 let optimized = masked.optimize()?;
159 assert!(
160 !optimized.is::<ScalarFn>(),
161 "constant mask should not fall through to execution, got {}",
162 optimized.encoding_id()
163 );
164 assert!(
165 optimized.is::<Primitive>(),
166 "constant mask should reduce into the Primitive input, got {}",
167 optimized.encoding_id()
168 );
169
170 let mut ctx = crate::array_session().create_execution_ctx();
171 let expected = if mask_value {
172 PrimitiveArray::from_option_iter([Some(1i32), Some(2), Some(3), Some(4), Some(5)])
173 } else {
174 PrimitiveArray::from_option_iter([None::<i32>, None, None, None, None])
175 };
176 assert_arrays_eq!(optimized, expected, &mut ctx);
177
178 Ok(())
179 }
180}