holographic-memory 0.6.1

A high-performance Holographic Memory System (HMS) implementing Vector Symbolic Architectures (VSA).
Documentation
// Copyright 2024-2026 WritersLogic Contributors
// SPDX-License-Identifier: AGPL-3.0-or-later

use crate::core::entangled::EntangledHVec;

pub struct ClsConfig {
    pub dim: usize,
    pub density_denom: usize,
    pub consolidation_interval: usize,
    pub resonance_threshold: f64,
    pub heart1_capacity: usize,
}

impl ClsConfig {
    pub fn new(dim: usize, density_denom: usize) -> Self {
        Self {
            dim,
            density_denom,
            consolidation_interval: 50,
            resonance_threshold: 0.3,
            heart1_capacity: 200,
        }
    }
}

pub struct ClsMemory {
    cfg: ClsConfig,
    heart1_items: Vec<EntangledHVec>,
    heart1_bundle: Option<EntangledHVec>,
    heart2_items: Vec<EntangledHVec>,
    heart2_bundle: Option<EntangledHVec>,
    total_added: usize,
    total_consolidated: usize,
}

impl ClsMemory {
    pub fn new(cfg: ClsConfig) -> Self {
        Self {
            cfg,
            heart1_items: Vec::new(),
            heart1_bundle: None,
            heart2_items: Vec::new(),
            heart2_bundle: None,
            total_added: 0,
            total_consolidated: 0,
        }
    }

    pub fn add(&mut self, item: EntangledHVec) {
        self.heart1_items.push(item);
        self.rebuild_heart1();
        self.total_added += 1;

        if self
            .total_added
            .is_multiple_of(self.cfg.consolidation_interval)
        {
            self.consolidate();
        }
    }

    fn consolidate(&mut self) {
        if self.heart1_items.is_empty() {
            return;
        }

        let h1_bundle = self.heart1_bundle.clone();
        let mut promoted = Vec::new();
        let mut retained = Vec::new();

        for item in self.heart1_items.drain(..) {
            let resonates = match &self.heart2_bundle {
                Some(h2) => item.corrected_containment(h2) > self.cfg.resonance_threshold,
                None => true,
            };

            let reinforced = match &h1_bundle {
                Some(b) => item.corrected_containment(b) > 0.5,
                None => false,
            };

            if resonates || reinforced {
                promoted.push(item);
            } else {
                retained.push(item);
            }
        }

        for item in &promoted {
            self.heart2_items.push(item.clone());
        }
        self.total_consolidated += promoted.len();

        if retained.len() > self.cfg.heart1_capacity {
            let drain = retained.len() - self.cfg.heart1_capacity;
            retained.drain(..drain);
        }

        self.heart1_items = retained;
        self.rebuild_heart1();
        self.rebuild_heart2();
    }

    fn rebuild_heart1(&mut self) {
        if self.heart1_items.is_empty() {
            self.heart1_bundle = None;
        } else {
            self.heart1_bundle = Some(EntangledHVec::bundle_bloom(&self.heart1_items));
        }
    }

    fn rebuild_heart2(&mut self) {
        if self.heart2_items.is_empty() {
            self.heart2_bundle = None;
        } else {
            self.heart2_bundle = Some(EntangledHVec::bundle_bloom(&self.heart2_items));
        }
    }

    pub fn query(&self, item: &EntangledHVec) -> f64 {
        let h1_score = match &self.heart1_bundle {
            Some(b) => item.corrected_containment(b),
            None => 0.0,
        };
        let h2_score = match &self.heart2_bundle {
            Some(b) => item.corrected_containment(b),
            None => 0.0,
        };
        h1_score.max(h2_score)
    }

    pub fn heart1_count(&self) -> usize {
        self.heart1_items.len()
    }

    pub fn heart2_count(&self) -> usize {
        self.heart2_items.len()
    }

    pub fn heart1_density(&self) -> f64 {
        match &self.heart1_bundle {
            Some(b) => b.indices().len() as f64 / self.cfg.dim as f64,
            None => 0.0,
        }
    }

    pub fn heart2_density(&self) -> f64 {
        match &self.heart2_bundle {
            Some(b) => b.indices().len() as f64 / self.cfg.dim as f64,
            None => 0.0,
        }
    }

    pub fn total_consolidated(&self) -> usize {
        self.total_consolidated
    }
}

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

    #[test]
    fn test_cls_single_item() {
        let cfg = ClsConfig::new(16384, 256);
        let mut mem = ClsMemory::new(cfg);
        let item = EntangledHVec::new_deterministic(16384, 42);
        mem.add(item.clone());
        assert!(mem.query(&item) > 0.9);
    }

    #[test]
    fn test_cls_consolidation_runs() {
        let mut cfg = ClsConfig::new(16384, 256);
        cfg.consolidation_interval = 10;
        let mut mem = ClsMemory::new(cfg);
        for i in 0..20 {
            mem.add(EntangledHVec::new_deterministic(16384, i * 37 + 1));
        }
        assert!(mem.total_consolidated() > 0);
    }
}