use super::{
attractor::{AttractorConfig, AttractorDynamics, EnergyLandscape},
causal::{CausalConfig, CausalDiscoverySNN, CausalGraph, GraphEvent, GraphEventType},
morphogenetic::{MorphConfig, MorphogeneticSNN, TuringPattern},
optimizer::{GraphAction, NeuralGraphOptimizer, OptimizationResult, OptimizerConfig},
strange_loop::{MetaAction, MetaCognitiveMinCut, StrangeLoopConfig},
time_crystal::{CPGConfig, TimeCrystalCPG},
SimTime, Spike,
};
use crate::graph::{DynamicGraph, VertexId, Weight};
use std::collections::HashMap;
use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
pub struct EngineConfig {
pub enable_attractors: bool,
pub enable_strange_loop: bool,
pub enable_causal_discovery: bool,
pub enable_time_crystal: bool,
pub enable_morphogenetic: bool,
pub enable_optimizer: bool,
pub attractor_config: AttractorConfig,
pub strange_loop_config: StrangeLoopConfig,
pub causal_config: CausalConfig,
pub cpg_config: CPGConfig,
pub morph_config: MorphConfig,
pub optimizer_config: OptimizerConfig,
pub dt: f64,
pub max_steps: usize,
}
impl Default for EngineConfig {
fn default() -> Self {
Self {
enable_attractors: true,
enable_strange_loop: true,
enable_causal_discovery: true,
enable_time_crystal: true,
enable_morphogenetic: false, enable_optimizer: true,
attractor_config: AttractorConfig::default(),
strange_loop_config: StrangeLoopConfig::default(),
causal_config: CausalConfig::default(),
cpg_config: CPGConfig::default(),
morph_config: MorphConfig::default(),
optimizer_config: OptimizerConfig::default(),
dt: 1.0,
max_steps: 1000,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct EngineMetrics {
pub total_time: Duration,
pub attractor_time: Duration,
pub strange_loop_time: Duration,
pub causal_time: Duration,
pub cpg_time: Duration,
pub morph_time: Duration,
pub optimizer_time: Duration,
pub total_spikes: usize,
pub energy_estimate: f64,
pub mincut_value: f64,
pub synchrony: f64,
pub steps: usize,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OperationMode {
Optimize,
CausalDiscovery,
Attractor,
Crystal,
MetaCognitive,
Morphogenetic,
Full,
}
const MAX_EVENT_HISTORY: usize = 10_000;
pub struct CognitiveMinCutEngine {
graph: DynamicGraph,
config: EngineConfig,
attractor: Option<AttractorDynamics>,
strange_loop: Option<MetaCognitiveMinCut>,
causal: Option<CausalDiscoverySNN>,
time_crystal: Option<TimeCrystalCPG>,
morphogenetic: Option<MorphogeneticSNN>,
optimizer: Option<NeuralGraphOptimizer>,
time: SimTime,
metrics: EngineMetrics,
event_history: Vec<(GraphEvent, SimTime)>,
mode: OperationMode,
}
impl CognitiveMinCutEngine {
pub fn new(graph: DynamicGraph, config: EngineConfig) -> Self {
let attractor = if config.enable_attractors {
Some(AttractorDynamics::new(
graph.clone(),
config.attractor_config.clone(),
))
} else {
None
};
let strange_loop = if config.enable_strange_loop {
let mut sl_config = config.strange_loop_config.clone();
sl_config.level0_size = graph.num_vertices();
Some(MetaCognitiveMinCut::new(graph.clone(), sl_config))
} else {
None
};
let causal = if config.enable_causal_discovery {
Some(CausalDiscoverySNN::new(config.causal_config.clone()))
} else {
None
};
let time_crystal = if config.enable_time_crystal {
Some(TimeCrystalCPG::new(
graph.clone(),
config.cpg_config.clone(),
))
} else {
None
};
let morphogenetic = if config.enable_morphogenetic {
Some(MorphogeneticSNN::new(config.morph_config.clone()))
} else {
None
};
let optimizer = if config.enable_optimizer {
Some(NeuralGraphOptimizer::new(
graph.clone(),
config.optimizer_config.clone(),
))
} else {
None
};
Self {
graph,
config,
attractor,
strange_loop,
causal,
time_crystal,
morphogenetic,
optimizer,
time: 0.0,
metrics: EngineMetrics::default(),
event_history: Vec::new(),
mode: OperationMode::Full,
}
}
pub fn set_mode(&mut self, mode: OperationMode) {
self.mode = mode;
}
pub fn step(&mut self) -> Vec<Spike> {
let start = Instant::now();
let mut all_spikes = Vec::new();
match self.mode {
OperationMode::Optimize => {
self.step_optimizer(&mut all_spikes);
}
OperationMode::CausalDiscovery => {
self.step_causal();
}
OperationMode::Attractor => {
self.step_attractor(&mut all_spikes);
}
OperationMode::Crystal => {
self.step_time_crystal();
}
OperationMode::MetaCognitive => {
self.step_strange_loop();
}
OperationMode::Morphogenetic => {
self.step_morphogenetic();
}
OperationMode::Full => {
self.step_full(&mut all_spikes);
}
}
self.time += self.config.dt;
self.metrics.steps += 1;
self.metrics.total_time += start.elapsed();
self.metrics.total_spikes += all_spikes.len();
all_spikes
}
fn step_full(&mut self, all_spikes: &mut Vec<Spike>) {
self.step_attractor(all_spikes);
self.step_strange_loop();
self.step_time_crystal();
self.step_optimizer(all_spikes);
self.step_causal();
self.synchronize_graphs();
self.metrics.energy_estimate += all_spikes.len() as f64 * 0.001;
}
fn step_attractor(&mut self, spikes: &mut Vec<Spike>) {
if let Some(ref mut attractor) = self.attractor {
let start = Instant::now();
let new_spikes = attractor.step();
spikes.extend(new_spikes);
self.metrics.attractor_time += start.elapsed();
self.metrics.synchrony = attractor.snn().global_synchrony();
}
}
fn step_strange_loop(&mut self) {
if let Some(ref mut sl) = self.strange_loop {
let start = Instant::now();
let action = sl.strange_loop_step();
let event = match action {
MetaAction::Strengthen(_) => GraphEvent {
event_type: GraphEventType::WeightChange,
vertex: None,
edge: None,
data: 1.0,
},
MetaAction::Prune(_) => GraphEvent {
event_type: GraphEventType::EdgeDelete,
vertex: None,
edge: None,
data: -1.0,
},
MetaAction::Restructure => GraphEvent {
event_type: GraphEventType::ComponentMerge,
vertex: None,
edge: None,
data: 0.0,
},
MetaAction::NoOp => GraphEvent {
event_type: GraphEventType::MinCutChange,
vertex: None,
edge: None,
data: 0.0,
},
};
self.event_history.push((event, self.time));
self.metrics.strange_loop_time += start.elapsed();
}
}
fn step_causal(&mut self) {
if let Some(ref mut causal) = self.causal {
let start = Instant::now();
for (event, ts) in &self.event_history {
causal.observe_event(event.clone(), *ts);
}
self.event_history.clear();
self.metrics.causal_time += start.elapsed();
}
}
fn step_time_crystal(&mut self) {
if let Some(ref mut cpg) = self.time_crystal {
let start = Instant::now();
let _ = cpg.tick();
self.metrics.cpg_time += start.elapsed();
}
}
fn step_morphogenetic(&mut self) {
if let Some(ref mut morph) = self.morphogenetic {
let start = Instant::now();
morph.develop_step();
self.metrics.morph_time += start.elapsed();
}
}
fn step_optimizer(&mut self, _spikes: &mut Vec<Spike>) {
if let Some(ref mut opt) = self.optimizer {
let start = Instant::now();
let result = opt.optimize_step();
let event = match result.action {
GraphAction::AddEdge(u, v, _) => GraphEvent {
event_type: GraphEventType::EdgeInsert,
vertex: None,
edge: Some((u, v)),
data: result.reward,
},
GraphAction::RemoveEdge(u, v) => GraphEvent {
event_type: GraphEventType::EdgeDelete,
vertex: None,
edge: Some((u, v)),
data: result.reward,
},
_ => GraphEvent {
event_type: GraphEventType::WeightChange,
vertex: None,
edge: None,
data: result.reward,
},
};
self.event_history.push((event, self.time));
self.metrics.mincut_value = result.new_mincut;
self.metrics.optimizer_time += start.elapsed();
}
}
fn synchronize_graphs(&mut self) {
if let Some(ref opt) = self.optimizer {
self.graph = opt.graph().clone();
}
if let Some(ref mut attractor) = self.attractor {
*attractor = AttractorDynamics::new(self.graph.clone(), attractor.config().clone());
}
if self.event_history.len() > MAX_EVENT_HISTORY {
let drain_count = self.event_history.len() - MAX_EVENT_HISTORY;
self.event_history.drain(..drain_count);
}
}
pub fn run(&mut self, steps: usize) -> Vec<Spike> {
let mut all_spikes = Vec::new();
for _ in 0..steps {
let spikes = self.step();
all_spikes.extend(spikes);
}
all_spikes
}
pub fn run_until_converged(&mut self) -> (Vec<Spike>, bool) {
let mut all_spikes = Vec::new();
let mut prev_energy = f64::MAX;
let mut stable_count = 0;
for _ in 0..self.config.max_steps {
let spikes = self.step();
all_spikes.extend(spikes);
let energy = self.current_energy();
if (energy - prev_energy).abs() < 0.001 {
stable_count += 1;
if stable_count > 10 {
return (all_spikes, true);
}
} else {
stable_count = 0;
}
prev_energy = energy;
}
(all_spikes, false)
}
pub fn current_energy(&self) -> f64 {
if let Some(ref attractor) = self.attractor {
attractor.energy()
} else {
-self.metrics.mincut_value - self.metrics.synchrony
}
}
pub fn graph(&self) -> &DynamicGraph {
&self.graph
}
pub fn graph_mut(&mut self) -> &mut DynamicGraph {
&mut self.graph
}
pub fn metrics(&self) -> &EngineMetrics {
&self.metrics
}
pub fn causal_graph(&self) -> Option<CausalGraph> {
self.causal.as_ref().map(|c| c.extract_causal_graph())
}
pub fn current_phase(&self) -> Option<usize> {
self.time_crystal.as_ref().map(|tc| tc.current_phase())
}
pub fn at_attractor(&self) -> bool {
self.attractor
.as_ref()
.map(|a| a.reached_attractor())
.unwrap_or(false)
}
pub fn pattern(&self) -> Option<TuringPattern> {
self.morphogenetic.as_ref().map(|m| m.detect_pattern())
}
pub fn energy_landscape(&self) -> Option<&EnergyLandscape> {
self.attractor.as_ref().map(|a| a.energy_landscape())
}
pub fn search(&self, query: &[f64], k: usize) -> Vec<VertexId> {
let mut skip_regions = Vec::new();
if let Some(ref attractor) = self.attractor {
let skip = attractor.get_skip_mask();
skip_regions.extend(skip.iter().map(|(u, v)| (*u, *v)));
}
if let Some(ref opt) = self.optimizer {
return opt.search(query, k);
}
self.graph.vertices().into_iter().take(k).collect()
}
pub fn record_event(&mut self, event: GraphEvent) {
self.event_history.push((event, self.time));
}
pub fn reset(&mut self) {
self.time = 0.0;
self.metrics = EngineMetrics::default();
self.event_history.clear();
if let Some(ref mut attractor) = self.attractor {
attractor.reset();
}
if let Some(ref mut sl) = self.strange_loop {
sl.reset();
}
if let Some(ref mut causal) = self.causal {
causal.reset();
}
if let Some(ref mut cpg) = self.time_crystal {
cpg.reset();
}
if let Some(ref mut morph) = self.morphogenetic {
morph.reset();
}
if let Some(ref mut opt) = self.optimizer {
opt.reset();
}
}
pub fn summary(&self) -> EngineSummary {
EngineSummary {
mode: self.mode,
time: self.time,
graph_vertices: self.graph.num_vertices(),
graph_edges: self.graph.num_edges(),
mincut: self.metrics.mincut_value,
synchrony: self.metrics.synchrony,
at_attractor: self.at_attractor(),
current_phase: self.current_phase(),
pattern: self.pattern(),
total_spikes: self.metrics.total_spikes,
energy: self.metrics.energy_estimate,
}
}
}
#[derive(Debug, Clone)]
pub struct EngineSummary {
pub mode: OperationMode,
pub time: SimTime,
pub graph_vertices: usize,
pub graph_edges: usize,
pub mincut: f64,
pub synchrony: f64,
pub at_attractor: bool,
pub current_phase: Option<usize>,
pub pattern: Option<TuringPattern>,
pub total_spikes: usize,
pub energy: f64,
}
#[cfg(test)]
mod tests {
use super::*;
fn create_test_graph() -> DynamicGraph {
let graph = DynamicGraph::new();
for i in 0..10 {
graph.insert_edge(i, (i + 1) % 10, 1.0).unwrap();
}
graph
}
#[test]
fn test_engine_creation() {
let graph = create_test_graph();
let config = EngineConfig::default();
let engine = CognitiveMinCutEngine::new(graph, config);
assert_eq!(engine.graph().num_vertices(), 10);
}
#[test]
fn test_engine_step() {
let graph = create_test_graph();
let config = EngineConfig::default();
let mut engine = CognitiveMinCutEngine::new(graph, config);
engine.set_mode(OperationMode::Optimize);
let spikes = engine.step();
assert!(engine.metrics().steps == 1);
}
#[test]
fn test_engine_run() {
let graph = create_test_graph();
let mut config = EngineConfig::default();
config.enable_morphogenetic = false;
let mut engine = CognitiveMinCutEngine::new(graph, config);
let spikes = engine.run(10);
assert_eq!(engine.metrics().steps, 10);
}
#[test]
fn test_engine_modes() {
let graph = create_test_graph();
let config = EngineConfig::default();
let mut engine = CognitiveMinCutEngine::new(graph, config);
for mode in [
OperationMode::Optimize,
OperationMode::CausalDiscovery,
OperationMode::Attractor,
OperationMode::Crystal,
OperationMode::MetaCognitive,
] {
engine.set_mode(mode);
engine.step();
}
}
#[test]
fn test_engine_summary() {
let graph = create_test_graph();
let config = EngineConfig::default();
let mut engine = CognitiveMinCutEngine::new(graph, config);
engine.run(5);
let summary = engine.summary();
assert_eq!(summary.graph_vertices, 10);
assert!(summary.time > 0.0);
}
#[test]
fn test_record_event() {
let graph = create_test_graph();
let config = EngineConfig::default();
let mut engine = CognitiveMinCutEngine::new(graph, config);
engine.record_event(GraphEvent {
event_type: GraphEventType::EdgeInsert,
vertex: None,
edge: Some((0, 5)),
data: 1.0,
});
engine.step();
}
}