@@ -13,39 +13,106 @@ use crate::register_kernel;
1313
1414impl MinMaxKernel for BoolVTable {
1515 fn min_max ( & self , array : & BoolArray ) -> VortexResult < Option < MinMaxResult > > {
16- let x = match array. validity_mask ( ) {
16+ let mask = array. validity_mask ( ) ;
17+ let true_non_null = match mask {
1718 Mask :: AllTrue ( _) => array. bit_buffer ( ) . clone ( ) ,
1819 Mask :: AllFalse ( _) => return Ok ( None ) ,
19- Mask :: Values ( v) => array. bit_buffer ( ) . bitand ( v. bit_buffer ( ) ) ,
20+ Mask :: Values ( ref v) => array. bit_buffer ( ) . bitand ( v. bit_buffer ( ) ) ,
2021 } ;
2122
2223 // TODO(ngates): we should be able to bail out earlier as soon as we have one true and
2324 // one false value.
24- let mut slices = x . set_slices ( ) ;
25+ let mut true_slices = true_non_null . set_slices ( ) ;
2526 // If there are no slices, then all values are false
2627 // if there is a single slice that covers the entire array, then all values are true
2728 // otherwise, we have a mix of true and false values
2829
29- let Some ( slice) = slices . next ( ) else {
30+ let Some ( slice) = true_slices . next ( ) else {
3031 // all false
3132 return Ok ( Some ( MinMaxResult {
32- min : Scalar :: new ( array. dtype ( ) . clone ( ) , false . into ( ) ) ,
33- max : Scalar :: new ( array. dtype ( ) . clone ( ) , false . into ( ) ) ,
33+ min : Scalar :: bool ( false , array. dtype ( ) . nullability ( ) ) ,
34+ max : Scalar :: bool ( false , array. dtype ( ) . nullability ( ) ) ,
3435 } ) ) ;
3536 } ;
36- if slice. 0 == 0 && slice. 1 == x . len ( ) {
37+ if slice. 0 == 0 && slice. 1 == array . len ( ) {
3738 // all true
3839 return Ok ( Some ( MinMaxResult {
39- min : Scalar :: new ( array. dtype ( ) . clone ( ) , true . into ( ) ) ,
40- max : Scalar :: new ( array. dtype ( ) . clone ( ) , true . into ( ) ) ,
40+ min : Scalar :: bool ( true , array. dtype ( ) . nullability ( ) ) ,
41+ max : Scalar :: bool ( true , array. dtype ( ) . nullability ( ) ) ,
4142 } ) ) ;
4243 } ;
4344
45+ // If the non null true slice doesn't cover the whole array we need to check for valid false values
46+ match mask {
47+ // if the mask is all true or all false we don't need to look for false values
48+ Mask :: AllTrue ( _) | Mask :: AllFalse ( _) => { }
49+ Mask :: Values ( v) => {
50+ let false_non_null = ( !array. bit_buffer ( ) ) . bitand ( v. bit_buffer ( ) ) ;
51+ let mut false_slices = false_non_null. set_slices ( ) ;
52+
53+ let Some ( _) = false_slices. next ( ) else {
54+ // In this case we don't have any false values which means we are all true and null
55+ return Ok ( Some ( MinMaxResult {
56+ min : Scalar :: bool ( true , array. dtype ( ) . nullability ( ) ) ,
57+ max : Scalar :: bool ( true , array. dtype ( ) . nullability ( ) ) ,
58+ } ) ) ;
59+ } ;
60+ }
61+ }
62+
4463 Ok ( Some ( MinMaxResult {
45- min : Scalar :: new ( array. dtype ( ) . clone ( ) , false . into ( ) ) ,
46- max : Scalar :: new ( array. dtype ( ) . clone ( ) , true . into ( ) ) ,
64+ min : Scalar :: bool ( false , array. dtype ( ) . nullability ( ) ) ,
65+ max : Scalar :: bool ( true , array. dtype ( ) . nullability ( ) ) ,
4766 } ) )
4867 }
4968}
5069
5170register_kernel ! ( MinMaxKernelAdapter ( BoolVTable ) . lift( ) ) ;
71+
72+ #[ cfg( test) ]
73+ mod tests {
74+ use vortex_dtype:: { DType , Nullability } ;
75+ use vortex_scalar:: Scalar ;
76+
77+ use crate :: arrays:: BoolArray ;
78+ use crate :: compute:: { MinMaxResult , min_max} ;
79+
80+ #[ test]
81+ fn test_min_max_nulls ( ) {
82+ let dtype = DType :: Bool ( Nullability :: Nullable ) ;
83+ assert_eq ! (
84+ min_max( BoolArray :: from_iter( vec![ Some ( true ) , Some ( true ) , None , None ] ) . as_ref( ) )
85+ . unwrap( ) ,
86+ Some ( MinMaxResult {
87+ min: Scalar :: new( dtype. clone( ) , true . into( ) ) ,
88+ max: Scalar :: new( dtype. clone( ) , true . into( ) ) ,
89+ } )
90+ ) ;
91+
92+ assert_eq ! (
93+ min_max( BoolArray :: from_iter( vec![ None , Some ( true ) , Some ( true ) ] ) . as_ref( ) ) . unwrap( ) ,
94+ Some ( MinMaxResult {
95+ min: Scalar :: new( dtype. clone( ) , true . into( ) ) ,
96+ max: Scalar :: new( dtype. clone( ) , true . into( ) ) ,
97+ } )
98+ ) ;
99+
100+ assert_eq ! (
101+ min_max( BoolArray :: from_iter( vec![ None , Some ( true ) , Some ( true ) , None ] ) . as_ref( ) )
102+ . unwrap( ) ,
103+ Some ( MinMaxResult {
104+ min: Scalar :: new( dtype. clone( ) , true . into( ) ) ,
105+ max: Scalar :: new( dtype. clone( ) , true . into( ) ) ,
106+ } )
107+ ) ;
108+
109+ assert_eq ! (
110+ min_max( BoolArray :: from_iter( vec![ Some ( false ) , Some ( false ) , None , None ] ) . as_ref( ) )
111+ . unwrap( ) ,
112+ Some ( MinMaxResult {
113+ min: Scalar :: new( dtype. clone( ) , false . into( ) ) ,
114+ max: Scalar :: new( dtype, false . into( ) ) ,
115+ } )
116+ ) ;
117+ }
118+ }
0 commit comments