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::{AttractorDynamics, AttractorConfig, EnergyLandscape},
44    strange_loop::{MetaCognitiveMinCut, StrangeLoopConfig, MetaAction},
45    causal::{CausalDiscoverySNN, CausalConfig, CausalGraph, GraphEvent, GraphEventType},
46    time_crystal::{TimeCrystalCPG, CPGConfig},
47    morphogenetic::{MorphogeneticSNN, MorphConfig, TuringPattern},
48    optimizer::{NeuralGraphOptimizer, OptimizerConfig, OptimizationResult, GraphAction},
49    SimTime, Spike,
50};
51use crate::graph::{DynamicGraph, VertexId, Weight};
52use std::time::{Duration, Instant};
53use std::collections::HashMap;
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(graph.clone(), config.cpg_config.clone()))
216        } else {
217            None
218        };
219
220        let morphogenetic = if config.enable_morphogenetic {
221            Some(MorphogeneticSNN::new(config.morph_config.clone()))
222        } else {
223            None
224        };
225
226        let optimizer = if config.enable_optimizer {
227            Some(NeuralGraphOptimizer::new(graph.clone(), config.optimizer_config.clone()))
228        } else {
229            None
230        };
231
232        Self {
233            graph,
234            config,
235            attractor,
236            strange_loop,
237            causal,
238            time_crystal,
239            morphogenetic,
240            optimizer,
241            time: 0.0,
242            metrics: EngineMetrics::default(),
243            event_history: Vec::new(),
244            mode: OperationMode::Full,
245        }
246    }
247
248    /// Set operation mode
249    pub fn set_mode(&mut self, mode: OperationMode) {
250        self.mode = mode;
251    }
252
253    /// Run one integration step
254    pub fn step(&mut self) -> Vec<Spike> {
255        let start = Instant::now();
256        let mut all_spikes = Vec::new();
257
258        match self.mode {
259            OperationMode::Optimize => {
260                self.step_optimizer(&mut all_spikes);
261            }
262            OperationMode::CausalDiscovery => {
263                self.step_causal();
264            }
265            OperationMode::Attractor => {
266                self.step_attractor(&mut all_spikes);
267            }
268            OperationMode::Crystal => {
269                self.step_time_crystal();
270            }
271            OperationMode::MetaCognitive => {
272                self.step_strange_loop();
273            }
274            OperationMode::Morphogenetic => {
275                self.step_morphogenetic();
276            }
277            OperationMode::Full => {
278                self.step_full(&mut all_spikes);
279            }
280        }
281
282        self.time += self.config.dt;
283        self.metrics.steps += 1;
284        self.metrics.total_time += start.elapsed();
285        self.metrics.total_spikes += all_spikes.len();
286
287        all_spikes
288    }
289
290    /// Full integration step (all subsystems)
291    fn step_full(&mut self, all_spikes: &mut Vec<Spike>) {
292        // 1. Attractor dynamics (energy landscape)
293        self.step_attractor(all_spikes);
294
295        // 2. Strange loop (meta-cognition)
296        self.step_strange_loop();
297
298        // 3. Time crystal (coordination)
299        self.step_time_crystal();
300
301        // 4. Neural optimizer (learning)
302        self.step_optimizer(all_spikes);
303
304        // 5. Causal discovery (from accumulated events)
305        self.step_causal();
306
307        // 6. Synchronize graph states
308        self.synchronize_graphs();
309
310        // Update energy estimate
311        self.metrics.energy_estimate += all_spikes.len() as f64 * 0.001;
312    }
313
314    /// Step attractor dynamics
315    fn step_attractor(&mut self, spikes: &mut Vec<Spike>) {
316        if let Some(ref mut attractor) = self.attractor {
317            let start = Instant::now();
318            let new_spikes = attractor.step();
319            spikes.extend(new_spikes);
320            self.metrics.attractor_time += start.elapsed();
321            self.metrics.synchrony = attractor.snn().global_synchrony();
322        }
323    }
324
325    /// Step strange loop
326    fn step_strange_loop(&mut self) {
327        if let Some(ref mut sl) = self.strange_loop {
328            let start = Instant::now();
329            let action = sl.strange_loop_step();
330
331            // Record meta-action as event
332            let event = match action {
333                MetaAction::Strengthen(_) => GraphEvent {
334                    event_type: GraphEventType::WeightChange,
335                    vertex: None,
336                    edge: None,
337                    data: 1.0,
338                },
339                MetaAction::Prune(_) => GraphEvent {
340                    event_type: GraphEventType::EdgeDelete,
341                    vertex: None,
342                    edge: None,
343                    data: -1.0,
344                },
345                MetaAction::Restructure => GraphEvent {
346                    event_type: GraphEventType::ComponentMerge,
347                    vertex: None,
348                    edge: None,
349                    data: 0.0,
350                },
351                MetaAction::NoOp => GraphEvent {
352                    event_type: GraphEventType::MinCutChange,
353                    vertex: None,
354                    edge: None,
355                    data: 0.0,
356                },
357            };
358
359            self.event_history.push((event, self.time));
360            self.metrics.strange_loop_time += start.elapsed();
361        }
362    }
363
364    /// Step causal discovery
365    fn step_causal(&mut self) {
366        if let Some(ref mut causal) = self.causal {
367            let start = Instant::now();
368
369            // Process accumulated events
370            for (event, ts) in &self.event_history {
371                causal.observe_event(event.clone(), *ts);
372            }
373            self.event_history.clear();
374
375            self.metrics.causal_time += start.elapsed();
376        }
377    }
378
379    /// Step time crystal CPG
380    fn step_time_crystal(&mut self) {
381        if let Some(ref mut cpg) = self.time_crystal {
382            let start = Instant::now();
383            let _ = cpg.tick();
384            self.metrics.cpg_time += start.elapsed();
385        }
386    }
387
388    /// Step morphogenetic development
389    fn step_morphogenetic(&mut self) {
390        if let Some(ref mut morph) = self.morphogenetic {
391            let start = Instant::now();
392            morph.develop_step();
393            self.metrics.morph_time += start.elapsed();
394        }
395    }
396
397    /// Step neural optimizer
398    fn step_optimizer(&mut self, _spikes: &mut Vec<Spike>) {
399        if let Some(ref mut opt) = self.optimizer {
400            let start = Instant::now();
401            let result = opt.optimize_step();
402
403            // Record optimization action as event
404            let event = match result.action {
405                GraphAction::AddEdge(u, v, _) => GraphEvent {
406                    event_type: GraphEventType::EdgeInsert,
407                    vertex: None,
408                    edge: Some((u, v)),
409                    data: result.reward,
410                },
411                GraphAction::RemoveEdge(u, v) => GraphEvent {
412                    event_type: GraphEventType::EdgeDelete,
413                    vertex: None,
414                    edge: Some((u, v)),
415                    data: result.reward,
416                },
417                _ => GraphEvent {
418                    event_type: GraphEventType::WeightChange,
419                    vertex: None,
420                    edge: None,
421                    data: result.reward,
422                },
423            };
424
425            self.event_history.push((event, self.time));
426            self.metrics.mincut_value = result.new_mincut;
427            self.metrics.optimizer_time += start.elapsed();
428        }
429    }
430
431    /// Synchronize graph states across subsystems
432    fn synchronize_graphs(&mut self) {
433        // Use optimizer's graph as primary
434        if let Some(ref opt) = self.optimizer {
435            self.graph = opt.graph().clone();
436        }
437
438        // Update attractor subsystem with current graph state
439        if let Some(ref mut attractor) = self.attractor {
440            // Create new attractor dynamics with updated graph
441            // This preserves configuration while syncing graph
442            *attractor = AttractorDynamics::new(
443                self.graph.clone(),
444                attractor.config().clone(),
445            );
446        }
447
448        // Limit event history size to prevent memory exhaustion
449        if self.event_history.len() > MAX_EVENT_HISTORY {
450            // Keep only the most recent events
451            let drain_count = self.event_history.len() - MAX_EVENT_HISTORY;
452            self.event_history.drain(..drain_count);
453        }
454    }
455
456    /// Run for specified number of steps
457    pub fn run(&mut self, steps: usize) -> Vec<Spike> {
458        let mut all_spikes = Vec::new();
459
460        for _ in 0..steps {
461            let spikes = self.step();
462            all_spikes.extend(spikes);
463        }
464
465        all_spikes
466    }
467
468    /// Run until convergence or max steps
469    pub fn run_until_converged(&mut self) -> (Vec<Spike>, bool) {
470        let mut all_spikes = Vec::new();
471        let mut prev_energy = f64::MAX;
472        let mut stable_count = 0;
473
474        for _ in 0..self.config.max_steps {
475            let spikes = self.step();
476            all_spikes.extend(spikes);
477
478            let energy = self.current_energy();
479            if (energy - prev_energy).abs() < 0.001 {
480                stable_count += 1;
481                if stable_count > 10 {
482                    return (all_spikes, true);
483                }
484            } else {
485                stable_count = 0;
486            }
487            prev_energy = energy;
488        }
489
490        (all_spikes, false)
491    }
492
493    /// Get current energy
494    pub fn current_energy(&self) -> f64 {
495        if let Some(ref attractor) = self.attractor {
496            attractor.energy()
497        } else {
498            -self.metrics.mincut_value - self.metrics.synchrony
499        }
500    }
501
502    /// Get primary graph
503    pub fn graph(&self) -> &DynamicGraph {
504        &self.graph
505    }
506
507    /// Get mutable graph
508    pub fn graph_mut(&mut self) -> &mut DynamicGraph {
509        &mut self.graph
510    }
511
512    /// Get metrics
513    pub fn metrics(&self) -> &EngineMetrics {
514        &self.metrics
515    }
516
517    /// Get causal graph (if available)
518    pub fn causal_graph(&self) -> Option<CausalGraph> {
519        self.causal.as_ref().map(|c| c.extract_causal_graph())
520    }
521
522    /// Get current phase (from time crystal)
523    pub fn current_phase(&self) -> Option<usize> {
524        self.time_crystal.as_ref().map(|tc| tc.current_phase())
525    }
526
527    /// Get attractor status
528    pub fn at_attractor(&self) -> bool {
529        self.attractor.as_ref().map(|a| a.reached_attractor()).unwrap_or(false)
530    }
531
532    /// Get morphogenetic pattern
533    pub fn pattern(&self) -> Option<TuringPattern> {
534        self.morphogenetic.as_ref().map(|m| m.detect_pattern())
535    }
536
537    /// Get energy landscape
538    pub fn energy_landscape(&self) -> Option<&EnergyLandscape> {
539        self.attractor.as_ref().map(|a| a.energy_landscape())
540    }
541
542    /// Subpolynomial search exploiting all learned structures
543    pub fn search(&self, query: &[f64], k: usize) -> Vec<VertexId> {
544        // Combine skip regions from all subsystems
545        let mut skip_regions = Vec::new();
546
547        // From attractor dynamics
548        if let Some(ref attractor) = self.attractor {
549            let skip = attractor.get_skip_mask();
550            skip_regions.extend(skip.iter().map(|(u, v)| (*u, *v)));
551        }
552
553        // From neural optimizer
554        if let Some(ref opt) = self.optimizer {
555            return opt.search(query, k);
556        }
557
558        // Fallback: return all vertices
559        self.graph.vertices().into_iter().take(k).collect()
560    }
561
562    /// Record external event for causal analysis
563    pub fn record_event(&mut self, event: GraphEvent) {
564        self.event_history.push((event, self.time));
565    }
566
567    /// Reset all subsystems
568    pub fn reset(&mut self) {
569        self.time = 0.0;
570        self.metrics = EngineMetrics::default();
571        self.event_history.clear();
572
573        if let Some(ref mut attractor) = self.attractor {
574            attractor.reset();
575        }
576        if let Some(ref mut sl) = self.strange_loop {
577            sl.reset();
578        }
579        if let Some(ref mut causal) = self.causal {
580            causal.reset();
581        }
582        if let Some(ref mut cpg) = self.time_crystal {
583            cpg.reset();
584        }
585        if let Some(ref mut morph) = self.morphogenetic {
586            morph.reset();
587        }
588        if let Some(ref mut opt) = self.optimizer {
589            opt.reset();
590        }
591    }
592
593    /// Get summary of engine state
594    pub fn summary(&self) -> EngineSummary {
595        EngineSummary {
596            mode: self.mode,
597            time: self.time,
598            graph_vertices: self.graph.num_vertices(),
599            graph_edges: self.graph.num_edges(),
600            mincut: self.metrics.mincut_value,
601            synchrony: self.metrics.synchrony,
602            at_attractor: self.at_attractor(),
603            current_phase: self.current_phase(),
604            pattern: self.pattern(),
605            total_spikes: self.metrics.total_spikes,
606            energy: self.metrics.energy_estimate,
607        }
608    }
609}
610
611/// Summary of engine state
612#[derive(Debug, Clone)]
613pub struct EngineSummary {
614    /// Current operation mode
615    pub mode: OperationMode,
616    /// Simulation time
617    pub time: SimTime,
618    /// Number of graph vertices
619    pub graph_vertices: usize,
620    /// Number of graph edges
621    pub graph_edges: usize,
622    /// Current mincut value
623    pub mincut: f64,
624    /// Global synchrony
625    pub synchrony: f64,
626    /// At attractor?
627    pub at_attractor: bool,
628    /// Current time crystal phase
629    pub current_phase: Option<usize>,
630    /// Morphogenetic pattern
631    pub pattern: Option<TuringPattern>,
632    /// Total spikes generated
633    pub total_spikes: usize,
634    /// Energy estimate
635    pub energy: f64,
636}
637
638#[cfg(test)]
639mod tests {
640    use super::*;
641
642    fn create_test_graph() -> DynamicGraph {
643        let graph = DynamicGraph::new();
644        for i in 0..10 {
645            graph.insert_edge(i, (i + 1) % 10, 1.0).unwrap();
646        }
647        graph
648    }
649
650    #[test]
651    fn test_engine_creation() {
652        let graph = create_test_graph();
653        let config = EngineConfig::default();
654
655        let engine = CognitiveMinCutEngine::new(graph, config);
656
657        assert_eq!(engine.graph().num_vertices(), 10);
658    }
659
660    #[test]
661    fn test_engine_step() {
662        let graph = create_test_graph();
663        let config = EngineConfig::default();
664
665        let mut engine = CognitiveMinCutEngine::new(graph, config);
666        engine.set_mode(OperationMode::Optimize);
667
668        let spikes = engine.step();
669        assert!(engine.metrics().steps == 1);
670    }
671
672    #[test]
673    fn test_engine_run() {
674        let graph = create_test_graph();
675        let mut config = EngineConfig::default();
676        config.enable_morphogenetic = false;  // Expensive
677
678        let mut engine = CognitiveMinCutEngine::new(graph, config);
679
680        let spikes = engine.run(10);
681        assert_eq!(engine.metrics().steps, 10);
682    }
683
684    #[test]
685    fn test_engine_modes() {
686        let graph = create_test_graph();
687        let config = EngineConfig::default();
688
689        let mut engine = CognitiveMinCutEngine::new(graph, config);
690
691        // Test each mode
692        for mode in [
693            OperationMode::Optimize,
694            OperationMode::CausalDiscovery,
695            OperationMode::Attractor,
696            OperationMode::Crystal,
697            OperationMode::MetaCognitive,
698        ] {
699            engine.set_mode(mode);
700            engine.step();
701        }
702    }
703
704    #[test]
705    fn test_engine_summary() {
706        let graph = create_test_graph();
707        let config = EngineConfig::default();
708
709        let mut engine = CognitiveMinCutEngine::new(graph, config);
710        engine.run(5);
711
712        let summary = engine.summary();
713        assert_eq!(summary.graph_vertices, 10);
714        assert!(summary.time > 0.0);
715    }
716
717    #[test]
718    fn test_record_event() {
719        let graph = create_test_graph();
720        let config = EngineConfig::default();
721
722        let mut engine = CognitiveMinCutEngine::new(graph, config);
723
724        engine.record_event(GraphEvent {
725            event_type: GraphEventType::EdgeInsert,
726            vertex: None,
727            edge: Some((0, 5)),
728            data: 1.0,
729        });
730
731        engine.step();
732    }
733}