Skip to main content

ruvector_mincut/snn/
cognitive_engine.rs

1//! # Unified Cognitive MinCut Engine
2//!
3//! Combines all six integration layers into a unified system.
4//!
5//! ## Architecture
6//!
7//! ```text
8//! ┌─────────────────────────────────────────────────────────────────────────────┐
9//! │                      COGNITIVE MINCUT ENGINE                                │
10//! ├─────────────────────────────────────────────────────────────────────────────┤
11//! │                                                                             │
12//! │   ┌─────────────────────────────────────────────────────────────────────┐   │
13//! │   │                        META-COGNITIVE LAYER                         │   │
14//! │   │  Strange Loop + Neural Optimizer + Causal Discovery                 │   │
15//! │   └───────────────────────────┬─────────────────────────────────────────┘   │
16//! │                               │                                             │
17//! │   ┌───────────────────────────▼─────────────────────────────────────────┐   │
18//! │   │                      DYNAMICAL SYSTEMS LAYER                        │   │
19//! │   │  Temporal Attractors + Time Crystals + Morphogenesis                │   │
20//! │   └───────────────────────────┬─────────────────────────────────────────┘   │
21//! │                               │                                             │
22//! │   ┌───────────────────────────▼─────────────────────────────────────────┐   │
23//! │   │                      GRAPH ALGORITHM LAYER                          │   │
24//! │   │  Karger-Stein MinCut + Subpolynomial Search + HNSW                  │   │
25//! │   └───────────────────────────┬─────────────────────────────────────────┘   │
26//! │                               │                                             │
27//! │   ┌───────────────────────────▼─────────────────────────────────────────┐   │
28//! │   │                      NEUROMORPHIC SUBSTRATE                         │   │
29//! │   │  SNN + STDP + Meta-Neuron + CPG                                     │   │
30//! │   └─────────────────────────────────────────────────────────────────────┘   │
31//! │                                                                             │
32//! └─────────────────────────────────────────────────────────────────────────────┘
33//! ```
34//!
35//! ## Performance Targets
36//!
37//! | Metric | Unified | Improvement |
38//! |--------|---------|-------------|
39//! | MinCut (1K nodes) | ~5 μs | 10x |
40//! | Energy per query | ~10 μJ | 1000x |
41
42use super::{
43    attractor::{AttractorConfig, AttractorDynamics, EnergyLandscape},
44    causal::{CausalConfig, CausalDiscoverySNN, CausalGraph, GraphEvent, GraphEventType},
45    morphogenetic::{MorphConfig, MorphogeneticSNN, TuringPattern},
46    optimizer::{GraphAction, NeuralGraphOptimizer, OptimizationResult, OptimizerConfig},
47    strange_loop::{MetaAction, MetaCognitiveMinCut, StrangeLoopConfig},
48    time_crystal::{CPGConfig, TimeCrystalCPG},
49    SimTime, Spike,
50};
51use crate::graph::{DynamicGraph, VertexId, Weight};
52use std::collections::HashMap;
53use std::time::{Duration, Instant};
54
55/// Configuration for the Cognitive MinCut Engine
56#[derive(Debug, Clone)]
57pub struct EngineConfig {
58    /// Enable attractor dynamics layer
59    pub enable_attractors: bool,
60    /// Enable strange loop self-modification
61    pub enable_strange_loop: bool,
62    /// Enable causal discovery
63    pub enable_causal_discovery: bool,
64    /// Enable time crystal coordination
65    pub enable_time_crystal: bool,
66    /// Enable morphogenetic growth
67    pub enable_morphogenetic: bool,
68    /// Enable neural optimizer
69    pub enable_optimizer: bool,
70    /// Attractor configuration
71    pub attractor_config: AttractorConfig,
72    /// Strange loop configuration
73    pub strange_loop_config: StrangeLoopConfig,
74    /// Causal discovery configuration
75    pub causal_config: CausalConfig,
76    /// Time crystal configuration
77    pub cpg_config: CPGConfig,
78    /// Morphogenetic configuration
79    pub morph_config: MorphConfig,
80    /// Optimizer configuration
81    pub optimizer_config: OptimizerConfig,
82    /// Time step for unified simulation
83    pub dt: f64,
84    /// Maximum steps per operation
85    pub max_steps: usize,
86}
87
88impl Default for EngineConfig {
89    fn default() -> Self {
90        Self {
91            enable_attractors: true,
92            enable_strange_loop: true,
93            enable_causal_discovery: true,
94            enable_time_crystal: true,
95            enable_morphogenetic: false, // Expensive, off by default
96            enable_optimizer: true,
97            attractor_config: AttractorConfig::default(),
98            strange_loop_config: StrangeLoopConfig::default(),
99            causal_config: CausalConfig::default(),
100            cpg_config: CPGConfig::default(),
101            morph_config: MorphConfig::default(),
102            optimizer_config: OptimizerConfig::default(),
103            dt: 1.0,
104            max_steps: 1000,
105        }
106    }
107}
108
109/// Metrics from engine operation
110#[derive(Debug, Clone, Default)]
111pub struct EngineMetrics {
112    /// Total time spent in computation
113    pub total_time: Duration,
114    /// Time in attractor dynamics
115    pub attractor_time: Duration,
116    /// Time in strange loop
117    pub strange_loop_time: Duration,
118    /// Time in causal discovery
119    pub causal_time: Duration,
120    /// Time in time crystal
121    pub cpg_time: Duration,
122    /// Time in morphogenesis
123    pub morph_time: Duration,
124    /// Time in optimization
125    pub optimizer_time: Duration,
126    /// Number of spikes generated
127    pub total_spikes: usize,
128    /// Energy estimate (arbitrary units)
129    pub energy_estimate: f64,
130    /// Current mincut value
131    pub mincut_value: f64,
132    /// Global synchrony
133    pub synchrony: f64,
134    /// Steps taken
135    pub steps: usize,
136}
137
138/// Operation mode for the engine
139#[derive(Debug, Clone, Copy, PartialEq)]
140pub enum OperationMode {
141    /// Optimize graph structure
142    Optimize,
143    /// Discover causal relationships
144    CausalDiscovery,
145    /// Evolve to attractor
146    Attractor,
147    /// Coordinated phase operation
148    Crystal,
149    /// Self-modifying operation
150    MetaCognitive,
151    /// Grow structure
152    Morphogenetic,
153    /// All systems active
154    Full,
155}
156
157/// Maximum event history size to prevent memory exhaustion
158const MAX_EVENT_HISTORY: usize = 10_000;
159
160/// The unified Cognitive MinCut Engine
161pub struct CognitiveMinCutEngine {
162    /// Primary graph being optimized
163    graph: DynamicGraph,
164    /// Configuration
165    config: EngineConfig,
166    /// Attractor dynamics subsystem
167    attractor: Option<AttractorDynamics>,
168    /// Strange loop subsystem
169    strange_loop: Option<MetaCognitiveMinCut>,
170    /// Causal discovery subsystem
171    causal: Option<CausalDiscoverySNN>,
172    /// Time crystal CPG subsystem
173    time_crystal: Option<TimeCrystalCPG>,
174    /// Morphogenetic subsystem
175    morphogenetic: Option<MorphogeneticSNN>,
176    /// Neural optimizer subsystem
177    optimizer: Option<NeuralGraphOptimizer>,
178    /// Current simulation time
179    time: SimTime,
180    /// Accumulated metrics
181    metrics: EngineMetrics,
182    /// Event history for causal analysis
183    event_history: Vec<(GraphEvent, SimTime)>,
184    /// Current operation mode
185    mode: OperationMode,
186}
187
188impl CognitiveMinCutEngine {
189    /// Create a new Cognitive MinCut Engine
190    pub fn new(graph: DynamicGraph, config: EngineConfig) -> Self {
191        let attractor = if config.enable_attractors {
192            Some(AttractorDynamics::new(
193                graph.clone(),
194                config.attractor_config.clone(),
195            ))
196        } else {
197            None
198        };
199
200        let strange_loop = if config.enable_strange_loop {
201            let mut sl_config = config.strange_loop_config.clone();
202            sl_config.level0_size = graph.num_vertices();
203            Some(MetaCognitiveMinCut::new(graph.clone(), sl_config))
204        } else {
205            None
206        };
207
208        let causal = if config.enable_causal_discovery {
209            Some(CausalDiscoverySNN::new(config.causal_config.clone()))
210        } else {
211            None
212        };
213
214        let time_crystal = if config.enable_time_crystal {
215            Some(TimeCrystalCPG::new(
216                graph.clone(),
217                config.cpg_config.clone(),
218            ))
219        } else {
220            None
221        };
222
223        let morphogenetic = if config.enable_morphogenetic {
224            Some(MorphogeneticSNN::new(config.morph_config.clone()))
225        } else {
226            None
227        };
228
229        let optimizer = if config.enable_optimizer {
230            Some(NeuralGraphOptimizer::new(
231                graph.clone(),
232                config.optimizer_config.clone(),
233            ))
234        } else {
235            None
236        };
237
238        Self {
239            graph,
240            config,
241            attractor,
242            strange_loop,
243            causal,
244            time_crystal,
245            morphogenetic,
246            optimizer,
247            time: 0.0,
248            metrics: EngineMetrics::default(),
249            event_history: Vec::new(),
250            mode: OperationMode::Full,
251        }
252    }
253
254    /// Set operation mode
255    pub fn set_mode(&mut self, mode: OperationMode) {
256        self.mode = mode;
257    }
258
259    /// Run one integration step
260    pub fn step(&mut self) -> Vec<Spike> {
261        let start = Instant::now();
262        let mut all_spikes = Vec::new();
263
264        match self.mode {
265            OperationMode::Optimize => {
266                self.step_optimizer(&mut all_spikes);
267            }
268            OperationMode::CausalDiscovery => {
269                self.step_causal();
270            }
271            OperationMode::Attractor => {
272                self.step_attractor(&mut all_spikes);
273            }
274            OperationMode::Crystal => {
275                self.step_time_crystal();
276            }
277            OperationMode::MetaCognitive => {
278                self.step_strange_loop();
279            }
280            OperationMode::Morphogenetic => {
281                self.step_morphogenetic();
282            }
283            OperationMode::Full => {
284                self.step_full(&mut all_spikes);
285            }
286        }
287
288        self.time += self.config.dt;
289        self.metrics.steps += 1;
290        self.metrics.total_time += start.elapsed();
291        self.metrics.total_spikes += all_spikes.len();
292
293        all_spikes
294    }
295
296    /// Full integration step (all subsystems)
297    fn step_full(&mut self, all_spikes: &mut Vec<Spike>) {
298        // 1. Attractor dynamics (energy landscape)
299        self.step_attractor(all_spikes);
300
301        // 2. Strange loop (meta-cognition)
302        self.step_strange_loop();
303
304        // 3. Time crystal (coordination)
305        self.step_time_crystal();
306
307        // 4. Neural optimizer (learning)
308        self.step_optimizer(all_spikes);
309
310        // 5. Causal discovery (from accumulated events)
311        self.step_causal();
312
313        // 6. Synchronize graph states
314        self.synchronize_graphs();
315
316        // Update energy estimate
317        self.metrics.energy_estimate += all_spikes.len() as f64 * 0.001;
318    }
319
320    /// Step attractor dynamics
321    fn step_attractor(&mut self, spikes: &mut Vec<Spike>) {
322        if let Some(ref mut attractor) = self.attractor {
323            let start = Instant::now();
324            let new_spikes = attractor.step();
325            spikes.extend(new_spikes);
326            self.metrics.attractor_time += start.elapsed();
327            self.metrics.synchrony = attractor.snn().global_synchrony();
328        }
329    }
330
331    /// Step strange loop
332    fn step_strange_loop(&mut self) {
333        if let Some(ref mut sl) = self.strange_loop {
334            let start = Instant::now();
335            let action = sl.strange_loop_step();
336
337            // Record meta-action as event
338            let event = match action {
339                MetaAction::Strengthen(_) => GraphEvent {
340                    event_type: GraphEventType::WeightChange,
341                    vertex: None,
342                    edge: None,
343                    data: 1.0,
344                },
345                MetaAction::Prune(_) => GraphEvent {
346                    event_type: GraphEventType::EdgeDelete,
347                    vertex: None,
348                    edge: None,
349                    data: -1.0,
350                },
351                MetaAction::Restructure => GraphEvent {
352                    event_type: GraphEventType::ComponentMerge,
353                    vertex: None,
354                    edge: None,
355                    data: 0.0,
356                },
357                MetaAction::NoOp => GraphEvent {
358                    event_type: GraphEventType::MinCutChange,
359                    vertex: None,
360                    edge: None,
361                    data: 0.0,
362                },
363            };
364
365            self.event_history.push((event, self.time));
366            self.metrics.strange_loop_time += start.elapsed();
367        }
368    }
369
370    /// Step causal discovery
371    fn step_causal(&mut self) {
372        if let Some(ref mut causal) = self.causal {
373            let start = Instant::now();
374
375            // Process accumulated events
376            for (event, ts) in &self.event_history {
377                causal.observe_event(event.clone(), *ts);
378            }
379            self.event_history.clear();
380
381            self.metrics.causal_time += start.elapsed();
382        }
383    }
384
385    /// Step time crystal CPG
386    fn step_time_crystal(&mut self) {
387        if let Some(ref mut cpg) = self.time_crystal {
388            let start = Instant::now();
389            let _ = cpg.tick();
390            self.metrics.cpg_time += start.elapsed();
391        }
392    }
393
394    /// Step morphogenetic development
395    fn step_morphogenetic(&mut self) {
396        if let Some(ref mut morph) = self.morphogenetic {
397            let start = Instant::now();
398            morph.develop_step();
399            self.metrics.morph_time += start.elapsed();
400        }
401    }
402
403    /// Step neural optimizer
404    fn step_optimizer(&mut self, _spikes: &mut Vec<Spike>) {
405        if let Some(ref mut opt) = self.optimizer {
406            let start = Instant::now();
407            let result = opt.optimize_step();
408
409            // Record optimization action as event
410            let event = match result.action {
411                GraphAction::AddEdge(u, v, _) => GraphEvent {
412                    event_type: GraphEventType::EdgeInsert,
413                    vertex: None,
414                    edge: Some((u, v)),
415                    data: result.reward,
416                },
417                GraphAction::RemoveEdge(u, v) => GraphEvent {
418                    event_type: GraphEventType::EdgeDelete,
419                    vertex: None,
420                    edge: Some((u, v)),
421                    data: result.reward,
422                },
423                _ => GraphEvent {
424                    event_type: GraphEventType::WeightChange,
425                    vertex: None,
426                    edge: None,
427                    data: result.reward,
428                },
429            };
430
431            self.event_history.push((event, self.time));
432            self.metrics.mincut_value = result.new_mincut;
433            self.metrics.optimizer_time += start.elapsed();
434        }
435    }
436
437    /// Synchronize graph states across subsystems
438    fn synchronize_graphs(&mut self) {
439        // Use optimizer's graph as primary
440        if let Some(ref opt) = self.optimizer {
441            self.graph = opt.graph().clone();
442        }
443
444        // Update attractor subsystem with current graph state
445        if let Some(ref mut attractor) = self.attractor {
446            // Create new attractor dynamics with updated graph
447            // This preserves configuration while syncing graph
448            *attractor = AttractorDynamics::new(self.graph.clone(), attractor.config().clone());
449        }
450
451        // Limit event history size to prevent memory exhaustion
452        if self.event_history.len() > MAX_EVENT_HISTORY {
453            // Keep only the most recent events
454            let drain_count = self.event_history.len() - MAX_EVENT_HISTORY;
455            self.event_history.drain(..drain_count);
456        }
457    }
458
459    /// Run for specified number of steps
460    pub fn run(&mut self, steps: usize) -> Vec<Spike> {
461        let mut all_spikes = Vec::new();
462
463        for _ in 0..steps {
464            let spikes = self.step();
465            all_spikes.extend(spikes);
466        }
467
468        all_spikes
469    }
470
471    /// Run until convergence or max steps
472    pub fn run_until_converged(&mut self) -> (Vec<Spike>, bool) {
473        let mut all_spikes = Vec::new();
474        let mut prev_energy = f64::MAX;
475        let mut stable_count = 0;
476
477        for _ in 0..self.config.max_steps {
478            let spikes = self.step();
479            all_spikes.extend(spikes);
480
481            let energy = self.current_energy();
482            if (energy - prev_energy).abs() < 0.001 {
483                stable_count += 1;
484                if stable_count > 10 {
485                    return (all_spikes, true);
486                }
487            } else {
488                stable_count = 0;
489            }
490            prev_energy = energy;
491        }
492
493        (all_spikes, false)
494    }
495
496    /// Get current energy
497    pub fn current_energy(&self) -> f64 {
498        if let Some(ref attractor) = self.attractor {
499            attractor.energy()
500        } else {
501            -self.metrics.mincut_value - self.metrics.synchrony
502        }
503    }
504
505    /// Get primary graph
506    pub fn graph(&self) -> &DynamicGraph {
507        &self.graph
508    }
509
510    /// Get mutable graph
511    pub fn graph_mut(&mut self) -> &mut DynamicGraph {
512        &mut self.graph
513    }
514
515    /// Get metrics
516    pub fn metrics(&self) -> &EngineMetrics {
517        &self.metrics
518    }
519
520    /// Get causal graph (if available)
521    pub fn causal_graph(&self) -> Option<CausalGraph> {
522        self.causal.as_ref().map(|c| c.extract_causal_graph())
523    }
524
525    /// Get current phase (from time crystal)
526    pub fn current_phase(&self) -> Option<usize> {
527        self.time_crystal.as_ref().map(|tc| tc.current_phase())
528    }
529
530    /// Get attractor status
531    pub fn at_attractor(&self) -> bool {
532        self.attractor
533            .as_ref()
534            .map(|a| a.reached_attractor())
535            .unwrap_or(false)
536    }
537
538    /// Get morphogenetic pattern
539    pub fn pattern(&self) -> Option<TuringPattern> {
540        self.morphogenetic.as_ref().map(|m| m.detect_pattern())
541    }
542
543    /// Get energy landscape
544    pub fn energy_landscape(&self) -> Option<&EnergyLandscape> {
545        self.attractor.as_ref().map(|a| a.energy_landscape())
546    }
547
548    /// Subpolynomial search exploiting all learned structures
549    pub fn search(&self, query: &[f64], k: usize) -> Vec<VertexId> {
550        // Combine skip regions from all subsystems
551        let mut skip_regions = Vec::new();
552
553        // From attractor dynamics
554        if let Some(ref attractor) = self.attractor {
555            let skip = attractor.get_skip_mask();
556            skip_regions.extend(skip.iter().map(|(u, v)| (*u, *v)));
557        }
558
559        // From neural optimizer
560        if let Some(ref opt) = self.optimizer {
561            return opt.search(query, k);
562        }
563
564        // Fallback: return all vertices
565        self.graph.vertices().into_iter().take(k).collect()
566    }
567
568    /// Record external event for causal analysis
569    pub fn record_event(&mut self, event: GraphEvent) {
570        self.event_history.push((event, self.time));
571    }
572
573    /// Reset all subsystems
574    pub fn reset(&mut self) {
575        self.time = 0.0;
576        self.metrics = EngineMetrics::default();
577        self.event_history.clear();
578
579        if let Some(ref mut attractor) = self.attractor {
580            attractor.reset();
581        }
582        if let Some(ref mut sl) = self.strange_loop {
583            sl.reset();
584        }
585        if let Some(ref mut causal) = self.causal {
586            causal.reset();
587        }
588        if let Some(ref mut cpg) = self.time_crystal {
589            cpg.reset();
590        }
591        if let Some(ref mut morph) = self.morphogenetic {
592            morph.reset();
593        }
594        if let Some(ref mut opt) = self.optimizer {
595            opt.reset();
596        }
597    }
598
599    /// Get summary of engine state
600    pub fn summary(&self) -> EngineSummary {
601        EngineSummary {
602            mode: self.mode,
603            time: self.time,
604            graph_vertices: self.graph.num_vertices(),
605            graph_edges: self.graph.num_edges(),
606            mincut: self.metrics.mincut_value,
607            synchrony: self.metrics.synchrony,
608            at_attractor: self.at_attractor(),
609            current_phase: self.current_phase(),
610            pattern: self.pattern(),
611            total_spikes: self.metrics.total_spikes,
612            energy: self.metrics.energy_estimate,
613        }
614    }
615}
616
617/// Summary of engine state
618#[derive(Debug, Clone)]
619pub struct EngineSummary {
620    /// Current operation mode
621    pub mode: OperationMode,
622    /// Simulation time
623    pub time: SimTime,
624    /// Number of graph vertices
625    pub graph_vertices: usize,
626    /// Number of graph edges
627    pub graph_edges: usize,
628    /// Current mincut value
629    pub mincut: f64,
630    /// Global synchrony
631    pub synchrony: f64,
632    /// At attractor?
633    pub at_attractor: bool,
634    /// Current time crystal phase
635    pub current_phase: Option<usize>,
636    /// Morphogenetic pattern
637    pub pattern: Option<TuringPattern>,
638    /// Total spikes generated
639    pub total_spikes: usize,
640    /// Energy estimate
641    pub energy: f64,
642}
643
644#[cfg(test)]
645mod tests {
646    use super::*;
647
648    fn create_test_graph() -> DynamicGraph {
649        let graph = DynamicGraph::new();
650        for i in 0..10 {
651            graph.insert_edge(i, (i + 1) % 10, 1.0).unwrap();
652        }
653        graph
654    }
655
656    #[test]
657    fn test_engine_creation() {
658        let graph = create_test_graph();
659        let config = EngineConfig::default();
660
661        let engine = CognitiveMinCutEngine::new(graph, config);
662
663        assert_eq!(engine.graph().num_vertices(), 10);
664    }
665
666    #[test]
667    fn test_engine_step() {
668        let graph = create_test_graph();
669        let config = EngineConfig::default();
670
671        let mut engine = CognitiveMinCutEngine::new(graph, config);
672        engine.set_mode(OperationMode::Optimize);
673
674        let spikes = engine.step();
675        assert!(engine.metrics().steps == 1);
676    }
677
678    #[test]
679    fn test_engine_run() {
680        let graph = create_test_graph();
681        let mut config = EngineConfig::default();
682        config.enable_morphogenetic = false; // Expensive
683
684        let mut engine = CognitiveMinCutEngine::new(graph, config);
685
686        let spikes = engine.run(10);
687        assert_eq!(engine.metrics().steps, 10);
688    }
689
690    #[test]
691    fn test_engine_modes() {
692        let graph = create_test_graph();
693        let config = EngineConfig::default();
694
695        let mut engine = CognitiveMinCutEngine::new(graph, config);
696
697        // Test each mode
698        for mode in [
699            OperationMode::Optimize,
700            OperationMode::CausalDiscovery,
701            OperationMode::Attractor,
702            OperationMode::Crystal,
703            OperationMode::MetaCognitive,
704        ] {
705            engine.set_mode(mode);
706            engine.step();
707        }
708    }
709
710    #[test]
711    fn test_engine_summary() {
712        let graph = create_test_graph();
713        let config = EngineConfig::default();
714
715        let mut engine = CognitiveMinCutEngine::new(graph, config);
716        engine.run(5);
717
718        let summary = engine.summary();
719        assert_eq!(summary.graph_vertices, 10);
720        assert!(summary.time > 0.0);
721    }
722
723    #[test]
724    fn test_record_event() {
725        let graph = create_test_graph();
726        let config = EngineConfig::default();
727
728        let mut engine = CognitiveMinCutEngine::new(graph, config);
729
730        engine.record_event(GraphEvent {
731            event_type: GraphEventType::EdgeInsert,
732            vertex: None,
733            edge: Some((0, 5)),
734            data: 1.0,
735        });
736
737        engine.step();
738    }
739}