1use 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#[derive(Debug, Clone)]
57pub struct EngineConfig {
58 pub enable_attractors: bool,
60 pub enable_strange_loop: bool,
62 pub enable_causal_discovery: bool,
64 pub enable_time_crystal: bool,
66 pub enable_morphogenetic: bool,
68 pub enable_optimizer: bool,
70 pub attractor_config: AttractorConfig,
72 pub strange_loop_config: StrangeLoopConfig,
74 pub causal_config: CausalConfig,
76 pub cpg_config: CPGConfig,
78 pub morph_config: MorphConfig,
80 pub optimizer_config: OptimizerConfig,
82 pub dt: f64,
84 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, 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#[derive(Debug, Clone, Default)]
111pub struct EngineMetrics {
112 pub total_time: Duration,
114 pub attractor_time: Duration,
116 pub strange_loop_time: Duration,
118 pub causal_time: Duration,
120 pub cpg_time: Duration,
122 pub morph_time: Duration,
124 pub optimizer_time: Duration,
126 pub total_spikes: usize,
128 pub energy_estimate: f64,
130 pub mincut_value: f64,
132 pub synchrony: f64,
134 pub steps: usize,
136}
137
138#[derive(Debug, Clone, Copy, PartialEq)]
140pub enum OperationMode {
141 Optimize,
143 CausalDiscovery,
145 Attractor,
147 Crystal,
149 MetaCognitive,
151 Morphogenetic,
153 Full,
155}
156
157const MAX_EVENT_HISTORY: usize = 10_000;
159
160pub struct CognitiveMinCutEngine {
162 graph: DynamicGraph,
164 config: EngineConfig,
166 attractor: Option<AttractorDynamics>,
168 strange_loop: Option<MetaCognitiveMinCut>,
170 causal: Option<CausalDiscoverySNN>,
172 time_crystal: Option<TimeCrystalCPG>,
174 morphogenetic: Option<MorphogeneticSNN>,
176 optimizer: Option<NeuralGraphOptimizer>,
178 time: SimTime,
180 metrics: EngineMetrics,
182 event_history: Vec<(GraphEvent, SimTime)>,
184 mode: OperationMode,
186}
187
188impl CognitiveMinCutEngine {
189 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 pub fn set_mode(&mut self, mode: OperationMode) {
256 self.mode = mode;
257 }
258
259 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 fn step_full(&mut self, all_spikes: &mut Vec<Spike>) {
298 self.step_attractor(all_spikes);
300
301 self.step_strange_loop();
303
304 self.step_time_crystal();
306
307 self.step_optimizer(all_spikes);
309
310 self.step_causal();
312
313 self.synchronize_graphs();
315
316 self.metrics.energy_estimate += all_spikes.len() as f64 * 0.001;
318 }
319
320 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 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 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 fn step_causal(&mut self) {
372 if let Some(ref mut causal) = self.causal {
373 let start = Instant::now();
374
375 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 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 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 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 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 fn synchronize_graphs(&mut self) {
439 if let Some(ref opt) = self.optimizer {
441 self.graph = opt.graph().clone();
442 }
443
444 if let Some(ref mut attractor) = self.attractor {
446 *attractor = AttractorDynamics::new(self.graph.clone(), attractor.config().clone());
449 }
450
451 if self.event_history.len() > MAX_EVENT_HISTORY {
453 let drain_count = self.event_history.len() - MAX_EVENT_HISTORY;
455 self.event_history.drain(..drain_count);
456 }
457 }
458
459 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 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 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 pub fn graph(&self) -> &DynamicGraph {
507 &self.graph
508 }
509
510 pub fn graph_mut(&mut self) -> &mut DynamicGraph {
512 &mut self.graph
513 }
514
515 pub fn metrics(&self) -> &EngineMetrics {
517 &self.metrics
518 }
519
520 pub fn causal_graph(&self) -> Option<CausalGraph> {
522 self.causal.as_ref().map(|c| c.extract_causal_graph())
523 }
524
525 pub fn current_phase(&self) -> Option<usize> {
527 self.time_crystal.as_ref().map(|tc| tc.current_phase())
528 }
529
530 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 pub fn pattern(&self) -> Option<TuringPattern> {
540 self.morphogenetic.as_ref().map(|m| m.detect_pattern())
541 }
542
543 pub fn energy_landscape(&self) -> Option<&EnergyLandscape> {
545 self.attractor.as_ref().map(|a| a.energy_landscape())
546 }
547
548 pub fn search(&self, query: &[f64], k: usize) -> Vec<VertexId> {
550 let mut skip_regions = Vec::new();
552
553 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 if let Some(ref opt) = self.optimizer {
561 return opt.search(query, k);
562 }
563
564 self.graph.vertices().into_iter().take(k).collect()
566 }
567
568 pub fn record_event(&mut self, event: GraphEvent) {
570 self.event_history.push((event, self.time));
571 }
572
573 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 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#[derive(Debug, Clone)]
619pub struct EngineSummary {
620 pub mode: OperationMode,
622 pub time: SimTime,
624 pub graph_vertices: usize,
626 pub graph_edges: usize,
628 pub mincut: f64,
630 pub synchrony: f64,
632 pub at_attractor: bool,
634 pub current_phase: Option<usize>,
636 pub pattern: Option<TuringPattern>,
638 pub total_spikes: usize,
640 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; 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 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}