11mod compare;
22
3+ use std:: fmt:: Debug ;
4+
5+ use vortex_array:: arrays:: ConstantArray ;
36use vortex_array:: compute:: {
4- filter, scalar_at, slice, take, CompareFn , FilterFn , ScalarAtFn , SliceFn , TakeFn ,
7+ between, filter, scalar_at, slice, take, BetweenFn , BetweenOptions , CompareFn , FilterFn ,
8+ ScalarAtFn , SliceFn , StrictComparison , TakeFn ,
59} ;
610use vortex_array:: variants:: PrimitiveArrayTrait ;
711use vortex_array:: vtable:: ComputeVTable ;
812use vortex_array:: { Array , IntoArray } ;
13+ use vortex_dtype:: NativePType ;
914use vortex_error:: VortexResult ;
1015use vortex_mask:: Mask ;
11- use vortex_scalar:: Scalar ;
16+ use vortex_scalar:: { Scalar , ScalarType } ;
1217
1318use crate :: { match_each_alp_float_ptype, ALPArray , ALPEncoding , ALPFloat } ;
1419
@@ -17,6 +22,10 @@ impl ComputeVTable for ALPEncoding {
1722 Some ( self )
1823 }
1924
25+ fn between_fn ( & self ) -> Option < & dyn BetweenFn < Array > > {
26+ Some ( self )
27+ }
28+
2029 fn filter_fn ( & self ) -> Option < & dyn FilterFn < Array > > {
2130 Some ( self )
2231 }
@@ -107,3 +116,156 @@ impl FilterFn<ALPArray> for ALPEncoding {
107116 )
108117 }
109118}
119+
120+ impl BetweenFn < ALPArray > for ALPEncoding {
121+ fn between (
122+ & self ,
123+ array : & ALPArray ,
124+ lower : & Array ,
125+ upper : & Array ,
126+ options : & BetweenOptions ,
127+ ) -> VortexResult < Option < Array > > {
128+ let ( Some ( lower) , Some ( upper) ) = ( lower. as_constant ( ) , upper. as_constant ( ) ) else {
129+ return Ok ( None ) ;
130+ } ;
131+
132+ if array. patches ( ) . is_some ( ) {
133+ return Ok ( None ) ;
134+ }
135+
136+ match_each_alp_float_ptype ! ( array. ptype( ) , |$F | {
137+ between_impl:: <$F >( array, $F :: try_from( lower) ?, $F :: try_from( upper) ?, options)
138+ } )
139+ . map ( Some )
140+ }
141+ }
142+
143+ fn between_impl < T : NativePType + ALPFloat > (
144+ array : & ALPArray ,
145+ lower : T ,
146+ upper : T ,
147+ options : & BetweenOptions ,
148+ ) -> VortexResult < Array >
149+ where
150+ Scalar : From < T :: ALPInt > ,
151+ <T as ALPFloat >:: ALPInt : ScalarType + Debug ,
152+ {
153+ let exponents = array. exponents ( ) ;
154+
155+ // There are always compared
156+ // the below bound is `value {< | <=} x`, either value encodes into the ALPInt domain
157+ // in which case we can leave the comparison unchanged `enc(value) {< | <=} x` or it doesn't
158+ // and we encode into value below enc_below(value) < value < x, in which case the comparison
159+ // becomes enc(value) < x. See `alp_scalar_compare` for more details.
160+ // note that if the value doesn't encode than value != x, so must use strict comparison.
161+ let ( lower_enc, lower_strict) = T :: encode_single ( lower, exponents)
162+ . map ( |x| ( x, options. lower_strict ) )
163+ . unwrap_or_else ( || ( T :: encode_below ( lower, exponents) , StrictComparison :: Strict ) ) ;
164+
165+ // the upper value `x { < | <= } value` similarly encodes or `x < value < enc_above(value())`
166+ let ( upper_enc, upper_strict) = T :: encode_single ( upper, exponents)
167+ . map ( |x| ( x, options. upper_strict ) )
168+ . unwrap_or_else ( || ( T :: encode_above ( upper, exponents) , StrictComparison :: Strict ) ) ;
169+
170+ let options = BetweenOptions {
171+ lower_strict,
172+ upper_strict,
173+ } ;
174+
175+ between (
176+ array. encoded ( ) ,
177+ ConstantArray :: new ( lower_enc, array. len ( ) ) ,
178+ ConstantArray :: new ( upper_enc, array. len ( ) ) ,
179+ & options,
180+ )
181+ }
182+
183+ #[ cfg( test) ]
184+ mod tests {
185+ use itertools:: Itertools ;
186+ use vortex_array:: arrays:: PrimitiveArray ;
187+ use vortex_array:: compute:: { BetweenOptions , StrictComparison } ;
188+ use vortex_array:: IntoArrayVariant ;
189+
190+ use crate :: alp:: compute:: between_impl;
191+ use crate :: ALPArray ;
192+
193+ fn between_test ( arr : & ALPArray , lower : f32 , upper : f32 , options : & BetweenOptions ) -> bool {
194+ let res = between_impl ( arr, lower, upper, options)
195+ . unwrap ( )
196+ . into_bool ( )
197+ . unwrap ( )
198+ . boolean_buffer ( )
199+ . iter ( )
200+ . collect_vec ( ) ;
201+ assert_eq ! ( res. len( ) , 1 ) ;
202+
203+ res[ 0 ]
204+ }
205+
206+ #[ test]
207+ fn comparison_range ( ) {
208+ let value = 0.0605_f32 ;
209+ let array = PrimitiveArray :: from_iter ( [ value; 1 ] ) ;
210+ let encoded = crate :: alp:: compress:: alp_encode ( & array) . unwrap ( ) ;
211+ assert ! ( encoded. patches( ) . is_none( ) ) ;
212+ assert_eq ! (
213+ encoded
214+ . encoded( )
215+ . into_primitive( )
216+ . unwrap( )
217+ . as_slice:: <i32 >( ) ,
218+ vec![ 605 ; 1 ]
219+ ) ;
220+
221+ assert ! ( between_test(
222+ & encoded,
223+ 0.0605_f32 ,
224+ 0.0605 ,
225+ & BetweenOptions {
226+ lower_strict: StrictComparison :: NonStrict ,
227+ upper_strict: StrictComparison :: NonStrict ,
228+ } ,
229+ ) ) ;
230+
231+ assert ! ( !between_test(
232+ & encoded,
233+ 0.0605_f32 ,
234+ 0.0605 ,
235+ & BetweenOptions {
236+ lower_strict: StrictComparison :: Strict ,
237+ upper_strict: StrictComparison :: NonStrict ,
238+ } ,
239+ ) ) ;
240+
241+ assert ! ( !between_test(
242+ & encoded,
243+ 0.0605_f32 ,
244+ 0.0605 ,
245+ & BetweenOptions {
246+ lower_strict: StrictComparison :: NonStrict ,
247+ upper_strict: StrictComparison :: Strict ,
248+ } ,
249+ ) ) ;
250+
251+ assert ! ( between_test(
252+ & encoded,
253+ 0.060499_f32 ,
254+ 0.06051 ,
255+ & BetweenOptions {
256+ lower_strict: StrictComparison :: NonStrict ,
257+ upper_strict: StrictComparison :: NonStrict ,
258+ } ,
259+ ) ) ;
260+
261+ assert ! ( between_test(
262+ & encoded,
263+ 0.06_f32 ,
264+ 0.06051 ,
265+ & BetweenOptions {
266+ lower_strict: StrictComparison :: NonStrict ,
267+ upper_strict: StrictComparison :: Strict ,
268+ } ,
269+ ) )
270+ }
271+ }
0 commit comments