wave-memory 0.1.0

A geometric wave-memory system where waves adapt the form. Inspired by Leonov recursive structures.
Documentation
//! wave-memory — geometric wave memory based on Leonov-like form dynamics

//! # Overview
//! This library simulates wave propagation through an adaptive geometric medium (GeoForm).
//! The form is initialized using a chaotic recursive sequence with memory, and it evolves over time
//! based on the wave energy. This creates a primitive model of self-organizing spatial memory.

/// Represents the geometric memory field that reacts to wave energy
#[derive(Debug, Clone)]
pub struct GeoForm {
    pub data: Vec<f64>,     // shape values across space
    pub alpha: f64,         // learning rate
    pub damping: f64,       // resistance to deformation
}

impl GeoForm {
    /// Constructs a shape using a Leonov-like recursive chaotic sequence
    pub fn from_leonov(len: usize, seed: u64) -> Self {
        use rand::{Rng, SeedableRng};
        use rand_pcg::Pcg64;

        let mut rng = Pcg64::seed_from_u64(seed);
        let mut data = vec![1.0, 1.0];

        while data.len() < len {
            let n = data.len();
            let a = rng.random_range(-2.0..2.0);
            let b = rng.random_range(-2.0..2.0);
            let c = rng.random_range(-2.0..2.0);
            let d = rng.random_range(1..=n.min(10));
            let val = (a * data[n - 1] + b * data[n - 2] + c * data[n - d] / (1.0 + n as f64)).abs();
            data.push(val);
        }

        Self {
            data,
            alpha: 0.1,
            damping: 0.01,
        }
    }

    /// Updates the shape based on wave energy
    /// Each point of the form responds to local wave energy
    pub fn adapt(&mut self, wave: &[f64], dt: f64) {
        for (f, &psi) in self.data.iter_mut().zip(wave.iter()) {
            *f += self.alpha * psi * psi * dt;           // learn from energy
            *f -= self.damping * (*f - 1.0);             // decay toward neutral baseline
        }
    }
}

/// Simulates a wave traveling across the shape
#[derive(Debug, Clone)]
pub struct Wave {
    pub psi_prev: Vec<f64>,  // previous wave state
    pub psi: Vec<f64>,       // current wave state
    pub alpha: f64,          // wave stiffness coefficient
}

impl Wave {
    /// Initializes the wave with a single impulse
    pub fn new(len: usize, impulse_pos: usize) -> Self {
        let mut psi = vec![0.0; len];
        psi[impulse_pos] = 1.0;  // spike at center

        Self {
            psi_prev: psi.clone(),
            psi,
            alpha: 0.5,
        }
    }

    /// Computes the next wave step based on the current form
    pub fn step(&mut self, form: &GeoForm) {
        let len = self.psi.len();
        let mut next = vec![0.0; len];

        for i in 1..len - 1 {
            let laplace = (self.psi[i + 1] - 2.0 * self.psi[i] + self.psi[i - 1]) / form.data[i].max(1e-6);
            next[i] = 2.0 * self.psi[i] - self.psi_prev[i] + self.alpha * laplace;
        }

        self.psi_prev = self.psi.clone();
        self.psi = next;
    }

    /// Returns squared amplitude as wave energy
    pub fn energy(&self) -> Vec<f64> {
        self.psi.iter().map(|x| x * x).collect()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Simulates wave and memory interaction
    #[test]
    fn test_adaptive_wave_memory() {
        let mut form = GeoForm::from_leonov(64, 42);
        let mut wave = Wave::new(64, 32);

        for _ in 0..50 {
            wave.step(&form);
            let energy = wave.energy();
            form.adapt(&energy, 0.1);
        }

        // Form should evolve
        assert!(form.data.iter().any(|&f| f > 1.01));
    }
}