1use 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#[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(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 pub fn set_mode(&mut self, mode: OperationMode) {
250 self.mode = mode;
251 }
252
253 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 fn step_full(&mut self, all_spikes: &mut Vec<Spike>) {
292 self.step_attractor(all_spikes);
294
295 self.step_strange_loop();
297
298 self.step_time_crystal();
300
301 self.step_optimizer(all_spikes);
303
304 self.step_causal();
306
307 self.synchronize_graphs();
309
310 self.metrics.energy_estimate += all_spikes.len() as f64 * 0.001;
312 }
313
314 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 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 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 fn step_causal(&mut self) {
366 if let Some(ref mut causal) = self.causal {
367 let start = Instant::now();
368
369 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 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 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 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 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 fn synchronize_graphs(&mut self) {
433 if let Some(ref opt) = self.optimizer {
435 self.graph = opt.graph().clone();
436 }
437
438 if let Some(ref mut attractor) = self.attractor {
440 *attractor = AttractorDynamics::new(
443 self.graph.clone(),
444 attractor.config().clone(),
445 );
446 }
447
448 if self.event_history.len() > MAX_EVENT_HISTORY {
450 let drain_count = self.event_history.len() - MAX_EVENT_HISTORY;
452 self.event_history.drain(..drain_count);
453 }
454 }
455
456 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 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 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 pub fn graph(&self) -> &DynamicGraph {
504 &self.graph
505 }
506
507 pub fn graph_mut(&mut self) -> &mut DynamicGraph {
509 &mut self.graph
510 }
511
512 pub fn metrics(&self) -> &EngineMetrics {
514 &self.metrics
515 }
516
517 pub fn causal_graph(&self) -> Option<CausalGraph> {
519 self.causal.as_ref().map(|c| c.extract_causal_graph())
520 }
521
522 pub fn current_phase(&self) -> Option<usize> {
524 self.time_crystal.as_ref().map(|tc| tc.current_phase())
525 }
526
527 pub fn at_attractor(&self) -> bool {
529 self.attractor.as_ref().map(|a| a.reached_attractor()).unwrap_or(false)
530 }
531
532 pub fn pattern(&self) -> Option<TuringPattern> {
534 self.morphogenetic.as_ref().map(|m| m.detect_pattern())
535 }
536
537 pub fn energy_landscape(&self) -> Option<&EnergyLandscape> {
539 self.attractor.as_ref().map(|a| a.energy_landscape())
540 }
541
542 pub fn search(&self, query: &[f64], k: usize) -> Vec<VertexId> {
544 let mut skip_regions = Vec::new();
546
547 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 if let Some(ref opt) = self.optimizer {
555 return opt.search(query, k);
556 }
557
558 self.graph.vertices().into_iter().take(k).collect()
560 }
561
562 pub fn record_event(&mut self, event: GraphEvent) {
564 self.event_history.push((event, self.time));
565 }
566
567 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 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#[derive(Debug, Clone)]
613pub struct EngineSummary {
614 pub mode: OperationMode,
616 pub time: SimTime,
618 pub graph_vertices: usize,
620 pub graph_edges: usize,
622 pub mincut: f64,
624 pub synchrony: f64,
626 pub at_attractor: bool,
628 pub current_phase: Option<usize>,
630 pub pattern: Option<TuringPattern>,
632 pub total_spikes: usize,
634 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; 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 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}