pub mod consolidation;
pub mod episodic;
pub mod semantic;
pub mod working;
pub use consolidation::{ConsolidationConfig, SleepConsolidation};
pub use episodic::{Episode, EpisodeQuery, EpisodicMemory};
pub use semantic::{Concept, ConceptGraph, SemanticMemory};
pub use working::{WorkingMemory, WorkingMemoryConfig};
use ronn_core::tensor::Tensor;
use std::time::{SystemTime, UNIX_EPOCH};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum MemoryError {
#[error("Working memory error: {0}")]
WorkingMemory(String),
#[error("Episodic memory error: {0}")]
EpisodicMemory(String),
#[error("Semantic memory error: {0}")]
SemanticMemory(String),
#[error("Consolidation error: {0}")]
Consolidation(String),
#[error("Core error: {0}")]
Core(#[from] ronn_core::error::CoreError),
}
pub type Result<T> = std::result::Result<T, MemoryError>;
pub struct MultiTierMemory {
working: WorkingMemory,
episodic: EpisodicMemory,
semantic: SemanticMemory,
consolidation: SleepConsolidation,
}
impl MultiTierMemory {
pub fn new() -> Self {
Self {
working: WorkingMemory::new(WorkingMemoryConfig::default()),
episodic: EpisodicMemory::new(),
semantic: SemanticMemory::new(),
consolidation: SleepConsolidation::new(ConsolidationConfig::default()),
}
}
pub fn store(&mut self, data: Tensor, importance: f64) -> Result<MemoryId> {
let id = self.working.store(data, importance)?;
if importance > 0.7 {
let tensor = self.working.get(id)?;
let episode = Episode {
id,
data: tensor,
timestamp: current_timestamp(),
importance,
};
self.episodic.store_episode(episode)?;
}
Ok(id)
}
pub fn retrieve(&self, id: MemoryId) -> Result<Option<Tensor>> {
if let Ok(tensor) = self.working.get(id) {
return Ok(Some(tensor));
}
if let Some(episode) = self.episodic.get_episode(id) {
return Ok(Some(episode.data));
}
Ok(None)
}
pub fn search_similar(&self, query: &Tensor, limit: usize) -> Result<Vec<MemoryId>> {
self.working.search_similar(query, limit)
}
pub async fn consolidate(&mut self) -> Result<ConsolidationResult> {
let working_items = self.working.drain_old_items()?;
let items_count = working_items.len();
for (id, tensor, importance) in working_items {
if importance > 0.5 {
let episode = Episode {
id,
data: tensor,
timestamp: current_timestamp(),
importance,
};
self.episodic.store_episode(episode)?;
}
}
let patterns = self.consolidation.extract_patterns(&self.episodic).await?;
let patterns_count = patterns.len();
for concept in patterns {
self.semantic.store_concept(concept)?;
}
Ok(ConsolidationResult {
episodes_consolidated: items_count,
patterns_extracted: patterns_count,
})
}
pub fn stats(&self) -> MemoryStats {
MemoryStats {
working_items: self.working.len(),
episodic_episodes: self.episodic.len(),
semantic_concepts: self.semantic.len(),
}
}
}
impl Default for MultiTierMemory {
fn default() -> Self {
Self::new()
}
}
pub type MemoryId = u64;
#[derive(Debug, Clone)]
pub struct ConsolidationResult {
pub episodes_consolidated: usize,
pub patterns_extracted: usize,
}
#[derive(Debug, Clone)]
pub struct MemoryStats {
pub working_items: usize,
pub episodic_episodes: usize,
pub semantic_concepts: usize,
}
pub fn current_timestamp() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis() as u64
}
#[cfg(test)]
mod tests {
use super::*;
use ronn_core::types::{DataType, TensorLayout};
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
#[test]
fn test_memory_creation() {
let memory = MultiTierMemory::new();
let stats = memory.stats();
assert_eq!(stats.working_items, 0);
assert_eq!(stats.episodic_episodes, 0);
assert_eq!(stats.semantic_concepts, 0);
}
#[test]
fn test_store_and_retrieve() -> Result<()> {
let mut memory = MultiTierMemory::new();
let data = vec![1.0f32, 2.0, 3.0, 4.0];
let tensor = Tensor::from_data(data, vec![1, 4], DataType::F32, TensorLayout::RowMajor)?;
let id = memory.store(tensor.clone(), 0.3)?;
let retrieved = memory.retrieve(id)?;
assert!(retrieved.is_some());
Ok(())
}
#[test]
fn test_high_importance_storage() -> Result<()> {
let mut memory = MultiTierMemory::new();
let data = vec![1.0f32, 2.0, 3.0, 4.0];
let tensor = Tensor::from_data(data, vec![1, 4], DataType::F32, TensorLayout::RowMajor)?;
let id = memory.store(tensor, 0.9)?;
let stats = memory.stats();
assert_eq!(stats.working_items, 1);
assert_eq!(stats.episodic_episodes, 1);
Ok(())
}
#[tokio::test]
async fn test_consolidation() -> Result<()> {
let mut memory = MultiTierMemory::new();
for i in 0..5 {
let data = vec![i as f32; 4];
let tensor =
Tensor::from_data(data, vec![1, 4], DataType::F32, TensorLayout::RowMajor)?;
memory.store(tensor, 0.6)?;
}
let result = memory.consolidate().await?;
assert!(result.episodes_consolidated >= 0);
assert!(result.patterns_extracted >= 0);
Ok(())
}
}