//! Integrated Coherence Benchmarks for Prime-Radiant //! //! End-to-end benchmarks combining all modules: //! - Full coherence pipeline (topology -> spectral -> causal -> decision) //! - Memory usage profiling //! - Throughput measurements //! - Scalability analysis //! //! Target metrics: //! - End-to-end coherence: < 50ms for 1K entities //! - Memory overhead: < 100MB for 10K entities //! - Throughput: > 100 decisions/second use criterion::{ black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput, }; use std::collections::HashMap; use std::time::Instant; // ============================================================================ // INTEGRATED COHERENCE ENGINE // ============================================================================ /// Entity in the coherence graph #[derive(Clone, Debug)] struct Entity { id: usize, state: Vec, beliefs: Vec, } /// A belief with confidence #[derive(Clone, Debug)] struct Belief { content: String, confidence: f64, source_id: usize, } /// Constraint between entities #[derive(Clone, Debug)] struct Constraint { source: usize, target: usize, weight: f64, restriction_map: Vec>, } /// Coherence decision #[derive(Clone, Debug)] pub enum CoherenceDecision { Accept { confidence: f64 }, Reject { reason: String, energy: f64 }, Defer { required_evidence: Vec }, } /// Full coherence computation result #[derive(Clone, Debug)] pub struct CoherenceResult { /// Total coherence energy (lower is better) pub total_energy: f64, /// Topological coherence (from cohomology) pub topological_energy: f64, /// Spectral coherence (from eigenvalues) pub spectral_energy: f64, /// Causal coherence (from intervention consistency) pub causal_energy: f64, /// Betti numbers pub betti: Vec, /// Spectral gap pub spectral_gap: f64, /// Final decision pub decision: CoherenceDecision, } /// Integrated coherence engine struct CoherenceEngine { entities: Vec, constraints: Vec, /// Thresholds for decision making accept_threshold: f64, reject_threshold: f64, } impl CoherenceEngine { fn new() -> Self { Self { entities: Vec::new(), constraints: Vec::new(), accept_threshold: 0.1, reject_threshold: 1.0, } } fn add_entity(&mut self, state_dim: usize) -> usize { let id = self.entities.len(); let entity = Entity { id, state: vec![0.0; state_dim], beliefs: Vec::new(), }; self.entities.push(entity); id } fn set_state(&mut self, id: usize, state: Vec) { if id < self.entities.len() { self.entities[id].state = state; } } fn add_constraint(&mut self, source: usize, target: usize, weight: f64) { let dim = if source < self.entities.len() { self.entities[source].state.len() } else { 16 }; // Identity restriction map let restriction_map: Vec> = (0..dim) .map(|i| { let mut row = vec![0.0; dim]; row[i] = 1.0; row }) .collect(); self.constraints.push(Constraint { source, target, weight, restriction_map, }); } /// Compute full coherence fn compute_coherence(&self) -> CoherenceResult { // 1. Topological coherence via coboundary computation let topological_energy = self.compute_topological_energy(); // 2. Spectral coherence via Laplacian eigenvalues let (spectral_energy, spectral_gap) = self.compute_spectral_coherence(); // 3. Causal coherence via intervention consistency let causal_energy = self.compute_causal_energy(); // 4. Combined energy let total_energy = topological_energy + spectral_energy + causal_energy; // 5. Betti numbers approximation let betti = self.compute_betti_numbers(); // 6. Decision let decision = if total_energy < self.accept_threshold { CoherenceDecision::Accept { confidence: 1.0 - total_energy / self.accept_threshold, } } else if total_energy > self.reject_threshold { CoherenceDecision::Reject { reason: "Energy exceeds rejection threshold".to_string(), energy: total_energy, } } else { CoherenceDecision::Defer { required_evidence: vec!["Additional context needed".to_string()], } }; CoherenceResult { total_energy, topological_energy, spectral_energy, causal_energy, betti, spectral_gap, decision, } } fn compute_topological_energy(&self) -> f64 { let mut energy = 0.0; // Compute residuals at each constraint (coboundary) for constraint in &self.constraints { if constraint.source >= self.entities.len() || constraint.target >= self.entities.len() { continue; } let source_state = &self.entities[constraint.source].state; let target_state = &self.entities[constraint.target].state; // Apply restriction map let restricted_source = self.apply_restriction(&constraint.restriction_map, source_state); // Residual = rho(source) - target let mut residual_sq = 0.0; for (rs, ts) in restricted_source.iter().zip(target_state.iter()) { let diff = rs - ts; residual_sq += diff * diff; } energy += constraint.weight * residual_sq; } energy } fn apply_restriction(&self, map: &[Vec], state: &[f64]) -> Vec { map.iter() .map(|row| { row.iter() .zip(state.iter()) .map(|(a, b)| a * b) .sum() }) .collect() } fn compute_spectral_coherence(&self) -> (f64, f64) { let n = self.entities.len(); if n == 0 { return (0.0, 0.0); } // Build Laplacian let mut laplacian = vec![vec![0.0; n]; n]; let mut degrees = vec![0.0; n]; for constraint in &self.constraints { if constraint.source < n && constraint.target < n { let w = constraint.weight; laplacian[constraint.source][constraint.target] -= w; laplacian[constraint.target][constraint.source] -= w; degrees[constraint.source] += w; degrees[constraint.target] += w; } } for i in 0..n { laplacian[i][i] = degrees[i]; } // Power iteration for largest eigenvalue let mut v: Vec = (0..n).map(|i| ((i + 1) as f64).sqrt().sin()).collect(); let norm: f64 = v.iter().map(|x| x * x).sum::().sqrt(); for x in &mut v { *x /= norm; } let mut lambda_max = 0.0; for _ in 0..50 { let mut y = vec![0.0; n]; for i in 0..n { for j in 0..n { y[i] += laplacian[i][j] * v[j]; } } lambda_max = v.iter().zip(y.iter()).map(|(a, b)| a * b).sum(); let norm: f64 = y.iter().map(|x| x * x).sum::().sqrt(); if norm > 1e-10 { v = y.iter().map(|x| x / norm).collect(); } } // Estimate spectral gap (lambda_2 / lambda_max) let spectral_gap = if n > 1 { 0.1 } else { 1.0 }; // Simplified // Spectral energy based on eigenvalue distribution let spectral_energy = if lambda_max > 0.0 { (lambda_max - degrees.iter().sum::() / n as f64).abs() } else { 0.0 }; (spectral_energy * 0.01, spectral_gap) } fn compute_causal_energy(&self) -> f64 { // Check if state updates are consistent with causal ordering // Simplified: measure variance in state transitions let mut energy = 0.0; let mut count = 0; for constraint in &self.constraints { if constraint.source >= self.entities.len() || constraint.target >= self.entities.len() { continue; } let source_state = &self.entities[constraint.source].state; let target_state = &self.entities[constraint.target].state; // Causal consistency: target should be "downstream" of source let source_norm: f64 = source_state.iter().map(|x| x * x).sum(); let target_norm: f64 = target_state.iter().map(|x| x * x).sum(); // Penalize if target has unexplained variance if target_norm > source_norm * 1.5 { energy += (target_norm - source_norm * 1.5) * 0.1; } count += 1; } if count > 0 { energy / count as f64 } else { 0.0 } } fn compute_betti_numbers(&self) -> Vec { let n = self.entities.len(); let m = self.constraints.len(); // Very rough approximation // Betti_0 = connected components // Betti_1 = independent cycles let betti_0 = if n > m { n - m } else { 1 }; let betti_1 = if m > n { m - n } else { 0 }; vec![betti_0.max(1), betti_1] } } // ============================================================================ // STREAMING COHERENCE PROCESSOR // ============================================================================ /// Incremental coherence updates struct StreamingCoherence { engine: CoherenceEngine, /// Cache for incremental updates residual_cache: HashMap<(usize, usize), f64>, /// Rolling energy window energy_history: Vec, history_window: usize, } impl StreamingCoherence { fn new(history_window: usize) -> Self { Self { engine: CoherenceEngine::new(), residual_cache: HashMap::new(), energy_history: Vec::new(), history_window, } } fn update_entity(&mut self, id: usize, state: Vec) -> f64 { self.engine.set_state(id, state); // Compute incremental energy delta let mut delta = 0.0; for constraint in &self.engine.constraints { if constraint.source == id || constraint.target == id { let old_residual = self.residual_cache .get(&(constraint.source, constraint.target)) .copied() .unwrap_or(0.0); let new_residual = self.compute_residual(constraint); delta += (new_residual - old_residual).abs(); self.residual_cache .insert((constraint.source, constraint.target), new_residual); } } // Update history self.energy_history.push(delta); if self.energy_history.len() > self.history_window { self.energy_history.remove(0); } delta } fn compute_residual(&self, constraint: &Constraint) -> f64 { if constraint.source >= self.engine.entities.len() || constraint.target >= self.engine.entities.len() { return 0.0; } let source = &self.engine.entities[constraint.source].state; let target = &self.engine.entities[constraint.target].state; let restricted = self.engine.apply_restriction(&constraint.restriction_map, source); let mut residual_sq = 0.0; for (r, t) in restricted.iter().zip(target.iter()) { let diff = r - t; residual_sq += diff * diff; } constraint.weight * residual_sq } fn get_trend(&self) -> f64 { if self.energy_history.len() < 2 { return 0.0; } let n = self.energy_history.len(); let recent = &self.energy_history[(n / 2)..]; let older = &self.energy_history[..(n / 2)]; let recent_avg: f64 = recent.iter().sum::() / recent.len() as f64; let older_avg: f64 = older.iter().sum::() / older.len().max(1) as f64; recent_avg - older_avg } } // ============================================================================ // BATCH COHERENCE PROCESSOR // ============================================================================ /// Batch processing for high throughput struct BatchCoherence { batch_size: usize, pending: Vec<(usize, Vec)>, engine: CoherenceEngine, } impl BatchCoherence { fn new(batch_size: usize) -> Self { Self { batch_size, pending: Vec::new(), engine: CoherenceEngine::new(), } } fn add_update(&mut self, id: usize, state: Vec) -> Option> { self.pending.push((id, state)); if self.pending.len() >= self.batch_size { Some(self.process_batch()) } else { None } } fn process_batch(&mut self) -> Vec { let mut results = Vec::with_capacity(self.pending.len()); for (id, state) in &self.pending { self.engine.set_state(*id, state.clone()); results.push(self.engine.compute_coherence()); } self.pending.clear(); results } fn flush(&mut self) -> Vec { self.process_batch() } } // ============================================================================ // MEMORY PROFILING // ============================================================================ struct MemoryProfile { entity_bytes: usize, constraint_bytes: usize, cache_bytes: usize, total_bytes: usize, } fn estimate_memory(engine: &CoherenceEngine) -> MemoryProfile { let entity_bytes: usize = engine.entities.iter() .map(|e| { std::mem::size_of::() + e.state.len() * std::mem::size_of::() + e.beliefs.len() * std::mem::size_of::() }) .sum(); let constraint_bytes: usize = engine.constraints.iter() .map(|c| { std::mem::size_of::() + c.restriction_map.len() * c.restriction_map.get(0).map(|r| r.len()).unwrap_or(0) * std::mem::size_of::() }) .sum(); let cache_bytes = 0; // Would include residual cache if implemented let total_bytes = entity_bytes + constraint_bytes + cache_bytes + std::mem::size_of::(); MemoryProfile { entity_bytes, constraint_bytes, cache_bytes, total_bytes, } } // ============================================================================ // DATA GENERATORS // ============================================================================ fn generate_coherence_graph(num_entities: usize, avg_degree: usize, state_dim: usize) -> CoherenceEngine { let mut engine = CoherenceEngine::new(); // Add entities for i in 0..num_entities { let id = engine.add_entity(state_dim); let state: Vec = (0..state_dim) .map(|j| ((i * state_dim + j) as f64 * 0.1).sin()) .collect(); engine.set_state(id, state); } // Add constraints with random-ish pattern let mut rng_state = 42u64; for i in 0..num_entities { for _ in 0..avg_degree { rng_state = rng_state.wrapping_mul(6364136223846793005).wrapping_add(1); let j = (rng_state as usize) % num_entities; if i != j { let weight = ((rng_state >> 32) as f64 / (u32::MAX as f64)) * 0.9 + 0.1; engine.add_constraint(i, j, weight); } } } engine } fn generate_hierarchical_graph( num_levels: usize, branching: usize, state_dim: usize, ) -> CoherenceEngine { let mut engine = CoherenceEngine::new(); let mut level_nodes: Vec> = Vec::new(); // Create hierarchical structure for level in 0..num_levels { let num_nodes = branching.pow(level as u32); let mut nodes = Vec::new(); for i in 0..num_nodes { let id = engine.add_entity(state_dim); let state: Vec = (0..state_dim) .map(|j| ((level * 1000 + i * state_dim + j) as f64 * 0.1).sin()) .collect(); engine.set_state(id, state); nodes.push(id); } // Connect to parent level if level > 0 { for (i, &node) in nodes.iter().enumerate() { let parent_idx = i / branching; if parent_idx < level_nodes[level - 1].len() { let parent = level_nodes[level - 1][parent_idx]; engine.add_constraint(parent, node, 1.0); } } } level_nodes.push(nodes); } engine } // ============================================================================ // BENCHMARKS // ============================================================================ fn bench_end_to_end_coherence(c: &mut Criterion) { let mut group = c.benchmark_group("integrated/end_to_end"); group.sample_size(20); for &num_entities in &[100, 500, 1000, 2000] { let engine = generate_coherence_graph(num_entities, 5, 32); group.throughput(Throughput::Elements(num_entities as u64)); group.bench_with_input( BenchmarkId::new("full_coherence", num_entities), &engine, |b, engine| { b.iter(|| black_box(engine.compute_coherence())) }, ); } group.finish(); } fn bench_component_breakdown(c: &mut Criterion) { let mut group = c.benchmark_group("integrated/components"); group.sample_size(30); for &num_entities in &[500, 1000, 2000] { let engine = generate_coherence_graph(num_entities, 5, 32); group.throughput(Throughput::Elements(num_entities as u64)); group.bench_with_input( BenchmarkId::new("topological", num_entities), &engine, |b, engine| { b.iter(|| black_box(engine.compute_topological_energy())) }, ); group.bench_with_input( BenchmarkId::new("spectral", num_entities), &engine, |b, engine| { b.iter(|| black_box(engine.compute_spectral_coherence())) }, ); group.bench_with_input( BenchmarkId::new("causal", num_entities), &engine, |b, engine| { b.iter(|| black_box(engine.compute_causal_energy())) }, ); } group.finish(); } fn bench_streaming_updates(c: &mut Criterion) { let mut group = c.benchmark_group("integrated/streaming"); group.sample_size(50); for &num_entities in &[500, 1000, 2000] { let base_engine = generate_coherence_graph(num_entities, 5, 32); group.throughput(Throughput::Elements(100)); // 100 updates per iteration group.bench_with_input( BenchmarkId::new("incremental_updates", num_entities), &num_entities, |b, &n| { b.iter_batched( || { let mut streaming = StreamingCoherence::new(100); streaming.engine = generate_coherence_graph(n, 5, 32); streaming }, |mut streaming| { for i in 0..100 { let state: Vec = (0..32) .map(|j| ((i * 32 + j) as f64 * 0.01).sin()) .collect(); black_box(streaming.update_entity(i % n, state)); } }, criterion::BatchSize::SmallInput, ) }, ); } group.finish(); } fn bench_batch_throughput(c: &mut Criterion) { let mut group = c.benchmark_group("integrated/batch_throughput"); group.sample_size(20); for &batch_size in &[10, 50, 100, 200] { let num_entities = 1000; group.throughput(Throughput::Elements(batch_size as u64)); group.bench_with_input( BenchmarkId::new("process_batch", batch_size), &batch_size, |b, &batch_size| { b.iter_batched( || { let mut batch = BatchCoherence::new(batch_size); batch.engine = generate_coherence_graph(num_entities, 5, 32); // Pre-fill pending for i in 0..(batch_size - 1) { let state: Vec = (0..32) .map(|j| ((i * 32 + j) as f64 * 0.01).cos()) .collect(); batch.pending.push((i % num_entities, state)); } batch }, |mut batch| { let state: Vec = (0..32).map(|j| (j as f64 * 0.02).sin()).collect(); black_box(batch.add_update(0, state)) }, criterion::BatchSize::SmallInput, ) }, ); } group.finish(); } fn bench_hierarchical_coherence(c: &mut Criterion) { let mut group = c.benchmark_group("integrated/hierarchical"); group.sample_size(20); for &(levels, branching) in &[(3, 4), (4, 3), (5, 2), (4, 4)] { let engine = generate_hierarchical_graph(levels, branching, 32); let total_nodes: usize = (0..levels).map(|l| branching.pow(l as u32)).sum(); group.throughput(Throughput::Elements(total_nodes as u64)); group.bench_with_input( BenchmarkId::new(format!("{}L_{}B", levels, branching), total_nodes), &engine, |b, engine| { b.iter(|| black_box(engine.compute_coherence())) }, ); } group.finish(); } fn bench_memory_scaling(c: &mut Criterion) { let mut group = c.benchmark_group("integrated/memory"); group.sample_size(10); for &num_entities in &[1000, 5000, 10000] { group.bench_with_input( BenchmarkId::new("estimate_memory", num_entities), &num_entities, |b, &n| { b.iter_batched( || generate_coherence_graph(n, 5, 32), |engine| black_box(estimate_memory(&engine)), criterion::BatchSize::LargeInput, ) }, ); } group.finish(); } fn bench_decision_throughput(c: &mut Criterion) { let mut group = c.benchmark_group("integrated/decision_throughput"); group.sample_size(50); let engine = generate_coherence_graph(1000, 5, 32); group.throughput(Throughput::Elements(1000)); group.bench_function("decisions_per_second", |b| { b.iter(|| { let mut count = 0; for _ in 0..1000 { let result = engine.compute_coherence(); match result.decision { CoherenceDecision::Accept { .. } => count += 1, CoherenceDecision::Reject { .. } => count += 1, CoherenceDecision::Defer { .. } => count += 1, } } black_box(count) }) }); group.finish(); } fn bench_scalability(c: &mut Criterion) { let mut group = c.benchmark_group("integrated/scalability"); group.sample_size(10); // Test scaling with both entities and constraints for &(entities, avg_degree) in &[(500, 3), (500, 10), (1000, 3), (1000, 10), (2000, 5)] { let engine = generate_coherence_graph(entities, avg_degree, 32); let total_constraints = engine.constraints.len(); group.throughput(Throughput::Elements((entities + total_constraints) as u64)); group.bench_with_input( BenchmarkId::new(format!("{}e_{}d", entities, avg_degree), entities), &engine, |b, engine| { b.iter(|| black_box(engine.compute_coherence())) }, ); } group.finish(); } criterion_group!( benches, bench_end_to_end_coherence, bench_component_breakdown, bench_streaming_updates, bench_batch_throughput, bench_hierarchical_coherence, bench_memory_scaling, bench_decision_throughput, bench_scalability, ); criterion_main!(benches);