ruvector_attention/topology/
policy.rs1use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12pub enum AttentionMode {
13 Stable,
15 Cautious,
17 Freeze,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct PolicyConfig {
24 pub stable_threshold: f32,
26 pub freeze_threshold: f32,
28 pub cautious_width_factor: f32,
30 pub cautious_sparsity_factor: f32,
32 pub update_period: usize,
34 pub hysteresis: f32,
36}
37
38impl Default for PolicyConfig {
39 fn default() -> Self {
40 Self {
41 stable_threshold: 0.7,
42 freeze_threshold: 0.3,
43 cautious_width_factor: 0.5,
44 cautious_sparsity_factor: 2.0,
45 update_period: 4,
46 hysteresis: 0.05,
47 }
48 }
49}
50
51#[derive(Debug, Clone)]
53pub struct AttentionPolicy {
54 config: PolicyConfig,
55 current_mode: AttentionMode,
56 mode_history: Vec<AttentionMode>,
57}
58
59impl AttentionPolicy {
60 pub fn new(config: PolicyConfig) -> Self {
62 Self {
63 config,
64 current_mode: AttentionMode::Stable,
65 mode_history: Vec::new(),
66 }
67 }
68
69 pub fn determine_mode(&mut self, coherence: f32) -> AttentionMode {
71 let new_mode = self.compute_mode(coherence);
72
73 let mode = self.apply_hysteresis(new_mode, coherence);
75
76 self.mode_history.push(mode);
78 if self.mode_history.len() > 16 {
79 self.mode_history.remove(0);
80 }
81
82 self.current_mode = mode;
83 mode
84 }
85
86 fn compute_mode(&self, coherence: f32) -> AttentionMode {
88 if coherence >= self.config.stable_threshold {
89 AttentionMode::Stable
90 } else if coherence <= self.config.freeze_threshold {
91 AttentionMode::Freeze
92 } else {
93 AttentionMode::Cautious
94 }
95 }
96
97 fn apply_hysteresis(&self, new_mode: AttentionMode, coherence: f32) -> AttentionMode {
99 let h = self.config.hysteresis;
100
101 match (self.current_mode, new_mode) {
102 (AttentionMode::Stable, AttentionMode::Cautious) => {
104 if coherence < self.config.stable_threshold - h {
105 AttentionMode::Cautious
106 } else {
107 AttentionMode::Stable
108 }
109 }
110 (AttentionMode::Cautious, AttentionMode::Stable) => {
112 if coherence > self.config.stable_threshold + h {
113 AttentionMode::Stable
114 } else {
115 AttentionMode::Cautious
116 }
117 }
118 (AttentionMode::Cautious, AttentionMode::Freeze) => {
120 if coherence < self.config.freeze_threshold - h {
121 AttentionMode::Freeze
122 } else {
123 AttentionMode::Cautious
124 }
125 }
126 (AttentionMode::Freeze, AttentionMode::Cautious) => {
128 if coherence > self.config.freeze_threshold + h {
129 AttentionMode::Cautious
130 } else {
131 AttentionMode::Freeze
132 }
133 }
134 _ => new_mode,
136 }
137 }
138
139 pub fn current_mode(&self) -> AttentionMode {
141 self.current_mode
142 }
143
144 pub fn get_attention_width(&self, base_width: usize) -> usize {
146 match self.current_mode {
147 AttentionMode::Stable => base_width,
148 AttentionMode::Cautious => {
149 ((base_width as f32 * self.config.cautious_width_factor) as usize).max(1)
150 }
151 AttentionMode::Freeze => 0, }
153 }
154
155 pub fn get_sparsity_factor(&self) -> f32 {
157 match self.current_mode {
158 AttentionMode::Stable => 1.0,
159 AttentionMode::Cautious => self.config.cautious_sparsity_factor,
160 AttentionMode::Freeze => f32::INFINITY, }
162 }
163
164 pub fn allows_updates(&self) -> bool {
166 self.current_mode != AttentionMode::Freeze
167 }
168
169 pub fn allows_writes(&self) -> bool {
171 self.current_mode != AttentionMode::Freeze
172 }
173
174 pub fn mode_stability(&self) -> f32 {
176 if self.mode_history.is_empty() {
177 return 1.0;
178 }
179
180 let current = self.current_mode;
181 let matches = self.mode_history.iter().filter(|&&m| m == current).count();
182 matches as f32 / self.mode_history.len() as f32
183 }
184
185 pub fn reset(&mut self) {
187 self.current_mode = AttentionMode::Stable;
188 self.mode_history.clear();
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195
196 #[test]
197 fn test_policy_modes() {
198 let mut policy = AttentionPolicy::new(PolicyConfig::default());
199
200 assert_eq!(policy.determine_mode(0.9), AttentionMode::Stable);
202
203 assert_eq!(policy.determine_mode(0.5), AttentionMode::Cautious);
205
206 assert_eq!(policy.determine_mode(0.1), AttentionMode::Freeze);
208 }
209
210 #[test]
211 fn test_attention_width() {
212 let mut policy = AttentionPolicy::new(PolicyConfig::default());
213
214 policy.determine_mode(0.9);
215 assert_eq!(policy.get_attention_width(100), 100);
216
217 policy.determine_mode(0.5);
218 assert_eq!(policy.get_attention_width(100), 50);
219
220 policy.determine_mode(0.1);
221 assert_eq!(policy.get_attention_width(100), 0);
222 }
223
224 #[test]
225 fn test_hysteresis() {
226 let mut policy = AttentionPolicy::new(PolicyConfig {
227 stable_threshold: 0.7,
228 freeze_threshold: 0.3,
229 hysteresis: 0.1,
230 ..Default::default()
231 });
232
233 policy.determine_mode(0.8);
235 assert_eq!(policy.current_mode(), AttentionMode::Stable);
236
237 policy.determine_mode(0.65);
239 assert_eq!(policy.current_mode(), AttentionMode::Stable);
241
242 policy.determine_mode(0.55);
244 assert_eq!(policy.current_mode(), AttentionMode::Cautious);
245 }
246
247 #[test]
248 fn test_update_permissions() {
249 let mut policy = AttentionPolicy::new(PolicyConfig::default());
250
251 policy.determine_mode(0.8);
252 assert!(policy.allows_updates());
253 assert!(policy.allows_writes());
254
255 policy.determine_mode(0.1);
256 assert!(!policy.allows_updates());
257 assert!(!policy.allows_writes());
258 }
259}