strange_loop/
self_modifying.rs

1//! Self-modifying strange loops that evolve their own parameters
2
3use std::sync::{Arc, RwLock};
4
5/// Self-modifying loop that evolves its own code and parameters
6pub struct SelfModifyingLoop {
7    /// Current loop function (mutable)
8    loop_fn: Arc<RwLock<Box<dyn Fn(f64) -> f64 + Send + Sync>>>,
9    /// Evolution parameters
10    mutation_rate: f64,
11    /// Fitness history
12    fitness_history: Vec<f64>,
13    /// Current generation
14    generation: usize,
15    /// Best performing parameters
16    best_params: Vec<f64>,
17}
18
19impl SelfModifyingLoop {
20    pub fn new(mutation_rate: f64) -> Self {
21        let initial_fn = Box::new(|x: f64| x.sin() * x.cos()) as Box<dyn Fn(f64) -> f64 + Send + Sync>;
22
23        Self {
24            loop_fn: Arc::new(RwLock::new(initial_fn)),
25            mutation_rate,
26            fitness_history: Vec::new(),
27            generation: 0,
28            best_params: vec![1.0, 0.0, 0.0],
29        }
30    }
31
32    /// Evolve the loop function based on performance
33    pub fn evolve(&mut self, fitness: f64) {
34        self.fitness_history.push(fitness);
35        self.generation += 1;
36
37        // Only evolve if we have enough history
38        if self.fitness_history.len() < 10 {
39            return;
40        }
41
42        // Calculate fitness trend
43        let recent_avg = self.fitness_history.iter().rev().take(5).sum::<f64>() / 5.0;
44        let past_avg = self.fitness_history.iter().rev().skip(5).take(5).sum::<f64>() / 5.0;
45
46        // If performance is declining, mutate more aggressively
47        let mutation_factor = if recent_avg < past_avg {
48            self.mutation_rate * 2.0
49        } else {
50            self.mutation_rate
51        };
52
53        // Mutate parameters
54        self.mutate_parameters(mutation_factor);
55
56        // Update the loop function with new parameters
57        self.update_loop_function();
58    }
59
60    fn mutate_parameters(&mut self, factor: f64) {
61        use rand::Rng;
62        let mut rng = rand::thread_rng();
63
64        for param in &mut self.best_params {
65            if rng.gen::<f64>() < factor {
66                // Add Gaussian noise
67                let noise = rng.gen_range(-0.1..0.1);
68                *param += noise;
69                *param = param.clamp(-10.0, 10.0);
70            }
71        }
72    }
73
74    fn update_loop_function(&mut self) {
75        let a = self.best_params[0];
76        let b = self.best_params[1];
77        let c = self.best_params[2];
78
79        let new_fn = Box::new(move |x: f64| {
80            a * x.sin() + b * x.cos() + c * x.tan().tanh()
81        }) as Box<dyn Fn(f64) -> f64 + Send + Sync>;
82
83        if let Ok(mut fn_lock) = self.loop_fn.write() {
84            *fn_lock = new_fn;
85        }
86    }
87
88    /// Execute the current loop function
89    pub fn execute(&self, input: f64) -> f64 {
90        if let Ok(fn_lock) = self.loop_fn.read() {
91            fn_lock(input)
92        } else {
93            input
94        }
95    }
96
97    /// Self-replicate with mutations
98    pub fn replicate(&self) -> Self {
99        let mut child = Self::new(self.mutation_rate);
100        child.best_params = self.best_params.clone();
101        child.mutate_parameters(self.mutation_rate * 0.5);
102        child.update_loop_function();
103        child
104    }
105
106    /// Get evolutionary metrics
107    pub fn get_metrics(&self) -> EvolutionMetrics {
108        EvolutionMetrics {
109            generation: self.generation,
110            current_fitness: self.fitness_history.last().copied().unwrap_or(0.0),
111            best_fitness: self.fitness_history.iter().max_by(|a, b| a.partial_cmp(b).unwrap()).copied().unwrap_or(0.0),
112            mutation_rate: self.mutation_rate,
113            parameters: self.best_params.clone(),
114        }
115    }
116}
117
118#[derive(Debug, Clone)]
119pub struct EvolutionMetrics {
120    pub generation: usize,
121    pub current_fitness: f64,
122    pub best_fitness: f64,
123    pub mutation_rate: f64,
124    pub parameters: Vec<f64>,
125}