# SONA Memory Dreams: Offline Consolidation Engine ## Creativity Through Neural Replay and Recombination --- ## 1. Biological Inspiration ### Why Dreams Matter for Learning ``` HUMAN SLEEP-BASED LEARNING ══════════════════════════ Awake: Sleep (REM): Next Day: ───────────────── ───────────────── ───────────────── • New experiences • Replay memories • Consolidated knowledge • Pattern matching • Recombine ideas • Novel insights • Working memory • Strengthen important • Creative connections • Prune unimportant ``` Research shows that: - **Memory consolidation** happens during sleep - **Creative insights** emerge from random memory replay - **Neural pruning** removes low-value connections - **Analogical reasoning** connects distant concepts SONA's Dream Engine replicates these mechanisms for AI self-improvement. --- ## 2. Dream Engine Architecture ``` ┌─────────────────────────────────────────────────────────────────────┐ │ DREAM ENGINE ARCHITECTURE │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌───────────────┐ │ │ │ MEMORY GRAPH │──────┐ │ │ └───────────────┘ │ │ │ ▼ │ │ ┌─────────────────────────────────────┐ │ │ │ DREAM GENERATOR │ │ │ │ │ │ │ │ ┌─────────┐ ┌─────────┐ │ │ │ │ │ Random │ │Weighted │ │ │ │ │ │ Walks │ │ Sampling│ │ │ │ │ └────┬────┘ └────┬────┘ │ │ │ │ │ │ │ │ │ │ ▼ ▼ │ │ │ │ ┌──────────────────────┐ │ │ │ │ │ Dream Sequence │ │ │ │ │ │ [M₁→M₂→M₃→...→Mₙ] │ │ │ │ │ └──────────┬───────────┘ │ │ │ └─────────────┼───────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────┐ │ │ │ DREAM EVALUATOR │ │ │ │ │ │ │ │ • Novelty Score (new connections?) │ │ │ │ • Coherence Score (makes sense?) │ │ │ │ • Utility Score (useful insight?) │ │ │ └─────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────┐ │ │ │ DREAM INTEGRATOR │ │ │ │ │ │ │ │ • Add weak creative edges │ │ │ │ • Update pattern associations │ │ │ │ • Generate novel hypotheses │ │ │ └─────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` --- ## 3. Dream Generation ### Random Walk Memory Replay ```rust /// Dream generator using random walks on memory graph pub struct DreamGenerator { /// Temperature for random walk (higher = more random) temperature: f32, /// Maximum dream length max_length: usize, /// Minimum coherence threshold min_coherence: f32, /// Creativity bias (prefer novel connections) creativity_bias: f32, } impl DreamGenerator { /// Generate a single dream sequence pub fn generate_dream( &self, memory: &MemoryGraph, start_node: Option, ) -> Dream { let mut sequence = Vec::new(); let mut visited = HashSet::new(); // Start from random high-activation node if not specified let current = start_node.unwrap_or_else(|| { memory.sample_by_activation() }); sequence.push(current); visited.insert(current); // Random walk with creativity-weighted transitions for _ in 0..self.max_length { let neighbors = memory.get_neighbors(current); if neighbors.is_empty() { break; } // Compute transition probabilities let probs: Vec = neighbors.iter() .map(|&(neighbor, edge_weight)| { let novelty_bonus = if visited.contains(&neighbor) { 0.1 // Discourage revisits } else { 1.0 + self.creativity_bias * (1.0 - memory.get_access_frequency(neighbor)) }; (edge_weight * novelty_bonus).powf(1.0 / self.temperature) }) .collect(); // Sample next node let next = sample_weighted(&neighbors, &probs); if let Some((next_node, _)) = next { sequence.push(next_node); visited.insert(next_node); } else { break; } } Dream { sequence, temperature: self.temperature, timestamp: chrono::Utc::now().timestamp(), } } /// Generate creative jump dream (non-local connections) pub fn generate_creative_dream( &self, memory: &MemoryGraph, num_jumps: usize, ) -> Dream { let mut sequence = Vec::new(); // Sample diverse starting points let anchors = memory.sample_diverse(num_jumps, 0.3); for anchor in anchors { sequence.push(anchor); // Short local walk from each anchor let local_walk = self.generate_dream(memory, Some(anchor)); sequence.extend(local_walk.sequence.iter().skip(1).take(3)); } Dream { sequence, temperature: self.temperature * 2.0, // Higher temperature for creative dreams timestamp: chrono::Utc::now().timestamp(), } } } /// A dream sequence pub struct Dream { /// Sequence of visited memory nodes pub sequence: Vec, /// Temperature used for generation pub temperature: f32, /// Generation timestamp pub timestamp: i64, } ``` --- ## 4. Dream Evaluation ### Measuring Dream Quality ```rust /// Evaluator for dream quality pub struct DreamEvaluator { /// Memory graph reference memory: Arc, /// Novelty detection threshold novelty_threshold: f32, } impl DreamEvaluator { /// Evaluate dream quality across multiple dimensions pub fn evaluate(&self, dream: &Dream) -> DreamQuality { DreamQuality { novelty: self.compute_novelty(dream), coherence: self.compute_coherence(dream), utility: self.compute_utility(dream), diversity: self.compute_diversity(dream), } } /// Novelty: How many new connections are suggested? fn compute_novelty(&self, dream: &Dream) -> f32 { let mut novel_pairs = 0; let mut total_pairs = 0; for i in 0..dream.sequence.len() { for j in (i+1)..dream.sequence.len() { total_pairs += 1; let node_a = dream.sequence[i]; let node_b = dream.sequence[j]; // Check if edge exists if !self.memory.has_edge(node_a, node_b) { // Check semantic similarity let emb_a = self.memory.get_embedding(node_a); let emb_b = self.memory.get_embedding(node_b); let sim = cosine_similarity(&emb_a, &emb_b); // Novel = no edge but moderate similarity if sim > 0.3 && sim < 0.8 { novel_pairs += 1; } } } } novel_pairs as f32 / total_pairs.max(1) as f32 } /// Coherence: Does the dream sequence make semantic sense? fn compute_coherence(&self, dream: &Dream) -> f32 { if dream.sequence.len() < 2 { return 1.0; } let mut coherence_sum = 0.0f32; for window in dream.sequence.windows(2) { let emb_a = self.memory.get_embedding(window[0]); let emb_b = self.memory.get_embedding(window[1]); coherence_sum += cosine_similarity(&emb_a, &emb_b); } coherence_sum / (dream.sequence.len() - 1) as f32 } /// Utility: Are the suggested connections potentially useful? fn compute_utility(&self, dream: &Dream) -> f32 { // Based on node quality scores and access patterns let avg_quality: f32 = dream.sequence.iter() .map(|&id| self.memory.get_node_quality(id)) .sum::() / dream.sequence.len() as f32; // Higher utility if connecting high-quality nodes avg_quality } /// Diversity: How diverse are the visited nodes? fn compute_diversity(&self, dream: &Dream) -> f32 { // Average pairwise distance in embedding space let embeddings: Vec<_> = dream.sequence.iter() .map(|&id| self.memory.get_embedding(id)) .collect(); let mut total_dist = 0.0f32; let mut count = 0; for i in 0..embeddings.len() { for j in (i+1)..embeddings.len() { total_dist += 1.0 - cosine_similarity(&embeddings[i], &embeddings[j]); count += 1; } } total_dist / count.max(1) as f32 } } #[derive(Debug, Clone)] pub struct DreamQuality { /// How many novel connections suggested (0-1) pub novelty: f32, /// How semantically coherent (0-1) pub coherence: f32, /// How useful the connections might be (0-1) pub utility: f32, /// How diverse the dream content (0-1) pub diversity: f32, } impl DreamQuality { /// Overall quality score pub fn overall(&self) -> f32 { // Weighted combination favoring novelty and coherence 0.4 * self.novelty + 0.3 * self.coherence + 0.2 * self.utility + 0.1 * self.diversity } /// Is this dream worth integrating? pub fn is_valuable(&self, threshold: f32) -> bool { self.novelty > 0.3 && self.coherence > 0.4 && self.overall() > threshold } } ``` --- ## 5. Dream Integration ### Applying Dream Insights to Memory ```rust /// Integrates valuable dreams into memory graph pub struct DreamIntegrator { /// Memory graph to update memory: Arc>, /// Strength of new creative edges creative_edge_strength: f32, /// Decay factor for dream-derived edges dream_edge_decay: f32, } impl DreamIntegrator { /// Integrate a valuable dream into memory pub fn integrate(&self, dream: &Dream, quality: &DreamQuality) -> IntegrationResult { let mut result = IntegrationResult::default(); if !quality.is_valuable(0.5) { return result; // Skip low-quality dreams } let mut memory = self.memory.write(); // Extract novel connections from dream let novel_connections = self.extract_novel_connections(dream, &memory); for (node_a, node_b, strength) in novel_connections { // Add weak creative edge let edge_strength = self.creative_edge_strength * strength * quality.overall(); memory.add_edge( node_a, node_b, EdgeType::Creative, edge_strength, ); result.edges_added += 1; } // Update node associations based on dream co-occurrence for window in dream.sequence.windows(3) { memory.update_association(window[0], window[2], 0.01); } result.dream_quality = quality.overall(); result } fn extract_novel_connections( &self, dream: &Dream, memory: &MemoryGraph, ) -> Vec<(NodeId, NodeId, f32)> { let mut connections = Vec::new(); for i in 0..dream.sequence.len() { for j in (i+1)..dream.sequence.len().min(i+5) { // Only nearby in sequence let node_a = dream.sequence[i]; let node_b = dream.sequence[j]; if !memory.has_edge(node_a, node_b) { let emb_a = memory.get_embedding(node_a); let emb_b = memory.get_embedding(node_b); let sim = cosine_similarity(&emb_a, &emb_b); if sim > 0.3 { // Connection strength based on similarity and sequence proximity let proximity_factor = 1.0 / (j - i) as f32; let strength = sim * proximity_factor; connections.push((node_a, node_b, strength)); } } } } connections } } #[derive(Default)] pub struct IntegrationResult { pub edges_added: usize, pub associations_updated: usize, pub dream_quality: f32, } ``` --- ## 6. Memory Consolidation ### Strengthening Important Memories ```rust /// Consolidation engine for memory pruning and strengthening pub struct ConsolidationEngine { /// Memory graph reference memory: Arc>, /// Minimum access frequency for retention min_access_frequency: f32, /// Age decay factor (older = more decay) age_decay: f32, /// Quality threshold for preservation quality_threshold: f32, } impl ConsolidationEngine { /// Run full consolidation pass pub fn consolidate(&self) -> ConsolidationReport { let mut report = ConsolidationReport::default(); // Phase 1: Identify memories by value let (high_value, medium_value, low_value) = self.categorize_memories(); report.high_value_count = high_value.len(); report.medium_value_count = medium_value.len(); report.low_value_count = low_value.len(); // Phase 2: Strengthen high-value memories for &node_id in &high_value { self.strengthen_memory(node_id); report.memories_strengthened += 1; } // Phase 3: Decay low-value memories for &node_id in &low_value { let retained = self.decay_memory(node_id); if retained { report.memories_decayed += 1; } else { report.memories_removed += 1; } } // Phase 4: Prune weak edges let pruned = self.prune_weak_edges(); report.edges_pruned = pruned; // Phase 5: Merge similar memories let merged = self.merge_similar_memories(); report.memories_merged = merged; report } fn categorize_memories(&self) -> (Vec, Vec, Vec) { let memory = self.memory.read(); let mut high = Vec::new(); let mut medium = Vec::new(); let mut low = Vec::new(); for node in memory.iter_nodes() { let value_score = self.compute_value_score(node); if value_score > 0.7 { high.push(node.id); } else if value_score > 0.3 { medium.push(node.id); } else { low.push(node.id); } } (high, medium, low) } fn compute_value_score(&self, node: &MemoryNode) -> f32 { let memory = self.memory.read(); // Factors: // 1. Access frequency (more access = more valuable) let freq_score = (node.access_count as f32 / 100.0).min(1.0); // 2. Recency (recent = more valuable) let age_days = (chrono::Utc::now().timestamp() - node.last_accessed) / 86400; let recency_score = (-self.age_decay * age_days as f32).exp(); // 3. Quality (explicit quality score) let quality_score = node.quality_score; // 4. Connectivity (well-connected = more valuable) let degree = memory.node_degree(node.id); let connectivity_score = (degree as f32 / 10.0).min(1.0); // Weighted combination 0.3 * freq_score + 0.2 * recency_score + 0.3 * quality_score + 0.2 * connectivity_score } fn strengthen_memory(&self, node_id: NodeId) { let mut memory = self.memory.write(); // Increase edge weights to this node for edge in memory.get_edges_to(node_id) { memory.update_edge_weight(edge.from, node_id, EdgeUpdate::Multiply(1.1)); } // Mark as consolidated if let Some(node) = memory.get_node_mut(node_id) { node.consolidation_count += 1; node.last_consolidated = chrono::Utc::now().timestamp(); } } fn decay_memory(&self, node_id: NodeId) -> bool { let mut memory = self.memory.write(); // Reduce edge weights for edge in memory.get_edges_to(node_id) { memory.update_edge_weight(edge.from, node_id, EdgeUpdate::Multiply(0.5)); } // Check if node should be removed entirely let total_incoming_weight: f32 = memory.get_edges_to(node_id) .iter() .map(|e| e.weight) .sum(); if total_incoming_weight < 0.01 { // Remove isolated or nearly-isolated node memory.remove_node(node_id); false // Not retained } else { true // Retained but weakened } } fn prune_weak_edges(&self) -> usize { let mut memory = self.memory.write(); let weak_edges: Vec<_> = memory.iter_edges() .filter(|e| e.weight < 0.01) .map(|e| e.id) .collect(); for edge_id in &weak_edges { memory.remove_edge(*edge_id); } weak_edges.len() } fn merge_similar_memories(&self) -> usize { let mut memory = self.memory.write(); let mut merged_count = 0; // Find highly similar node pairs let nodes: Vec<_> = memory.iter_nodes().collect(); for i in 0..nodes.len() { for j in (i+1)..nodes.len() { let sim = cosine_similarity(&nodes[i].embedding, &nodes[j].embedding); if sim > 0.98 { // Merge j into i memory.merge_nodes(nodes[i].id, nodes[j].id); merged_count += 1; } } } merged_count } } #[derive(Default)] pub struct ConsolidationReport { pub high_value_count: usize, pub medium_value_count: usize, pub low_value_count: usize, pub memories_strengthened: usize, pub memories_decayed: usize, pub memories_removed: usize, pub memories_merged: usize, pub edges_pruned: usize, } ``` --- ## 7. Full Dream Cycle ### Orchestrating the Dream Process ```rust /// Complete dream cycle orchestrator pub struct DreamCycle { generator: DreamGenerator, evaluator: DreamEvaluator, integrator: DreamIntegrator, consolidator: ConsolidationEngine, config: DreamCycleConfig, } impl DreamCycle { /// Run complete dream cycle (weekly maintenance) pub async fn run(&self) -> DreamCycleReport { let start = Instant::now(); let mut report = DreamCycleReport::default(); // Phase 1: Generate dreams tracing::info!("Starting dream generation phase"); let dreams = self.generate_dreams(); report.dreams_generated = dreams.len(); // Phase 2: Evaluate dreams tracing::info!("Evaluating {} dreams", dreams.len()); let evaluated: Vec<_> = dreams.iter() .map(|d| (d, self.evaluator.evaluate(d))) .collect(); // Phase 3: Integrate valuable dreams tracing::info!("Integrating valuable dreams"); for (dream, quality) in &evaluated { if quality.is_valuable(self.config.dream_threshold) { let result = self.integrator.integrate(dream, quality); report.edges_added += result.edges_added; report.dreams_integrated += 1; } } // Phase 4: Memory consolidation tracing::info!("Running memory consolidation"); report.consolidation = self.consolidator.consolidate(); report.elapsed_ms = start.elapsed().as_millis() as u64; report.timestamp = chrono::Utc::now().timestamp(); tracing::info!( dreams = report.dreams_generated, integrated = report.dreams_integrated, edges = report.edges_added, elapsed_ms = report.elapsed_ms, "Dream cycle completed" ); report } fn generate_dreams(&self) -> Vec { let mut dreams = Vec::new(); // Regular random walk dreams for _ in 0..self.config.num_regular_dreams { let dream = self.generator.generate_dream(&self.memory, None); dreams.push(dream); } // Creative jump dreams for _ in 0..self.config.num_creative_dreams { let dream = self.generator.generate_creative_dream( &self.memory, self.config.creative_jump_count, ); dreams.push(dream); } dreams } } #[derive(Default)] pub struct DreamCycleReport { pub dreams_generated: usize, pub dreams_integrated: usize, pub edges_added: usize, pub consolidation: ConsolidationReport, pub elapsed_ms: u64, pub timestamp: i64, } ``` --- ## 8. Integration with exo-exotic Dreams Module SONA integrates with the exo-ai-2025 dream experiments: ```rust // From exo-exotic crate use exo_exotic::experiments::dreams::{ DreamExperiment, DreamConfig, NoveltyMeasure, }; impl DreamCycle { /// Run advanced dream experiments from exo-exotic pub async fn run_exotic_dreams(&self) -> ExoticDreamReport { let dream_experiment = DreamExperiment::new(DreamConfig { memory_count: self.memory.node_count(), replay_probability: 0.7, recombination_rate: 0.3, novelty_threshold: 0.5, }); let result = dream_experiment.run(&self.memory).await; ExoticDreamReport { novelty_score: result.novelty, coherence_score: result.coherence, creative_insights: result.insights.len(), new_hypotheses: result.hypotheses, } } } ``` --- ## Summary SONA's Dream Engine enables: | Feature | Mechanism | Outcome | |---------|-----------|---------| | **Memory Replay** | Random walks on memory graph | Strengthens important connections | | **Creative Recombination** | High-temperature sampling | Discovers novel associations | | **Quality Filtering** | Novelty + coherence metrics | Only valuable dreams integrated | | **Weak Edge Creation** | Dream-derived connections | Enables creative retrieval | | **Memory Consolidation** | Value-based pruning | Efficient memory usage | Dreams allow SONA to: 1. **Discover** connections it wouldn't find through normal operation 2. **Explore** the hypothesis space without user cost 3. **Consolidate** valuable knowledge 4. **Prune** low-value information 5. **Remain creative** while staying grounded