ruvector_nervous_system/routing/mod.rs
1//! Neural routing mechanisms for the nervous system
2//!
3//! This module implements three complementary routing strategies inspired by
4//! computational neuroscience:
5//!
6//! 1. **Predictive Coding** (`predictive`) - Bandwidth reduction through residual transmission
7//! 2. **Communication Through Coherence** (`coherence`) - Phase-locked oscillatory routing
8//! 3. **Global Workspace** (`workspace`) - Limited-capacity broadcast with competition
9//!
10//! # Architecture
11//!
12//! ```text
13//! ┌─────────────────────────────────────────────────────────┐
14//! │ CoherenceGatedSystem │
15//! ├─────────────────────────────────────────────────────────┤
16//! │ │
17//! │ ┌──────────────────┐ ┌──────────────────┐ │
18//! │ │ Predictive │ │ Oscillatory │ │
19//! │ │ Layers │─────▶│ Router │ │
20//! │ │ │ │ (Kuramoto) │ │
21//! │ └──────────────────┘ └──────────────────┘ │
22//! │ │ │ │
23//! │ │ ▼ │
24//! │ │ ┌──────────────────┐ │
25//! │ └─────────────────▶│ Global │ │
26//! │ │ Workspace │ │
27//! │ └──────────────────┘ │
28//! └─────────────────────────────────────────────────────────┘
29//! ```
30//!
31//! # Performance Characteristics
32//!
33//! - **Predictive coding**: 90-99% bandwidth reduction on stable signals
34//! - **Oscillator step**: <1μs per module (tested up to 100 modules)
35//! - **Communication gain**: <100ns per pair computation
36//! - **Workspace capacity**: 4-7 items (Miller's Law)
37//!
38//! # Examples
39//!
40//! ## Basic Coherence Routing
41//!
42//! ```rust
43//! use ruvector_nervous_system::routing::{OscillatoryRouter, Representation, GlobalWorkspace};
44//!
45//! // Create 40Hz gamma-band router
46//! let mut router = OscillatoryRouter::new(5, 40.0);
47//!
48//! // Advance oscillator dynamics
49//! for _ in 0..1000 {
50//! router.step(0.001); // 1ms time steps
51//! }
52//!
53//! // Route message based on phase coherence
54//! let message = vec![1.0, 2.0, 3.0];
55//! let receivers = vec![1, 2, 3];
56//! let routed = router.route(&message, 0, &receivers);
57//! ```
58//!
59//! ## Predictive Bandwidth Reduction
60//!
61//! ```rust
62//! use ruvector_nervous_system::routing::PredictiveLayer;
63//!
64//! let mut layer = PredictiveLayer::new(128, 0.2);
65//!
66//! // Only transmits when prediction error exceeds 20%
67//! let signal = vec![0.5; 128];
68//! if let Some(residual) = layer.residual_gated_write(&signal) {
69//! // Transmit residual (surprise)
70//! println!("Transmitting residual");
71//! } else {
72//! // No transmission needed (predictable)
73//! println!("Signal predicted - no transmission");
74//! }
75//! ```
76//!
77//! ## Global Workspace Broadcast
78//!
79//! ```rust
80//! use ruvector_nervous_system::routing::{GlobalWorkspace, Representation};
81//!
82//! let mut workspace = GlobalWorkspace::new(7); // 7-item capacity
83//!
84//! // Compete for broadcast access
85//! let rep1 = Representation::new(vec![1.0], 0.8, 0u16, 0);
86//! let rep2 = Representation::new(vec![2.0], 0.3, 1u16, 0);
87//!
88//! workspace.broadcast(rep1); // High salience - accepted
89//! workspace.broadcast(rep2); // Low salience - may be rejected
90//!
91//! // Run competitive dynamics
92//! workspace.compete();
93//!
94//! // Retrieve winning representations
95//! let winners = workspace.retrieve_top_k(3);
96//! ```
97
98pub mod circadian;
99pub mod coherence;
100pub mod predictive;
101pub mod workspace;
102
103pub use circadian::{
104 BudgetGuardrail, CircadianController, CircadianPhase, CircadianScheduler, HysteresisTracker,
105 NervousSystemMetrics, NervousSystemScorecard, PhaseModulation, ScorecardTargets,
106};
107pub use coherence::OscillatoryRouter;
108pub use predictive::PredictiveLayer;
109pub use workspace::{GlobalWorkspace, Representation};
110
111/// Integrated coherence-gated system combining all routing mechanisms
112#[derive(Debug, Clone)]
113pub struct CoherenceGatedSystem {
114 /// Oscillatory router for phase-based communication
115 router: OscillatoryRouter,
116 /// Global workspace for broadcast
117 workspace: GlobalWorkspace,
118 /// Predictive layers for each module
119 predictive: Vec<PredictiveLayer>,
120}
121
122impl CoherenceGatedSystem {
123 /// Create a new coherence-gated system
124 ///
125 /// # Arguments
126 /// * `num_modules` - Number of communicating modules
127 /// * `vector_dim` - Dimension of vectors being transmitted
128 /// * `gamma_frequency` - Base oscillation frequency (Hz, typically 30-90)
129 /// * `workspace_capacity` - Global workspace capacity (typically 4-7)
130 pub fn new(
131 num_modules: usize,
132 vector_dim: usize,
133 gamma_frequency: f32,
134 workspace_capacity: usize,
135 ) -> Self {
136 Self {
137 router: OscillatoryRouter::new(num_modules, gamma_frequency),
138 workspace: GlobalWorkspace::new(workspace_capacity),
139 predictive: (0..num_modules)
140 .map(|_| PredictiveLayer::new(vector_dim, 0.2))
141 .collect(),
142 }
143 }
144
145 /// Step oscillator dynamics forward in time
146 pub fn step_oscillators(&mut self, dt: f32) {
147 self.router.step(dt);
148 }
149
150 /// Route message with coherence gating and predictive filtering
151 ///
152 /// # Process
153 /// 1. Compute predictive residual
154 /// 2. If residual significant, apply coherence-based routing
155 /// 3. Broadcast to workspace if salience high enough
156 ///
157 /// # Returns
158 /// Vector of (receiver_id, weighted_residual) for successful routes
159 pub fn route_with_coherence(
160 &mut self,
161 message: &[f32],
162 sender: usize,
163 receivers: &[usize],
164 dt: f32,
165 ) -> Vec<(usize, Vec<f32>)> {
166 // Step 1: Advance oscillator dynamics
167 self.step_oscillators(dt);
168
169 // Step 2: Predictive filtering
170 if sender >= self.predictive.len() {
171 return Vec::new();
172 }
173
174 let residual = match self.predictive[sender].residual_gated_write(message) {
175 Some(res) => res,
176 None => return Vec::new(), // Predictable - no transmission
177 };
178
179 // Step 3: Coherence-based routing
180 let routed = self.router.route(&residual, sender, receivers);
181
182 // Step 4: Attempt global workspace broadcast for high-coherence routes
183 for (receiver, weighted_msg) in &routed {
184 let gain = self.router.communication_gain(sender, *receiver);
185
186 if gain > 0.7 {
187 // High coherence - try to broadcast to workspace
188 let salience = gain;
189 let rep = Representation::new(
190 weighted_msg.clone(),
191 salience,
192 sender as u16,
193 0, // Timestamp managed by workspace
194 );
195 self.workspace.broadcast(rep);
196 }
197 }
198
199 routed
200 }
201
202 /// Get current oscillator phases
203 pub fn phases(&self) -> &[f32] {
204 self.router.phases()
205 }
206
207 /// Get workspace contents
208 pub fn workspace_contents(&self) -> Vec<Representation> {
209 self.workspace.retrieve()
210 }
211
212 /// Run workspace competition
213 pub fn compete_workspace(&mut self) {
214 self.workspace.compete();
215 }
216
217 /// Get synchronization level (order parameter)
218 pub fn synchronization(&self) -> f32 {
219 self.router.order_parameter()
220 }
221
222 /// Get workspace occupancy (0.0 to 1.0)
223 pub fn workspace_occupancy(&self) -> f32 {
224 self.workspace.len() as f32 / self.workspace.capacity() as f32
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231
232 #[test]
233 fn test_integrated_system() {
234 let mut system = CoherenceGatedSystem::new(
235 5, // 5 modules
236 128, // 128-dim vectors
237 40.0, // 40Hz gamma
238 7, // 7-item workspace
239 );
240
241 assert_eq!(system.phases().len(), 5);
242 assert_eq!(system.workspace_contents().len(), 0);
243 }
244
245 #[test]
246 fn test_route_with_coherence() {
247 let mut system = CoherenceGatedSystem::new(3, 16, 40.0, 5);
248
249 // Synchronize oscillators first
250 for _ in 0..1000 {
251 system.step_oscillators(0.001);
252 }
253
254 let message = vec![1.0; 16];
255 let receivers = vec![1, 2];
256
257 // Should transmit first time (no prediction yet)
258 let routed = system.route_with_coherence(&message, 0, &receivers, 0.001);
259 assert!(!routed.is_empty());
260 }
261
262 #[test]
263 fn test_predictive_suppression() {
264 let mut system = CoherenceGatedSystem::new(2, 16, 40.0, 5);
265
266 let stable_message = vec![1.0; 16];
267 let receivers = vec![1];
268
269 // First transmission should go through
270 let first = system.route_with_coherence(&stable_message, 0, &receivers, 0.001);
271 assert!(!first.is_empty());
272
273 // After learning, stable message should be suppressed
274 for _ in 0..50 {
275 system.route_with_coherence(&stable_message, 0, &receivers, 0.001);
276 }
277
278 // Should eventually suppress (prediction learned)
279 let mut suppressed_count = 0;
280 for _ in 0..20 {
281 let result = system.route_with_coherence(&stable_message, 0, &receivers, 0.001);
282 if result.is_empty() {
283 suppressed_count += 1;
284 }
285 }
286
287 assert!(suppressed_count > 10, "Should suppress predictable signals");
288 }
289
290 #[test]
291 fn test_workspace_integration() {
292 let mut system = CoherenceGatedSystem::new(3, 8, 40.0, 3);
293
294 // Synchronize for high coherence
295 for _ in 0..2000 {
296 system.step_oscillators(0.001);
297 }
298
299 let message = vec![1.0; 8];
300 let receivers = vec![1, 2];
301
302 // Route with high coherence
303 system.route_with_coherence(&message, 0, &receivers, 0.001);
304
305 // Workspace should receive broadcast
306 let workspace_items = system.workspace_contents();
307 assert!(!workspace_items.is_empty(), "Workspace should have items");
308 }
309
310 #[test]
311 fn test_synchronization_metric() {
312 let mut system = CoherenceGatedSystem::new(10, 16, 40.0, 7);
313
314 let initial_sync = system.synchronization();
315
316 // Run dynamics with oscillators
317 for _ in 0..5000 {
318 system.step_oscillators(0.001);
319 }
320
321 let final_sync = system.synchronization();
322
323 // Synchronization should be a valid metric in [0, 1] range
324 assert!(
325 final_sync >= 0.0 && final_sync <= 1.0,
326 "Synchronization should be in valid range: {}",
327 final_sync
328 );
329 // Verify the metric works correctly
330 assert!(
331 initial_sync >= 0.0 && initial_sync <= 1.0,
332 "Initial sync should be valid: {}",
333 initial_sync
334 );
335 }
336
337 #[test]
338 fn test_workspace_occupancy() {
339 let mut system = CoherenceGatedSystem::new(3, 8, 40.0, 4);
340
341 assert_eq!(system.workspace_occupancy(), 0.0);
342
343 // Fill workspace manually
344 for i in 0..3 {
345 let rep = Representation::new(vec![1.0; 8], 0.8, i as u16, 0);
346 system.workspace.broadcast(rep);
347 }
348
349 assert_eq!(system.workspace_occupancy(), 0.75); // 3/4
350 }
351
352 #[test]
353 fn test_workspace_competition() {
354 let mut system = CoherenceGatedSystem::new(2, 8, 40.0, 3);
355
356 // Add weak representation
357 let rep = Representation::new(vec![1.0; 8], 0.3, 0_u16, 0);
358 system.workspace.broadcast(rep);
359
360 system.compete_workspace();
361
362 // Salience should decay
363 let contents = system.workspace_contents();
364 if !contents.is_empty() {
365 assert!(contents[0].salience < 0.3, "Salience should decay");
366 }
367 }
368
369 #[test]
370 fn test_end_to_end_routing() {
371 let mut system = CoherenceGatedSystem::new(4, 32, 40.0, 5);
372
373 // Synchronize oscillators
374 for _ in 0..1000 {
375 system.step_oscillators(0.0001);
376 }
377
378 // Send varying signal
379 let mut routed_count = 0;
380 for i in 0..100 {
381 let signal_strength = (i as f32 * 0.1).sin();
382 let message: Vec<f32> = (0..32).map(|_| signal_strength).collect();
383 let receivers = vec![1, 2, 3];
384
385 let routed = system.route_with_coherence(&message, 0, &receivers, 0.0001);
386
387 // Count successful routes
388 if !routed.is_empty() {
389 routed_count += 1;
390 }
391 }
392
393 // Should have some successful routes (predictive coding may suppress some)
394 assert!(
395 routed_count > 0,
396 "Should have at least some successful routes, got {}",
397 routed_count
398 );
399
400 // Workspace should have accumulated some representations
401 system.compete_workspace();
402
403 // Expect valid workspace state
404 assert!(system.workspace_occupancy() <= 1.0);
405 }
406
407 #[test]
408 fn test_performance_integrated() {
409 let mut system = CoherenceGatedSystem::new(50, 128, 40.0, 7);
410
411 let message = vec![1.0; 128];
412 let receivers: Vec<usize> = (1..50).collect();
413
414 let start = std::time::Instant::now();
415
416 for _ in 0..100 {
417 system.route_with_coherence(&message, 0, &receivers, 0.001);
418 }
419
420 let elapsed = start.elapsed();
421 let avg_route = elapsed.as_micros() / 100;
422
423 println!("Average route time: {}μs (50 modules, 128-dim)", avg_route);
424
425 // Should be reasonably fast (<1ms per route)
426 assert!(avg_route < 1000, "Routing should be fast");
427 }
428}