use ruvector_domain_expansion::{
ArmId, ContextBucket, Domain, DomainEmbedding, DomainExpansionEngine, DomainId, Evaluation,
Solution, Task,
};
use serde_json::json;
use uuid::Uuid;
use crate::collective::{CollectiveConsciousness, SubstrateSpecialization};
use crate::emergence::EmergenceDetector;
use crate::strange_loops::StrangeLoop;
pub struct StrangeLoopDomain {
id: DomainId,
#[allow(dead_code)]
strange_loop: StrangeLoop,
}
impl StrangeLoopDomain {
pub fn new(max_depth: usize) -> Self {
Self {
id: DomainId("strange_loop".to_string()),
strange_loop: StrangeLoop::new(max_depth),
}
}
fn score_content(content: &str) -> f32 {
let refs = content.matches("self").count()
+ content.matches("meta").count()
+ content.matches("loop").count();
(refs as f32 / 5.0).min(1.0)
}
}
impl Domain for StrangeLoopDomain {
fn id(&self) -> &DomainId {
&self.id
}
fn name(&self) -> &str {
"Strange Loop Self-Reference"
}
fn generate_tasks(&self, count: usize, difficulty: f32) -> Vec<Task> {
let max_depth = (difficulty * 4.0).round() as usize;
(0..count)
.map(|i| Task {
id: format!("sl_{:05}", i),
domain_id: self.id.clone(),
difficulty,
spec: json!({ "depth": max_depth, "variant": i % 3 }),
constraints: vec!["content_must_self_reference".to_string()],
})
.collect()
}
fn evaluate(&self, task: &Task, solution: &Solution) -> Evaluation {
let score = Self::score_content(&solution.content);
let efficiency = (1.0 - task.difficulty * 0.3).max(0.0);
let depth = task.spec.get("depth").and_then(|v| v.as_u64()).unwrap_or(0);
let mut eval = Evaluation::composite(score, efficiency, score * 0.9);
eval.constraint_results = vec![score > 0.0];
eval.notes = vec![format!("depth={} score={:.3}", depth, score)];
eval
}
fn embed(&self, solution: &Solution) -> DomainEmbedding {
let score = Self::score_content(&solution.content);
let mut v = vec![0.0f32; 64];
v[0] = score;
v[1] = 1.0 - score;
let depth = solution
.data
.get("depth")
.and_then(|d| d.as_u64())
.unwrap_or(0);
if depth < 2 {
v[5] = 1.0;
} else if depth < 4 {
v[6] = 1.0;
} else {
v[7] = 1.0;
}
for i in 8..64 {
v[i] = (score * i as f32 * std::f32::consts::PI / 64.0).sin().abs() * 0.5;
}
DomainEmbedding::new(v, self.id.clone())
}
fn embedding_dim(&self) -> usize {
64
}
fn reference_solution(&self, task: &Task) -> Option<Solution> {
let depth = task.spec.get("depth").and_then(|v| v.as_u64()).unwrap_or(0) as usize;
Some(Solution {
task_id: task.id.clone(),
content: format!(
"self-meta-loop: I observe my self-model at meta-depth {}",
depth
),
data: json!({ "depth": depth, "self_reference": true, "meta_level": depth }),
})
}
}
pub struct CollectiveDomainTransfer {
pub collective: CollectiveConsciousness,
pub engine: DomainExpansionEngine,
domain_id: DomainId,
#[allow(dead_code)]
substrate_ids: Vec<Uuid>,
rounds: usize,
}
impl CollectiveDomainTransfer {
pub fn new(num_substrates: usize) -> Self {
let specializations = [
SubstrateSpecialization::Perception,
SubstrateSpecialization::Processing,
SubstrateSpecialization::Memory,
SubstrateSpecialization::Integration,
];
let mut collective = CollectiveConsciousness::new();
let substrate_ids: Vec<Uuid> = (0..num_substrates)
.map(|i| collective.add_substrate(specializations[i % specializations.len()].clone()))
.collect();
let mut engine = DomainExpansionEngine::new();
engine.register_domain(Box::new(StrangeLoopDomain::new(4)));
let domain_id = DomainId("strange_loop".to_string());
Self {
collective,
engine,
domain_id,
substrate_ids,
rounds: 0,
}
}
pub fn run_cycle(&mut self) -> f64 {
let bucket = ContextBucket {
difficulty_tier: "medium".to_string(),
category: "self_reference".to_string(),
};
let arm_id = ArmId("arm_0".to_string());
let n = self.substrate_ids.len().max(1);
let tasks = self.engine.generate_tasks(&self.domain_id, n, 0.5);
for (i, task) in tasks.iter().enumerate() {
let solution = Solution {
task_id: task.id.clone(),
content: format!(
"self-meta-loop: I observe my self-model at meta-depth {}",
i
),
data: json!({ "depth": i, "self_reference": true }),
};
self.engine.evaluate_and_record(
&self.domain_id,
task,
&solution,
bucket.clone(),
arm_id.clone(),
);
}
self.rounds += 1;
self.collective.compute_global_phi()
}
pub fn collective_phi(&mut self) -> f64 {
self.collective.compute_global_phi()
}
pub fn rounds(&self) -> usize {
self.rounds
}
}
pub struct EmergentTransferDetector {
detector: EmergenceDetector,
baseline_scores: Vec<f64>,
post_transfer_scores: Vec<f64>,
}
impl EmergentTransferDetector {
pub fn new() -> Self {
Self {
detector: EmergenceDetector::new(),
baseline_scores: Vec::new(),
post_transfer_scores: Vec::new(),
}
}
pub fn record_baseline(&mut self, score: f64) {
self.baseline_scores.push(score);
self.detector.set_micro_state(self.baseline_scores.clone());
}
pub fn record_post_transfer(&mut self, score: f64) {
self.post_transfer_scores.push(score);
let mut combined = self.baseline_scores.clone();
combined.extend_from_slice(&self.post_transfer_scores);
self.detector.set_micro_state(combined);
}
pub fn emergence_score(&mut self) -> f64 {
self.detector.detect_emergence()
}
pub fn mean_improvement(&self) -> f64 {
if self.baseline_scores.is_empty() || self.post_transfer_scores.is_empty() {
return 0.0;
}
let base_mean: f64 =
self.baseline_scores.iter().sum::<f64>() / self.baseline_scores.len() as f64;
let post_mean: f64 =
self.post_transfer_scores.iter().sum::<f64>() / self.post_transfer_scores.len() as f64;
post_mean - base_mean
}
}
impl Default for EmergentTransferDetector {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strange_loop_domain_basics() {
let domain = StrangeLoopDomain::new(5);
assert_eq!(domain.name(), "Strange Loop Self-Reference");
assert_eq!(domain.embedding_dim(), 64);
let tasks = domain.generate_tasks(3, 0.5);
assert_eq!(tasks.len(), 3);
let sol = domain.reference_solution(&tasks[0]).unwrap();
let eval = domain.evaluate(&tasks[0], &sol);
assert!(eval.score > 0.0);
}
#[test]
fn test_strange_loop_embedding() {
let domain = StrangeLoopDomain::new(5);
let tasks = domain.generate_tasks(1, 0.5);
let sol = domain.reference_solution(&tasks[0]).unwrap();
let emb = domain.embed(&sol);
assert_eq!(emb.dim, 64);
assert_eq!(emb.vector.len(), 64);
}
#[test]
fn test_collective_domain_transfer() {
let mut cdt = CollectiveDomainTransfer::new(2);
let phi = cdt.run_cycle();
assert!(phi >= 0.0);
assert_eq!(cdt.rounds(), 1);
let phi2 = cdt.run_cycle();
assert!(phi2 >= 0.0);
assert_eq!(cdt.rounds(), 2);
}
#[test]
fn test_emergent_transfer_detector() {
let mut etd = EmergentTransferDetector::new();
etd.record_baseline(0.5);
etd.record_post_transfer(0.7);
let improvement = etd.mean_improvement();
assert!((improvement - 0.2).abs() < 1e-10);
let score = etd.emergence_score();
assert!(score >= 0.0);
}
#[test]
fn test_empty_detector() {
let etd = EmergentTransferDetector::new();
assert_eq!(etd.mean_improvement(), 0.0);
}
}