nodedb_vector/navix/
selectivity.rs1use roaring::RoaringBitmap;
11
12pub fn local_selectivity_at(node_neighbors: &[u32], allowed: &RoaringBitmap) -> f32 {
17 if node_neighbors.is_empty() {
18 return 0.0;
19 }
20 let matched = node_neighbors
21 .iter()
22 .filter(|&&n| allowed.contains(n))
23 .count();
24 matched as f32 / node_neighbors.len() as f32
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29#[non_exhaustive]
30pub enum NavixHeuristic {
31 Standard,
34 Directed,
38 Blind,
42}
43
44pub fn pick_heuristic(local_selectivity: f32) -> NavixHeuristic {
46 if local_selectivity > 0.50 {
47 NavixHeuristic::Standard
48 } else if local_selectivity >= 0.01 {
49 NavixHeuristic::Directed
50 } else {
51 NavixHeuristic::Blind
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[test]
62 fn heuristic_zero() {
63 assert_eq!(pick_heuristic(0.0), NavixHeuristic::Blind);
64 }
65
66 #[test]
67 fn heuristic_below_directed_threshold() {
68 assert_eq!(pick_heuristic(0.005), NavixHeuristic::Blind);
69 }
70
71 #[test]
72 fn heuristic_at_directed_lower_boundary() {
73 assert_eq!(pick_heuristic(0.01), NavixHeuristic::Directed);
75 }
76
77 #[test]
78 fn heuristic_mid_directed() {
79 assert_eq!(pick_heuristic(0.30), NavixHeuristic::Directed);
80 }
81
82 #[test]
83 fn heuristic_at_standard_lower_boundary() {
84 assert_eq!(pick_heuristic(0.50), NavixHeuristic::Directed);
86 }
87
88 #[test]
89 fn heuristic_just_above_standard_boundary() {
90 assert_eq!(pick_heuristic(0.51), NavixHeuristic::Standard);
91 }
92
93 #[test]
94 fn heuristic_full_selectivity() {
95 assert_eq!(pick_heuristic(1.0), NavixHeuristic::Standard);
96 }
97
98 #[test]
101 fn empty_neighbors_returns_zero() {
102 let allowed = RoaringBitmap::new();
103 assert_eq!(local_selectivity_at(&[], &allowed), 0.0);
104 }
105
106 #[test]
107 fn all_matching_returns_one() {
108 let mut allowed = RoaringBitmap::new();
109 allowed.insert(0);
110 allowed.insert(1);
111 allowed.insert(2);
112 let neighbors = [0u32, 1, 2];
113 assert!((local_selectivity_at(&neighbors, &allowed) - 1.0).abs() < 1e-6);
114 }
115
116 #[test]
117 fn half_matching_returns_half() {
118 let mut allowed = RoaringBitmap::new();
119 allowed.insert(0);
120 allowed.insert(2);
121 let neighbors = [0u32, 1, 2, 3];
122 assert!((local_selectivity_at(&neighbors, &allowed) - 0.5).abs() < 1e-6);
123 }
124
125 #[test]
126 fn none_matching_returns_zero() {
127 let allowed = RoaringBitmap::new();
128 let neighbors = [0u32, 1, 2, 3];
129 assert_eq!(local_selectivity_at(&neighbors, &allowed), 0.0);
130 }
131}