vortex_roaring/boolean/
stats.rs1use vortex_array::stats::{Stat, StatisticsVTable, StatsSet};
2use vortex_array::ArrayLen;
3use vortex_error::{vortex_err, VortexResult};
4
5use crate::{RoaringBoolArray, RoaringBoolEncoding};
6
7impl StatisticsVTable<RoaringBoolArray> for RoaringBoolEncoding {
8 fn compute_statistics(&self, array: &RoaringBoolArray, stat: Stat) -> VortexResult<StatsSet> {
9 let bitmap = array.bitmap();
11 let true_count = bitmap.statistics().cardinality;
12 if matches!(
13 stat,
14 Stat::TrueCount | Stat::Min | Stat::Max | Stat::IsConstant
15 ) {
16 return Ok(StatsSet::bools_with_true_and_null_count(
17 true_count as usize,
18 0,
19 array.len(),
20 ));
21 }
22
23 if matches!(stat, Stat::IsSorted | Stat::IsStrictSorted) {
24 let is_sorted = if true_count == 0 || true_count == array.len() as u64 {
25 true
26 } else {
27 let min_idx = bitmap.minimum().ok_or_else(|| {
28 vortex_err!("Bitmap has no minimum despite having cardinality > 0")
29 })?;
30 let max_idx = bitmap.maximum().ok_or_else(|| {
31 vortex_err!("Bitmap has no maximum despite having cardinality > 0")
32 })?;
33 (max_idx as usize + 1 == array.len())
34 && (max_idx + 1 - min_idx) as u64 == true_count
35 };
36
37 let is_strict_sorted =
38 is_sorted && (array.len() <= 1 || (array.len() == 2 && true_count == 1));
39 return Ok(StatsSet::new_unchecked(vec![
40 (Stat::IsSorted, is_sorted.into()),
41 (Stat::IsStrictSorted, is_strict_sorted.into()),
42 ]));
43 }
44
45 Ok(StatsSet::default())
46 }
47}
48
49#[cfg(test)]
50mod test {
51 use vortex_array::array::BoolArray;
52 use vortex_array::stats::ArrayStatistics;
53 use vortex_array::IntoArrayData;
54
55 use crate::RoaringBoolArray;
56
57 #[test]
58 #[cfg_attr(miri, ignore)]
59 fn bool_stats() {
60 let bool_arr = RoaringBoolArray::encode(
61 BoolArray::from_iter([false, false, true, true, false, true, true, false]).into_array(),
62 )
63 .unwrap();
64 assert!(!bool_arr.statistics().compute_is_strict_sorted().unwrap());
65 assert!(!bool_arr.statistics().compute_is_sorted().unwrap());
66 assert!(!bool_arr.statistics().compute_is_constant().unwrap());
67 assert!(!bool_arr.statistics().compute_min::<bool>().unwrap());
68 assert!(bool_arr.statistics().compute_max::<bool>().unwrap());
69 assert_eq!(bool_arr.statistics().compute_true_count().unwrap(), 4);
70 }
71
72 #[test]
73 #[cfg_attr(miri, ignore)]
74 fn strict_sorted() {
75 let bool_arr_1 =
76 RoaringBoolArray::encode(BoolArray::from_iter([false, true]).into_array()).unwrap();
77 assert!(bool_arr_1.statistics().compute_is_strict_sorted().unwrap());
78 assert!(bool_arr_1.statistics().compute_is_sorted().unwrap());
79
80 let bool_arr_2 =
81 RoaringBoolArray::encode(BoolArray::from_iter([true]).into_array()).unwrap();
82 assert!(bool_arr_2.statistics().compute_is_strict_sorted().unwrap());
83 assert!(bool_arr_2.statistics().compute_is_sorted().unwrap());
84
85 let bool_arr_3 =
86 RoaringBoolArray::encode(BoolArray::from_iter([false]).into_array()).unwrap();
87 assert!(bool_arr_3.statistics().compute_is_strict_sorted().unwrap());
88 assert!(bool_arr_3.statistics().compute_is_sorted().unwrap());
89
90 let bool_arr_4 =
91 RoaringBoolArray::encode(BoolArray::from_iter([true, false]).into_array()).unwrap();
92 assert!(!bool_arr_4.statistics().compute_is_strict_sorted().unwrap());
93 assert!(!bool_arr_4.statistics().compute_is_sorted().unwrap());
94
95 let bool_arr_5 =
96 RoaringBoolArray::encode(BoolArray::from_iter([false, true, true]).into_array())
97 .unwrap();
98 assert!(!bool_arr_5.statistics().compute_is_strict_sorted().unwrap());
99 assert!(bool_arr_5.statistics().compute_is_sorted().unwrap());
100 }
101}