vortex_sequence/
operator.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::ops::Mul;
5
6use num_traits::One;
7use vortex_array::ArrayRef;
8use vortex_array::execution::{BatchKernel, BatchKernelRef, BindCtx, MaskExecution};
9use vortex_array::vtable::OperatorVTable;
10use vortex_dtype::{NativePType, match_each_native_ptype};
11use vortex_error::{VortexExpect, VortexResult};
12use vortex_mask::AllOr;
13use vortex_vector::primitive::PVectorMut;
14use vortex_vector::{Vector, VectorMutOps};
15
16use crate::{SequenceArray, SequenceVTable};
17
18impl OperatorVTable<SequenceVTable> for SequenceVTable {
19    fn bind(
20        array: &SequenceArray,
21        selection: Option<&ArrayRef>,
22        ctx: &mut dyn BindCtx,
23    ) -> VortexResult<BatchKernelRef> {
24        let selection = ctx.bind_selection(array.len(), selection)?;
25
26        Ok(match_each_native_ptype!(array.ptype(), |T| {
27            if array.multiplier().cast::<T>() == <T as One>::one() {
28                Box::new(SequenceKernel::<T> {
29                    base: array.base().cast::<T>(),
30                    selection,
31                })
32            } else {
33                Box::new(MultiplierSequenceKernel::<T> {
34                    base: array.base().cast::<T>(),
35                    multiplier: array.multiplier().cast::<T>(),
36                    selection,
37                })
38            }
39        }))
40    }
41}
42
43struct SequenceKernel<T> {
44    base: T,
45    selection: MaskExecution,
46}
47
48impl<T: NativePType> BatchKernel for SequenceKernel<T> {
49    fn execute(self: Box<Self>) -> VortexResult<Vector> {
50        let selection = self.selection.execute()?;
51
52        let elements = match selection.indices() {
53            AllOr::All => PVectorMut::<T>::from_iter((0..selection.len()).map(|i| {
54                // This should never panic if the SequenceArray was constructed correctly
55                let offset = T::from_usize(i).vortex_expect("Overflow converting usize to ptype");
56                self.base + offset
57            })),
58            AllOr::None => PVectorMut::<T>::with_capacity(0),
59            AllOr::Some(indices) => {
60                PVectorMut::<T>::from_iter(indices.iter().map(|i| {
61                    // This should never panic if the SequenceArray was constructed correctly
62                    let offset =
63                        T::from_usize(*i).vortex_expect("Overflow converting usize to ptype");
64                    self.base + offset
65                }))
66            }
67        };
68
69        Ok(elements.freeze().into())
70    }
71}
72
73struct MultiplierSequenceKernel<T> {
74    base: T,
75    multiplier: T,
76    selection: MaskExecution,
77}
78
79impl<T: NativePType + Mul> BatchKernel for MultiplierSequenceKernel<T> {
80    fn execute(self: Box<Self>) -> VortexResult<Vector> {
81        let selection = self.selection.execute()?;
82
83        let elements = match selection.indices() {
84            AllOr::All => PVectorMut::<T>::from_iter((0..selection.len()).map(|i| {
85                // This should never panic if the SequenceArray was constructed correctly
86                let offset = T::from_usize(i).vortex_expect("Overflow converting usize to ptype");
87                let scaled = self.multiplier * offset;
88                self.base + scaled
89            })),
90            AllOr::None => PVectorMut::<T>::with_capacity(0),
91            AllOr::Some(indices) => PVectorMut::<T>::from_iter(indices.iter().map(|&i| {
92                // This should never panic if the SequenceArray was constructed correctly
93                let offset = T::from_usize(i).vortex_expect("Overflow converting usize to ptype");
94                let scaled = self.multiplier * offset;
95                self.base + scaled
96            })),
97        };
98
99        Ok(elements.freeze().into())
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use vortex_array::IntoArray;
106    use vortex_buffer::{bitbuffer, buffer};
107    use vortex_dtype::{Nullability, PTypeDowncast};
108    use vortex_vector::VectorOps;
109
110    use crate::SequenceArray;
111
112    #[test]
113    fn test_sequence_operator_unit_multiplier() {
114        // Test sequence with multiplier = 1: [2, 3, 4, 5]
115        let seq = SequenceArray::typed_new(2i32, 1, Nullability::NonNullable, 4)
116            .unwrap()
117            .into_array();
118
119        let result = seq.execute().unwrap().into_primitive().into_i32();
120
121        assert_eq!(
122            result.elements().as_slice(),
123            buffer![2i32, 3, 4, 5].as_slice()
124        );
125    }
126
127    #[test]
128    fn test_sequence_operator_with_multiplier() {
129        // Test sequence with multiplier = 3: [5, 8, 11, 14, 17]
130        let seq = SequenceArray::typed_new(5i64, 3, Nullability::NonNullable, 5)
131            .unwrap()
132            .into_array();
133
134        let result = seq.execute().unwrap().into_primitive().into_i64();
135
136        assert_eq!(
137            result.elements().as_slice(),
138            buffer![5i64, 8, 11, 14, 17].as_slice()
139        );
140    }
141
142    #[test]
143    fn test_sequence_operator_negative_multiplier() {
144        // Test sequence with negative multiplier: [10, 8, 6, 4]
145        let seq = SequenceArray::typed_new(10i16, -2, Nullability::NonNullable, 4)
146            .unwrap()
147            .into_array();
148
149        let result = seq.execute().unwrap().into_primitive().into_i16();
150
151        assert_eq!(
152            result.elements().as_slice(),
153            buffer![10i16, 8, 6, 4].as_slice()
154        );
155    }
156
157    #[test]
158    fn test_sequence_operator_single_element() {
159        // Test sequence with single element: [42]
160        let seq = SequenceArray::typed_new(42i32, 1, Nullability::NonNullable, 1)
161            .unwrap()
162            .into_array();
163
164        let result = seq.execute().unwrap().into_primitive().into_i32();
165
166        assert_eq!(result.elements().as_slice(), buffer![42i32].as_slice());
167    }
168
169    #[test]
170    fn test_sequence_operator_u64() {
171        // Test with unsigned type: [100, 110, 120, 130]
172        let seq = SequenceArray::typed_new(100u64, 10, Nullability::NonNullable, 4)
173            .unwrap()
174            .into_array();
175
176        let result = seq.execute().unwrap().into_primitive().into_u64();
177
178        assert_eq!(
179            result.elements().as_slice(),
180            buffer![100u64, 110, 120, 130].as_slice()
181        );
182    }
183
184    #[test]
185    fn test_sequence_operator_with_selection_alternating() {
186        // Test sequence [10, 11, 12, 13, 14] with selection [1 0 1 0 1] => [10, 12, 14]
187        let seq = SequenceArray::typed_new(10i32, 1, Nullability::NonNullable, 5)
188            .unwrap()
189            .into_array();
190
191        let selection = bitbuffer![1 0 1 0 1].into();
192        let result = seq
193            .execute_with_selection(&selection)
194            .unwrap()
195            .into_primitive()
196            .into_i32();
197
198        assert_eq!(
199            result.elements().as_slice(),
200            buffer![10i32, 12, 14].as_slice()
201        );
202    }
203
204    #[test]
205    fn test_sequence_operator_with_selection_beginning() {
206        // Test sequence [5, 8, 11, 14, 17] with selection [1 1 0 0 0] => [5, 8]
207        let seq = SequenceArray::typed_new(5i64, 3, Nullability::NonNullable, 5)
208            .unwrap()
209            .into_array();
210
211        let selection = bitbuffer![1 1 0 0 0].into();
212        let result = seq
213            .execute_with_selection(&selection)
214            .unwrap()
215            .into_primitive()
216            .into_i64();
217
218        assert_eq!(result.elements().as_slice(), buffer![5i64, 8].as_slice());
219    }
220
221    #[test]
222    fn test_sequence_operator_with_selection_end() {
223        // Test sequence [100, 110, 120, 130] with selection [0 0 1 1] => [120, 130]
224        let seq = SequenceArray::typed_new(100u64, 10, Nullability::NonNullable, 4)
225            .unwrap()
226            .into_array();
227
228        let selection = bitbuffer![0 0 1 1].into();
229        let result = seq
230            .execute_with_selection(&selection)
231            .unwrap()
232            .into_primitive()
233            .into_u64();
234
235        assert_eq!(
236            result.elements().as_slice(),
237            buffer![120u64, 130].as_slice()
238        );
239    }
240
241    #[test]
242    fn test_sequence_operator_with_selection_none() {
243        // Test sequence [2, 3, 4, 5] with selection [0 0 0 0] => []
244        let seq = SequenceArray::typed_new(2i32, 1, Nullability::NonNullable, 4)
245            .unwrap()
246            .into_array();
247
248        let selection = bitbuffer![0 0 0 0].into();
249        let result = seq.execute_with_selection(&selection).unwrap();
250        assert!(result.is_empty())
251    }
252
253    #[test]
254    fn test_sequence_operator_with_selection_all() {
255        // Test sequence [10, 8, 6, 4] with selection [1 1 1 1] => [10, 8, 6, 4]
256        let seq = SequenceArray::typed_new(10i16, -2, Nullability::NonNullable, 4)
257            .unwrap()
258            .into_array();
259
260        let selection = bitbuffer![1 1 1 1].into();
261        let result = seq
262            .execute_with_selection(&selection)
263            .unwrap()
264            .into_primitive()
265            .into_i16();
266
267        assert_eq!(
268            result.elements().as_slice(),
269            buffer![10i16, 8, 6, 4].as_slice()
270        );
271    }
272
273    #[test]
274    fn test_sequence_operator_with_multiplier_and_selection() {
275        // Test sequence [0, 5, 10, 15, 20, 25] with selection [1 0 0 1 0 1] => [0, 15, 25]
276        let seq = SequenceArray::typed_new(0i32, 5, Nullability::NonNullable, 6)
277            .unwrap()
278            .into_array();
279
280        let selection = bitbuffer![1 0 0 1 0 1].into();
281        let result = seq
282            .execute_with_selection(&selection)
283            .unwrap()
284            .into_primitive()
285            .into_i32();
286
287        assert_eq!(
288            result.elements().as_slice(),
289            buffer![0i32, 15, 25].as_slice()
290        );
291    }
292}