Skip to main content

st/mem8/
wave.rs

1//! Wave-based memory model for MEM8 cognitive architecture
2//! Based on the MEM8 paper - 256×256×65536 wave grid with interference patterns
3
4use serde::{Deserialize, Serialize};
5use std::f32::consts::PI;
6use std::sync::Arc;
7use std::time::{Duration, Instant};
8
9/// Memory wave at a specific grid position
10#[derive(Clone, Debug, Serialize, Deserialize)]
11pub struct MemoryWave {
12    /// Amplitude modulated by emotion and time
13    pub amplitude: f32,
14    /// Wave frequency encoding semantic content (0-1000Hz)
15    pub frequency: f32,
16    /// Phase encoding temporal relationships
17    pub phase: f32,
18    /// Emotional valence (-1.0 to 1.0)
19    pub valence: f32,
20    /// Emotional arousal (0.0 to 1.0)
21    pub arousal: f32,
22    /// Creation timestamp
23    #[serde(skip, default = "Instant::now")]
24    pub created_at: Instant,
25    /// Decay time constant (None = infinite)
26    #[serde(with = "duration_serde")]
27    pub decay_tau: Option<Duration>,
28}
29
30impl MemoryWave {
31    /// Create a new memory wave
32    pub fn new(frequency: f32, amplitude: f32) -> Self {
33        Self {
34            amplitude,
35            frequency: frequency.clamp(0.0, 1000.0),
36            phase: 0.0,
37            valence: 0.0,
38            arousal: 0.0,
39            created_at: Instant::now(),
40            decay_tau: Some(Duration::from_secs(5)), // Default 5s decay
41        }
42    }
43
44    /// Create a new memory wave with a specific frequency band
45    pub fn new_with_band(band: FrequencyBand, amplitude: f32, phase: f32, decay_rate: f32) -> Self {
46        let (min_freq, max_freq) = band.range();
47        let frequency = (min_freq + max_freq) / 2.0; // Use center frequency
48        let mut wave = Self::new(frequency, amplitude);
49        wave.phase = phase;
50        if decay_rate > 0.0 {
51            wave.decay_tau = Some(Duration::from_secs_f32(1.0 / decay_rate));
52        } else {
53            wave.decay_tau = None; // Infinite persistence
54        }
55        wave
56    }
57
58    /// Calculate wave value at time t with decay and emotional modulation
59    pub fn calculate(&self, t: f32) -> f32 {
60        let decay = self.calculate_decay();
61        let emotional_mod = self.calculate_emotional_modulation();
62
63        self.amplitude * decay * emotional_mod * (2.0 * PI * self.frequency * t + self.phase).sin()
64    }
65
66    /// Calculate temporal decay
67    pub fn calculate_decay(&self) -> f32 {
68        match self.decay_tau {
69            Some(tau) => {
70                let elapsed = self.created_at.elapsed().as_secs_f32();
71                (-elapsed / tau.as_secs_f32()).exp()
72            }
73            None => 1.0, // No decay
74        }
75    }
76
77    /// Calculate emotional modulation based on valence and arousal
78    pub fn calculate_emotional_modulation(&self) -> f32 {
79        const ALPHA: f32 = 0.3; // Valence influence
80        const BETA: f32 = 0.5; // Arousal influence
81
82        (1.0 + ALPHA * self.valence) * (1.0 + BETA * self.arousal)
83    }
84
85    /// Apply context-aware decay based on relevance, familiarity, and threat
86    pub fn apply_context_decay(&mut self, relevance: f32, familiarity: f32, threat: f32) {
87        if let Some(base_tau) = self.decay_tau {
88            let r_factor = relevance.clamp(0.5, 2.0);
89            let f_factor = familiarity.clamp(0.8, 1.5);
90            let t_factor = threat.clamp(0.3, 1.0);
91
92            let adjusted_tau = base_tau.as_secs_f32() * r_factor * f_factor * t_factor;
93            self.decay_tau = Some(Duration::from_secs_f32(adjusted_tau));
94        }
95    }
96}
97
98/// 3D Wave Grid: 256×256×65536 (8-bit × 8-bit × 16-bit)
99pub struct WaveGrid {
100    /// Grid dimensions
101    pub width: usize, // 256
102    pub height: usize, // 256
103    pub depth: usize,  // 65536
104
105    /// The actual grid storage (flattened for performance)
106    grid: Vec<Option<Arc<MemoryWave>>>,
107
108    /// Noise floor threshold for adaptive filtering
109    pub noise_floor: f32,
110}
111
112impl Default for WaveGrid {
113    fn default() -> Self {
114        Self::new()
115    }
116}
117
118impl WaveGrid {
119    /// Create a new wave grid with standard MEM8 dimensions
120    /// Grid is 256×256 (u8×u8 address space), Z (u16) is stored as temporal depth per cell
121    pub fn new() -> Self {
122        const WIDTH: usize = 256;   // X: u8 coordinate
123        const HEIGHT: usize = 256;  // Y: u8 coordinate
124        const DEPTH: usize = 1;     // Z is a value per cell, not a dimension
125
126        Self {
127            width: WIDTH,
128            height: HEIGHT,
129            depth: DEPTH,
130            grid: vec![None; WIDTH * HEIGHT], // 65,536 cells
131            noise_floor: 0.1,
132        }
133    }
134
135    /// Create a smaller wave grid for testing
136    #[cfg(test)]
137    pub fn new_test() -> Self {
138        Self::new() // Standard grid is already compact
139    }
140
141    /// Create a compact wave grid (same as new() - grid is inherently compact)
142    /// Grid: 256×256 = 65K cells, Z (u16) is temporal depth stored per cell
143    pub fn new_compact() -> Self {
144        Self::new()
145    }
146
147    /// Get linear index from 2D coordinates (X, Y)
148    /// Z is stored as temporal depth with the wave, not as a dimension
149    fn get_index(&self, x: u8, y: u8, _z: u16) -> usize {
150        let x = x as usize;
151        let y = y as usize;
152        y * self.width + x // 2D index: just X,Y
153    }
154
155    /// Store a memory wave at specific coordinates
156    /// Z (temporal depth) is tracked in AnchoredMemory, not grid structure
157    pub fn store(&mut self, x: u8, y: u8, z: u16, wave: MemoryWave) {
158        let idx = self.get_index(x, y, z);
159
160        // Apply noise floor filtering
161        if wave.amplitude > self.noise_floor {
162            self.grid[idx] = Some(Arc::new(wave));
163        }
164    }
165
166    /// Retrieve a memory wave at specific coordinates
167    pub fn get(&self, x: u8, y: u8, z: u16) -> Option<&Arc<MemoryWave>> {
168        let idx = self.get_index(x, y, z);
169        self.grid[idx].as_ref()
170    }
171
172    /// Calculate interference pattern at a specific point
173    /// Uses 3×3 neighborhood (X,Y plane)
174    pub fn calculate_interference(&self, x: u8, y: u8, z: u16, t: f32) -> f32 {
175        let mut total = 0.0;
176
177        // Check 3×3 neighborhood for interference (2D grid)
178        for dx in -1i8..=1 {
179            for dy in -1i8..=1 {
180                let nx = (x as i16 + dx as i16).clamp(0, 255) as u8;
181                let ny = (y as i16 + dy as i16).clamp(0, 255) as u8;
182
183                if let Some(wave) = self.get(nx, ny, z) {
184                    // Weight by distance (closer neighbors have more influence)
185                    let distance = ((dx * dx + dy * dy) as f32).sqrt();
186                    let weight = 1.0 / (1.0 + distance);
187                    total += wave.calculate(t) * weight;
188                }
189            }
190        }
191
192        total
193    }
194
195    /// Adaptive noise floor adjustment based on environmental conditions
196    pub fn adjust_noise_floor(&mut self, environmental_noise: f32) {
197        // Adapt noise floor to environmental conditions
198        self.noise_floor = (self.noise_floor * 0.9 + environmental_noise * 0.1).clamp(0.01, 0.5);
199    }
200
201    /// Count active (non-decayed) memories
202    pub fn active_memory_count(&self) -> usize {
203        self.grid
204            .iter()
205            .filter_map(|slot| slot.as_ref())
206            .filter(|wave| wave.calculate_decay() > 0.01)
207            .count()
208    }
209}
210
211/// Frequency bands for different content types
212#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
213pub enum FrequencyBand {
214    Delta,      // 0-100Hz (deep structural)
215    Theta,      // 100-200Hz (integration)
216    Alpha,      // 200-300Hz (conversational flow)
217    Beta,       // 300-500Hz (active processing)
218    Gamma,      // 500-800Hz (conscious binding)
219    HyperGamma, // 800-1000Hz (peak awareness)
220    // Legacy aliases
221    DeepStructural, // 0-200Hz
222    Conversational, // 200-400Hz
223    Technical,      // 400-600Hz
224    Implementation, // 600-800Hz
225    Abstract,       // 800-1000Hz
226}
227
228impl FrequencyBand {
229    /// Get the frequency range for this band
230    pub fn range(&self) -> (f32, f32) {
231        match self {
232            Self::Delta => (0.0, 100.0),
233            Self::Theta => (100.0, 200.0),
234            Self::Alpha => (200.0, 300.0),
235            Self::Beta => (300.0, 500.0),
236            Self::Gamma => (500.0, 800.0),
237            Self::HyperGamma => (800.0, 1000.0),
238            // Legacy mappings
239            Self::DeepStructural => (0.0, 200.0),
240            Self::Conversational => (200.0, 400.0),
241            Self::Technical => (400.0, 600.0),
242            Self::Implementation => (600.0, 800.0),
243            Self::Abstract => (800.0, 1000.0),
244        }
245    }
246
247    /// Get a frequency within this band
248    pub fn frequency(&self, position: f32) -> f32 {
249        let (min, max) = self.range();
250        min + (max - min) * position.clamp(0.0, 1.0)
251    }
252
253    /// Determine band from frequency
254    pub fn from_frequency(freq: f32) -> Self {
255        match freq {
256            f if f < 200.0 => Self::DeepStructural,
257            f if f < 400.0 => Self::Conversational,
258            f if f < 600.0 => Self::Technical,
259            f if f < 800.0 => Self::Implementation,
260            _ => Self::Abstract,
261        }
262    }
263}
264
265/// Serialization helpers for Duration
266mod duration_serde {
267    use serde::{Deserialize, Deserializer, Serializer};
268    use std::time::Duration;
269
270    pub fn serialize<S>(duration: &Option<Duration>, serializer: S) -> Result<S::Ok, S::Error>
271    where
272        S: Serializer,
273    {
274        match duration {
275            Some(d) => serializer.serialize_u64(d.as_secs()),
276            None => serializer.serialize_none(),
277        }
278    }
279
280    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Duration>, D::Error>
281    where
282        D: Deserializer<'de>,
283    {
284        let opt: Option<u64> = Option::deserialize(deserializer)?;
285        Ok(opt.map(Duration::from_secs))
286    }
287}
288
289#[cfg(test)]
290mod tests {
291    use super::*;
292
293    #[test]
294    fn test_memory_wave_creation() {
295        let wave = MemoryWave::new(440.0, 0.8);
296        assert_eq!(wave.frequency, 440.0);
297        assert_eq!(wave.amplitude, 0.8);
298    }
299
300    #[test]
301    fn test_wave_grid_storage() {
302        let mut grid = WaveGrid::new_test();
303        let wave = MemoryWave::new(440.0, 0.5);
304
305        grid.store(128, 128, 128, wave);
306
307        assert!(grid.get(128, 128, 128).is_some());
308        assert!(grid.get(0, 0, 0).is_none());
309    }
310
311    #[test]
312    fn test_emotional_modulation() {
313        let mut wave = MemoryWave::new(440.0, 1.0);
314        wave.valence = 0.5; // Positive
315        wave.arousal = 0.8; // High arousal
316
317        let modulation = wave.calculate_emotional_modulation();
318        assert!(modulation > 1.0); // Should amplify
319    }
320}