ruvector_temporal_tensor/
tier_policy.rs1#[derive(Clone, Copy, Debug)]
12pub struct TierPolicy {
13 pub hot_min_score: u32,
14 pub warm_min_score: u32,
15 pub warm_bits: u8,
16 pub drift_pct_q8: u32,
18 pub group_len: u32,
19}
20
21impl Default for TierPolicy {
22 fn default() -> Self {
23 Self {
24 hot_min_score: 512,
25 warm_min_score: 64,
26 warm_bits: 7,
27 drift_pct_q8: 26,
28 group_len: 64,
29 }
30 }
31}
32
33impl TierPolicy {
34 pub fn select_bits(&self, access_count: u32, last_access_ts: u32, now_ts: u32) -> u8 {
36 let age = now_ts.wrapping_sub(last_access_ts).wrapping_add(1);
37 let score = access_count.saturating_mul(1024).wrapping_div(age);
38
39 if score >= self.hot_min_score {
40 8
41 } else if score >= self.warm_min_score {
42 self.warm_bits
43 } else {
44 3
45 }
46 }
47
48 pub fn drift_factor(&self) -> f32 {
50 1.0 + (self.drift_pct_q8 as f32) / 256.0
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn test_default_policy() {
60 let p = TierPolicy::default();
61 assert_eq!(p.hot_min_score, 512);
62 assert_eq!(p.warm_min_score, 64);
63 assert_eq!(p.warm_bits, 7);
64 assert_eq!(p.drift_pct_q8, 26);
65 assert_eq!(p.group_len, 64);
66 }
67
68 #[test]
69 fn test_tier_selection_hot() {
70 let p = TierPolicy::default();
71 assert_eq!(p.select_bits(100, 0, 9), 8);
73 }
74
75 #[test]
76 fn test_tier_selection_warm() {
77 let p = TierPolicy::default();
78 assert_eq!(p.select_bits(10, 0, 99), 7);
80 }
81
82 #[test]
83 fn test_tier_selection_cold() {
84 let p = TierPolicy::default();
85 assert_eq!(p.select_bits(1, 0, 999), 3);
87 }
88
89 #[test]
90 fn test_drift_factor() {
91 let p = TierPolicy::default();
92 let df = p.drift_factor();
93 assert!((df - 1.1015625).abs() < 1e-6);
94 }
95
96 #[test]
97 fn test_warm_bits_5() {
98 let p = TierPolicy {
99 warm_bits: 5,
100 ..Default::default()
101 };
102 assert_eq!(p.select_bits(10, 0, 99), 5);
103 }
104}