Skip to main content

st/mem8/
reactive.rs

1//! Reactive memory layers for MEM8 - hierarchical processing from reflexes to consciousness
2//! Implements 4 layers: 0-10ms hardware reflexes to >200ms conscious deliberation
3
4use crate::mem8::wave::{MemoryWave, WaveGrid};
5use std::sync::{Arc, RwLock};
6use std::time::{Duration, Instant};
7
8/// Reactive layer types with their response time windows
9#[derive(Debug, Clone, Copy, PartialEq)]
10pub enum ReactiveLayer {
11    /// Layer 0: Hardware reflexes (0-10ms) - direct sensor-to-response
12    HardwareReflex,
13    /// Layer 1: Subcortical reactions (10-50ms) - pattern-matched responses
14    SubcorticalReaction,
15    /// Layer 2: Emotional responses (50-200ms) - emotionally-modulated decisions
16    EmotionalResponse,
17    /// Layer 3: Conscious deliberation (>200ms) - full cognitive processing
18    ConsciousDeliberation,
19}
20
21impl ReactiveLayer {
22    /// Get the response time window for this layer
23    pub fn response_window(&self) -> (Duration, Option<Duration>) {
24        match self {
25            Self::HardwareReflex => (Duration::ZERO, Some(Duration::from_millis(10))),
26            Self::SubcorticalReaction => {
27                (Duration::from_millis(10), Some(Duration::from_millis(50)))
28            }
29            Self::EmotionalResponse => {
30                (Duration::from_millis(50), Some(Duration::from_millis(200)))
31            }
32            Self::ConsciousDeliberation => (Duration::from_millis(200), None),
33        }
34    }
35
36    /// Determine which layer should handle based on response time
37    pub fn from_response_time(elapsed: Duration) -> Self {
38        match elapsed.as_millis() {
39            0..=10 => Self::HardwareReflex,
40            11..=50 => Self::SubcorticalReaction,
41            51..=200 => Self::EmotionalResponse,
42            _ => Self::ConsciousDeliberation,
43        }
44    }
45}
46
47/// A reactive response pattern
48#[derive(Clone)]
49pub struct ReactivePattern {
50    /// Pattern identifier
51    pub id: String,
52    /// Minimum activation threshold
53    pub threshold: f32,
54    /// Weight for this pattern
55    pub weight: f32,
56    /// Pattern-specific response
57    pub response: Arc<dyn Fn() -> ReactiveResponse + Send + Sync>,
58}
59
60/// Response from a reactive layer
61#[derive(Debug, Clone)]
62pub struct ReactiveResponse {
63    /// Layer that generated this response
64    pub layer: ReactiveLayer,
65    /// Response strength (0.0 to 1.0)
66    pub strength: f32,
67    /// Action to take
68    pub action: String,
69    /// Response latency
70    pub latency: Duration,
71}
72
73/// Hierarchical reactive memory system
74pub struct ReactiveMemory {
75    /// Wave grid for memory storage
76    wave_grid: Arc<RwLock<WaveGrid>>,
77    /// Registered patterns for each layer
78    patterns: Vec<Vec<ReactivePattern>>,
79    /// Start time for latency tracking
80    start_time: Instant,
81}
82
83impl ReactiveMemory {
84    /// Create a new reactive memory system
85    pub fn new(wave_grid: Arc<RwLock<WaveGrid>>) -> Self {
86        Self {
87            wave_grid,
88            patterns: vec![Vec::new(); 4], // 4 layers
89            start_time: Instant::now(),
90        }
91    }
92
93    /// Register a reactive pattern for a specific layer
94    pub fn register_pattern(&mut self, layer: ReactiveLayer, pattern: ReactivePattern) {
95        let layer_idx = layer as usize;
96        self.patterns[layer_idx].push(pattern);
97    }
98
99    /// Process input through all reactive layers
100    pub fn process(&self, input: &SensorInput) -> Option<ReactiveResponse> {
101        let start = Instant::now();
102
103        // Check each layer in order (fastest to slowest)
104        for layer in [
105            ReactiveLayer::HardwareReflex,
106            ReactiveLayer::SubcorticalReaction,
107            ReactiveLayer::EmotionalResponse,
108            ReactiveLayer::ConsciousDeliberation,
109        ] {
110            if let Some(response) = self.process_layer(layer, input, start) {
111                // Check if we should bypass higher layers
112                if self.should_bypass(layer, &response) {
113                    return Some(response);
114                }
115            }
116        }
117
118        None
119    }
120
121    /// Process input for a specific layer
122    fn process_layer(
123        &self,
124        layer: ReactiveLayer,
125        input: &SensorInput,
126        start: Instant,
127    ) -> Option<ReactiveResponse> {
128        let layer_idx = layer as usize;
129        let elapsed = start.elapsed();
130
131        // Check if we're within this layer's time window
132        let (min_time, max_time) = layer.response_window();
133        if elapsed < min_time || (max_time.is_some() && elapsed > max_time.unwrap()) {
134            return None;
135        }
136
137        // Evaluate patterns for this layer
138        let mut best_response: Option<ReactiveResponse> = None;
139        let mut best_strength = 0.0;
140
141        for pattern in &self.patterns[layer_idx] {
142            let activation = self.calculate_activation(pattern, input);
143
144            if activation > pattern.threshold && activation > best_strength {
145                best_strength = activation;
146                best_response = Some((pattern.response)());
147            }
148        }
149
150        best_response
151    }
152
153    /// Calculate pattern activation strength
154    fn calculate_activation(&self, pattern: &ReactivePattern, input: &SensorInput) -> f32 {
155        // Layer-specific activation calculation
156        match input {
157            SensorInput::Visual { intensity, .. } => pattern.weight * intensity,
158            SensorInput::Audio { amplitude, .. } => pattern.weight * amplitude,
159            SensorInput::Threat { severity, .. } => pattern.weight * severity,
160            _ => 0.0,
161        }
162    }
163
164    /// Determine if we should bypass higher layers
165    fn should_bypass(&self, layer: ReactiveLayer, response: &ReactiveResponse) -> bool {
166        // Critical responses bypass higher processing
167        match layer {
168            ReactiveLayer::HardwareReflex => response.strength > 0.9,
169            ReactiveLayer::SubcorticalReaction => response.strength > 0.8,
170            ReactiveLayer::EmotionalResponse => response.strength > 0.7,
171            ReactiveLayer::ConsciousDeliberation => true, // Always final
172        }
173    }
174
175    /// Calculate bypass probability based on threat level
176    pub fn bypass_probability(layer: ReactiveLayer, threat_level: f32) -> f32 {
177        const K: f32 = 2.0; // Sensitivity constant
178        let layer_idx = layer as usize;
179
180        1.0 - (-K * (3.0 - layer_idx as f32) * threat_level).exp()
181    }
182}
183
184/// Sensor input types
185#[derive(Debug, Clone)]
186pub enum SensorInput {
187    Visual {
188        intensity: f32,
189        motion: f32,
190        looming: bool,
191    },
192    Audio {
193        amplitude: f32,
194        frequency: f32,
195        sudden: bool,
196    },
197    Threat {
198        severity: f32,
199        proximity: f32,
200        pattern: String,
201    },
202    Network {
203        packet_malformed: bool,
204        attack_signature: Option<String>,
205    },
206}
207
208/// Looming detection for reflexive responses
209pub struct LoomingDetector {
210    /// Previous angular size measurements
211    history: Vec<(Instant, f32)>,
212    /// Response threshold (typically 0.5-1.0 seconds)
213    threshold: f32,
214}
215
216impl LoomingDetector {
217    pub fn new(threshold: f32) -> Self {
218        Self {
219            history: Vec::new(),
220            threshold,
221        }
222    }
223
224    /// Update with new angular size measurement
225    pub fn update(&mut self, angular_size: f32) -> Option<f32> {
226        let now = Instant::now();
227        self.history.push((now, angular_size));
228
229        // Keep only recent history (last 500ms)
230        self.history
231            .retain(|(t, _)| now.duration_since(*t) < Duration::from_millis(500));
232
233        // Need at least 2 points to calculate expansion
234        if self.history.len() < 2 {
235            return None;
236        }
237
238        // Calculate angular expansion rate (tau^-1)
239        let (t1, theta1) = self.history[self.history.len() - 2];
240        let (t2, theta2) = self.history[self.history.len() - 1];
241
242        let dt = t2.duration_since(t1).as_secs_f32();
243        let d_theta = theta2 - theta1;
244
245        if dt > 0.0 && theta2 > 0.0 {
246            let tau_inv = d_theta / (theta2 * dt);
247
248            // Calculate urgency
249            let urgency = 1.0 - (-self.threshold / tau_inv.max(0.001)).exp();
250            Some(urgency)
251        } else {
252            None
253        }
254    }
255}
256
257/// Multi-modal sensor coherence calculator
258pub struct SensorCoherence {
259    /// Sensor readings with phase information
260    sensors: Vec<(f32, f32)>, // (amplitude, phase)
261}
262
263impl Default for SensorCoherence {
264    fn default() -> Self {
265        Self::new()
266    }
267}
268
269impl SensorCoherence {
270    pub fn new() -> Self {
271        Self {
272            sensors: Vec::new(),
273        }
274    }
275
276    /// Add a sensor reading
277    pub fn add_sensor(&mut self, amplitude: f32, phase: f32) {
278        self.sensors.push((amplitude, phase));
279    }
280
281    /// Calculate coherence (0.0 = disagreement, 1.0 = agreement)
282    pub fn calculate(&self) -> f32 {
283        if self.sensors.is_empty() {
284            return 0.0;
285        }
286
287        // Calculate coherence using phase relationships
288        let mut sum_real = 0.0;
289        let mut sum_imag = 0.0;
290        let mut sum_amplitude_sq = 0.0;
291
292        for &(amplitude, phase) in &self.sensors {
293            sum_real += amplitude * phase.cos();
294            sum_imag += amplitude * phase.sin();
295            sum_amplitude_sq += amplitude * amplitude;
296        }
297
298        if sum_amplitude_sq > 0.0 {
299            let magnitude_sq = sum_real * sum_real + sum_imag * sum_imag;
300            magnitude_sq / sum_amplitude_sq
301        } else {
302            0.0
303        }
304    }
305}
306
307/// Subliminal processing for below-threshold stimuli
308pub struct SubliminalProcessor {
309    /// Threshold for conscious awareness
310    awareness_threshold: f32,
311    /// Subliminal amplitude range
312    subliminal_range: (f32, f32),
313}
314
315impl Default for SubliminalProcessor {
316    fn default() -> Self {
317        Self::new()
318    }
319}
320
321impl SubliminalProcessor {
322    pub fn new() -> Self {
323        Self {
324            awareness_threshold: 0.15,
325            subliminal_range: (0.01, 0.15),
326        }
327    }
328
329    /// Check if stimulus is subliminal
330    pub fn is_subliminal(&self, amplitude: f32) -> bool {
331        amplitude >= self.subliminal_range.0 && amplitude < self.subliminal_range.1
332    }
333
334    /// Process subliminal stimulus
335    pub fn process(&self, wave: &MemoryWave) -> Option<SubconsciousEffect> {
336        if self.is_subliminal(wave.amplitude) {
337            // Subliminal processing occurs below conscious threshold
338            Some(SubconsciousEffect {
339                priming: wave.frequency / 1000.0, // Normalized frequency as priming strength
340                emotional_bias: wave.valence * 0.3, // Reduced emotional influence
341                pattern_activation: wave.arousal * 0.2,
342            })
343        } else {
344            None
345        }
346    }
347}
348
349/// Effects of subliminal processing
350#[derive(Debug, Clone)]
351pub struct SubconsciousEffect {
352    /// Priming strength for related concepts
353    pub priming: f32,
354    /// Emotional bias influence
355    pub emotional_bias: f32,
356    /// Pattern activation level
357    pub pattern_activation: f32,
358}
359
360#[cfg(test)]
361mod tests {
362    use super::*;
363
364    #[test]
365    fn test_reactive_layers() {
366        assert_eq!(
367            ReactiveLayer::from_response_time(Duration::from_millis(5)),
368            ReactiveLayer::HardwareReflex
369        );
370        assert_eq!(
371            ReactiveLayer::from_response_time(Duration::from_millis(30)),
372            ReactiveLayer::SubcorticalReaction
373        );
374        assert_eq!(
375            ReactiveLayer::from_response_time(Duration::from_millis(100)),
376            ReactiveLayer::EmotionalResponse
377        );
378        assert_eq!(
379            ReactiveLayer::from_response_time(Duration::from_millis(300)),
380            ReactiveLayer::ConsciousDeliberation
381        );
382    }
383
384    #[test]
385    fn test_looming_detection() {
386        let mut detector = LoomingDetector::new(0.5);
387
388        // Simulate approaching object
389        detector.update(0.1);
390        std::thread::sleep(Duration::from_millis(100));
391        detector.update(0.15);
392        std::thread::sleep(Duration::from_millis(100));
393
394        if let Some(urgency) = detector.update(0.25) {
395            assert!(urgency > 0.0);
396            assert!(urgency <= 1.0);
397        }
398    }
399
400    #[test]
401    fn test_sensor_coherence() {
402        let mut coherence = SensorCoherence::new();
403
404        // Add coherent sensors (similar phases)
405        coherence.add_sensor(1.0, 0.0);
406        coherence.add_sensor(0.8, 0.1);
407        coherence.add_sensor(0.9, -0.1);
408
409        let c = coherence.calculate();
410        assert!(c > 0.9); // High coherence
411
412        // Add incoherent sensor
413        coherence.add_sensor(1.0, std::f32::consts::PI); // Opposite phase
414        let c2 = coherence.calculate();
415        assert!(c2 < c); // Reduced coherence
416    }
417}