vortex_array/aggregate_fn/fns/all_non_nan/
mod.rs1use vortex_error::VortexResult;
5use vortex_session::VortexSession;
6use vortex_session::registry::CachedId;
7
8use crate::ArrayRef;
9use crate::Columnar;
10use crate::ExecutionCtx;
11use crate::aggregate_fn::AggregateArgs;
12use crate::aggregate_fn::AggregateFnId;
13use crate::aggregate_fn::AggregateFnVTable;
14use crate::aggregate_fn::EmptyOptions;
15use crate::aggregate_fn::fns::nan_count::columnar_nan_count;
16use crate::aggregate_fn::fns::nan_count::nan_count;
17use crate::dtype::DType;
18use crate::dtype::Nullability;
19use crate::scalar::Scalar;
20
21#[derive(Clone, Debug)]
32pub struct AllNonNan;
33
34impl AggregateFnVTable for AllNonNan {
35 type Options = EmptyOptions;
36 type Partial = bool;
37
38 fn id(&self) -> AggregateFnId {
39 static ID: CachedId = CachedId::new("vortex.all_non_nan");
40 *ID
41 }
42
43 fn serialize(&self, _options: &Self::Options) -> VortexResult<Option<Vec<u8>>> {
44 Ok(Some(vec![]))
45 }
46
47 fn deserialize(
48 &self,
49 _metadata: &[u8],
50 _session: &VortexSession,
51 ) -> VortexResult<Self::Options> {
52 Ok(EmptyOptions)
53 }
54
55 fn return_dtype(&self, _options: &Self::Options, input_dtype: &DType) -> Option<DType> {
56 matches!(input_dtype, DType::Primitive(ptype, _) if ptype.is_float())
57 .then_some(DType::Bool(Nullability::Nullable))
58 }
59
60 fn partial_dtype(&self, options: &Self::Options, input_dtype: &DType) -> Option<DType> {
61 self.return_dtype(options, input_dtype)
62 }
63
64 fn empty_partial(
65 &self,
66 _args: AggregateArgs<'_, Self::Options>,
67 ) -> VortexResult<Self::Partial> {
68 Ok(true)
69 }
70
71 fn partial_from_scalar(
72 &self,
73 _args: AggregateArgs<'_, Self::Options>,
74 scalar: &Scalar,
75 ) -> VortexResult<Self::Partial> {
76 bool::try_from(scalar)
77 }
78
79 fn merge_partials(
80 &self,
81 _args: AggregateArgs<'_, Self::Options>,
82 first: Self::Partial,
83 second: Self::Partial,
84 ) -> VortexResult<Self::Partial> {
85 Ok(first && second)
86 }
87
88 fn to_scalar(
89 &self,
90 _args: AggregateArgs<'_, Self::Options>,
91 partial: &Self::Partial,
92 ) -> VortexResult<Scalar> {
93 Ok(Scalar::bool(*partial, Nullability::Nullable))
94 }
95
96 fn is_saturated(
97 &self,
98 _args: AggregateArgs<'_, Self::Options>,
99 partial: &Self::Partial,
100 ) -> bool {
101 !*partial
102 }
103
104 fn try_accumulate(
105 &self,
106 _args: AggregateArgs<'_, Self::Options>,
107 state: &mut Self::Partial,
108 batch: &ArrayRef,
109 ctx: &mut ExecutionCtx,
110 ) -> VortexResult<bool> {
111 *state &= nan_count(batch, ctx)? == 0;
112 Ok(true)
113 }
114
115 fn accumulate(
116 &self,
117 _args: AggregateArgs<'_, Self::Options>,
118 partial: &mut Self::Partial,
119 batch: &Columnar,
120 ctx: &mut ExecutionCtx,
121 ) -> VortexResult<()> {
122 *partial &= columnar_nan_count(batch, ctx)? == 0;
125 Ok(())
126 }
127
128 fn finalize(
129 &self,
130 _args: AggregateArgs<'_, Self::Options>,
131 partials: ArrayRef,
132 ) -> VortexResult<ArrayRef> {
133 Ok(partials)
134 }
135
136 fn finalize_scalar(
137 &self,
138 args: AggregateArgs<'_, Self::Options>,
139 partial: &Self::Partial,
140 ) -> VortexResult<Scalar> {
141 self.to_scalar(args, partial)
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use vortex_error::VortexResult;
148
149 use crate::IntoArray;
150 use crate::VortexSessionExecute;
151 use crate::aggregate_fn::Accumulator;
152 use crate::aggregate_fn::DynAccumulator;
153 use crate::aggregate_fn::EmptyOptions;
154 use crate::aggregate_fn::fns::all_non_nan::AllNonNan;
155 use crate::array_session;
156 use crate::arrays::PrimitiveArray;
157 use crate::dtype::DType;
158 use crate::dtype::Nullability;
159 use crate::dtype::PType;
160
161 #[test]
162 fn all_non_nan_aggregate_fn() -> VortexResult<()> {
163 let mut ctx = array_session().create_execution_ctx();
164 let dtype = DType::Primitive(PType::F32, Nullability::Nullable);
165 let mut acc = Accumulator::try_new(AllNonNan, EmptyOptions, dtype)?;
166
167 let batch = PrimitiveArray::from_option_iter([Some(1.0f32), None, Some(3.0)]).into_array();
168 acc.accumulate(&batch, &mut ctx)?;
169
170 assert!(bool::try_from(&acc.finish()?)?);
171 Ok(())
172 }
173
174 #[test]
175 fn all_non_nan_false_with_nan() -> VortexResult<()> {
176 let mut ctx = array_session().create_execution_ctx();
177 let dtype = DType::Primitive(PType::F32, Nullability::Nullable);
178 let mut acc = Accumulator::try_new(AllNonNan, EmptyOptions, dtype)?;
179
180 let batch = PrimitiveArray::from_option_iter([Some(1.0f32), Some(f32::NAN)]).into_array();
181 acc.accumulate(&batch, &mut ctx)?;
182
183 assert!(!bool::try_from(&acc.finish()?)?);
184 Ok(())
185 }
186
187 #[test]
188 fn all_non_nan_unsupported_for_non_float() -> VortexResult<()> {
189 let dtype = DType::Primitive(PType::I32, Nullability::Nullable);
190 assert!(Accumulator::try_new(AllNonNan, EmptyOptions, dtype).is_err());
191 Ok(())
192 }
193
194 #[test]
195 fn all_non_nan_true_for_empty_float() -> VortexResult<()> {
196 let dtype = DType::Primitive(PType::F32, Nullability::Nullable);
197 let mut acc = Accumulator::try_new(AllNonNan, EmptyOptions, dtype)?;
198
199 assert!(bool::try_from(&acc.finish()?)?);
200 Ok(())
201 }
202}