vortex_roaring/boolean/
stats.rs

1use 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        // Only needs to compute IsSorted, IsStrictSorted and RunCount all other stats have been populated on construction
10        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}