sublinear_solver/temporal_nexus/core/
strange_loop.rs

1//! Strange Loop Operator with Contraction for Temporal Consciousness
2//!
3//! This module implements the strange loop operator that creates self-referential
4//! patterns necessary for consciousness emergence. The operator uses contraction
5//! mapping with Lipschitz constant < 1 to ensure convergence.
6
7use std::collections::VecDeque;
8use super::TemporalResult;
9
10/// Metrics for contraction convergence analysis
11#[derive(Debug, Clone, Default)]
12pub struct ContractionMetrics {
13    pub iterations_to_convergence: usize,
14    pub convergence_rate: f64,
15    pub lipschitz_constant: f64,
16    pub final_fixed_point: Vec<f64>,
17    pub contraction_achieved: bool,
18    pub stability_measure: f64,
19}
20
21/// Strange loop state representing self-referential structure
22#[derive(Debug, Clone)]
23struct LoopState {
24    pub level: usize,
25    pub state_vector: Vec<f64>,
26    pub self_reference: f64,
27    pub emergence_factor: f64,
28    pub timestamp: u64,
29}
30
31/// Contraction mapping parameters
32#[derive(Debug, Clone)]
33struct ContractionParams {
34    pub lipschitz_bound: f64,
35    pub convergence_threshold: f64,
36    pub max_iterations: usize,
37    pub stability_window: usize,
38}
39
40/// Strange Loop Operator implementing self-referential consciousness patterns
41pub struct StrangeLoopOperator {
42    params: ContractionParams,
43    loop_states: VecDeque<LoopState>,
44    metrics: ContractionMetrics,
45    fixed_point: Vec<f64>,
46    iteration_count: u64,
47    contraction_history: VecDeque<f64>,
48    
49    // Self-reference tracking
50    self_reference_strength: f64,
51    emergence_level: f64,
52    loop_depth: usize,
53}
54
55impl StrangeLoopOperator {
56    /// Create a new strange loop operator
57    pub fn new(lipschitz_bound: f64, max_iterations: usize) -> Self {
58        Self {
59            params: ContractionParams {
60                lipschitz_bound: lipschitz_bound.min(0.99), // Ensure < 1
61                convergence_threshold: 1e-6,
62                max_iterations,
63                stability_window: 10,
64            },
65            loop_states: VecDeque::with_capacity(1000),
66            metrics: ContractionMetrics::default(),
67            fixed_point: Vec::new(),
68            iteration_count: 0,
69            contraction_history: VecDeque::with_capacity(1000),
70            
71            self_reference_strength: 0.0,
72            emergence_level: 0.0,
73            loop_depth: 0,
74        }
75    }
76    
77    /// Process one iteration of the strange loop with contraction
78    pub fn process_iteration(&mut self, time: f64, state: &[f64]) -> TemporalResult<ContractionMetrics> {
79        self.iteration_count += 1;
80        
81        // Create new loop state with self-reference
82        let loop_state = self.create_loop_state(time, state)?;
83        
84        // Apply contraction mapping
85        let contracted_state = self.apply_contraction_mapping(&loop_state.state_vector)?;
86        
87        // Update fixed point estimate
88        self.update_fixed_point(&contracted_state)?;
89        
90        // Check convergence
91        let convergence_info = self.check_convergence(&contracted_state)?;
92        
93        // Update self-reference and emergence
94        self.update_self_reference(&loop_state)?;
95        self.update_emergence_level(&contracted_state)?;
96        
97        // Store state history
98        self.store_loop_state(loop_state);
99        
100        // Update metrics
101        self.update_metrics(convergence_info)?;
102        
103        Ok(self.metrics.clone())
104    }
105    
106    /// Get current contraction metrics
107    pub fn get_metrics(&self) -> &ContractionMetrics {
108        &self.metrics
109    }
110    
111    /// Get current emergence level
112    pub fn get_emergence_level(&self) -> f64 {
113        self.emergence_level
114    }
115    
116    /// Get self-reference strength
117    pub fn get_self_reference_strength(&self) -> f64 {
118        self.self_reference_strength
119    }
120    
121    /// Get current loop depth
122    pub fn get_loop_depth(&self) -> usize {
123        self.loop_depth
124    }
125    
126    /// Get fixed point estimate
127    pub fn get_fixed_point(&self) -> &[f64] {
128        &self.fixed_point
129    }
130    
131    /// Reset the operator state
132    pub fn reset(&mut self) {
133        self.loop_states.clear();
134        self.fixed_point.clear();
135        self.iteration_count = 0;
136        self.contraction_history.clear();
137        self.self_reference_strength = 0.0;
138        self.emergence_level = 0.0;
139        self.loop_depth = 0;
140        self.metrics = ContractionMetrics::default();
141    }
142    
143    /// Force convergence check (for testing)
144    pub fn force_convergence_check(&mut self, state: &[f64]) -> TemporalResult<bool> {
145        let convergence_info = self.check_convergence(state)?;
146        Ok(convergence_info.converged)
147    }
148    
149    // Private helper methods
150    
151    fn create_loop_state(&mut self, time: f64, state: &[f64]) -> TemporalResult<LoopState> {
152        // Calculate self-reference by looking at state history
153        let self_ref = self.calculate_self_reference(state)?;
154        
155        // Calculate emergence factor based on loop complexity
156        let emergence = self.calculate_emergence_factor(state)?;
157        
158        // Determine current loop depth
159        self.loop_depth = self.calculate_loop_depth(state);
160        
161        Ok(LoopState {
162            level: self.loop_depth,
163            state_vector: state.to_vec(),
164            self_reference: self_ref,
165            emergence_factor: emergence,
166            timestamp: time as u64,
167        })
168    }
169    
170    fn apply_contraction_mapping(&self, state: &[f64]) -> TemporalResult<Vec<f64>> {
171        if state.is_empty() {
172            return Ok(Vec::new());
173        }
174        
175        let mut contracted = Vec::with_capacity(state.len());
176        
177        for (i, &value) in state.iter().enumerate() {
178            // Apply contraction with self-reference
179            let self_ref_component = if i < self.loop_states.len() {
180                self.loop_states[i % self.loop_states.len()].self_reference
181            } else {
182                0.0
183            };
184            
185            // Contraction mapping: f(x) = L * x + c, where L < 1
186            let contracted_value = self.params.lipschitz_bound * value 
187                + (1.0 - self.params.lipschitz_bound) * self_ref_component;
188            
189            // Apply strange loop transformation
190            let loop_transformed = self.apply_strange_loop_transform(contracted_value, i);
191            
192            contracted.push(loop_transformed);
193        }
194        
195        Ok(contracted)
196    }
197    
198    fn apply_strange_loop_transform(&self, value: f64, index: usize) -> f64 {
199        // Strange loop: the output influences the input through self-reference
200        let loop_factor = (self.self_reference_strength * (index as f64 + 1.0).ln()).sin();
201        let self_modulation = 1.0 + 0.1 * loop_factor;
202        
203        // Apply bounded transformation to maintain stability
204        let transformed = value * self_modulation;
205        transformed.tanh() // Bounded between -1 and 1
206    }
207    
208    fn update_fixed_point(&mut self, contracted_state: &[f64]) -> TemporalResult<()> {
209        if self.fixed_point.is_empty() {
210            self.fixed_point = contracted_state.to_vec();
211        } else {
212            // Update fixed point estimate using exponential moving average
213            let alpha = 0.1; // Learning rate
214            
215            for (i, &new_value) in contracted_state.iter().enumerate() {
216                if i < self.fixed_point.len() {
217                    self.fixed_point[i] = (1.0 - alpha) * self.fixed_point[i] + alpha * new_value;
218                } else {
219                    self.fixed_point.push(new_value);
220                }
221            }
222        }
223        
224        Ok(())
225    }
226    
227    fn check_convergence(&mut self, state: &[f64]) -> TemporalResult<ConvergenceInfo> {
228        if self.fixed_point.is_empty() || state.len() != self.fixed_point.len() {
229            return Ok(ConvergenceInfo {
230                converged: false,
231                distance: f64::INFINITY,
232                iterations: self.iteration_count as usize,
233            });
234        }
235        
236        // Calculate L2 distance to fixed point
237        let distance: f64 = state.iter()
238            .zip(self.fixed_point.iter())
239            .map(|(a, b)| (a - b).powi(2))
240            .sum::<f64>()
241            .sqrt();
242        
243        self.contraction_history.push_back(distance);
244        if self.contraction_history.len() > 1000 {
245            self.contraction_history.pop_front();
246        }
247        
248        let converged = distance < self.params.convergence_threshold;
249        
250        Ok(ConvergenceInfo {
251            converged,
252            distance,
253            iterations: self.iteration_count as usize,
254        })
255    }
256    
257    fn calculate_self_reference(&self, state: &[f64]) -> TemporalResult<f64> {
258        if self.loop_states.is_empty() {
259            return Ok(0.0);
260        }
261        
262        // Calculate correlation with previous states
263        let mut total_correlation = 0.0;
264        let mut count = 0;
265        
266        for prev_state in self.loop_states.iter().rev().take(10) {
267            if prev_state.state_vector.len() == state.len() {
268                let correlation = self.calculate_correlation(&prev_state.state_vector, state)?;
269                total_correlation += correlation * prev_state.emergence_factor;
270                count += 1;
271            }
272        }
273        
274        if count > 0 {
275            Ok(total_correlation / count as f64)
276        } else {
277            Ok(0.0)
278        }
279    }
280    
281    fn calculate_emergence_factor(&self, state: &[f64]) -> TemporalResult<f64> {
282        if state.is_empty() {
283            return Ok(0.0);
284        }
285        
286        // Calculate emergence based on state complexity and self-reference
287        let complexity = self.calculate_state_complexity(state);
288        let self_ref_factor = self.self_reference_strength;
289        let loop_depth_factor = (self.loop_depth as f64).ln().max(0.0);
290        
291        let emergence = (complexity * (1.0 + self_ref_factor) * (1.0 + loop_depth_factor)).tanh();
292        Ok(emergence)
293    }
294    
295    fn calculate_loop_depth(&self, state: &[f64]) -> usize {
296        // Calculate how deep the self-reference goes
297        let mut depth = 0;
298        let threshold = 0.1;
299        
300        for prev_state in self.loop_states.iter().rev() {
301            if prev_state.state_vector.len() == state.len() {
302                let correlation = self.calculate_correlation(&prev_state.state_vector, state)
303                    .unwrap_or(0.0);
304                
305                if correlation > threshold {
306                    depth += 1;
307                } else {
308                    break;
309                }
310            }
311            
312            if depth > 100 { // Limit depth for performance
313                break;
314            }
315        }
316        
317        depth
318    }
319    
320    fn calculate_correlation(&self, state1: &[f64], state2: &[f64]) -> TemporalResult<f64> {
321        if state1.len() != state2.len() || state1.is_empty() {
322            return Ok(0.0);
323        }
324        
325        let mean1: f64 = state1.iter().sum::<f64>() / state1.len() as f64;
326        let mean2: f64 = state2.iter().sum::<f64>() / state2.len() as f64;
327        
328        let mut numerator = 0.0;
329        let mut sum_sq1 = 0.0;
330        let mut sum_sq2 = 0.0;
331        
332        for (v1, v2) in state1.iter().zip(state2.iter()) {
333            let diff1 = v1 - mean1;
334            let diff2 = v2 - mean2;
335            
336            numerator += diff1 * diff2;
337            sum_sq1 += diff1 * diff1;
338            sum_sq2 += diff2 * diff2;
339        }
340        
341        let denominator = (sum_sq1 * sum_sq2).sqrt();
342        
343        if denominator > 0.0 {
344            Ok(numerator / denominator)
345        } else {
346            Ok(0.0)
347        }
348    }
349    
350    fn calculate_state_complexity(&self, state: &[f64]) -> f64 {
351        if state.is_empty() {
352            return 0.0;
353        }
354        
355        // Calculate entropy-based complexity measure
356        let mut complexity = 0.0;
357        
358        // Variance component
359        let mean: f64 = state.iter().sum::<f64>() / state.len() as f64;
360        let variance: f64 = state.iter()
361            .map(|x| (x - mean).powi(2))
362            .sum::<f64>() / state.len() as f64;
363        
364        complexity += variance.sqrt();
365        
366        // Information content component
367        for &value in state {
368            if value.abs() > 1e-10 {
369                complexity += -value.abs().ln() / state.len() as f64;
370            }
371        }
372        
373        complexity.min(10.0) // Bound complexity
374    }
375    
376    fn update_self_reference(&mut self, loop_state: &LoopState) -> TemporalResult<()> {
377        // Update self-reference strength based on loop state
378        let alpha = 0.05; // Learning rate
379        self.self_reference_strength = (1.0 - alpha) * self.self_reference_strength 
380            + alpha * loop_state.self_reference;
381        
382        // Bound self-reference strength
383        self.self_reference_strength = self.self_reference_strength.clamp(0.0, 1.0);
384        
385        Ok(())
386    }
387    
388    fn update_emergence_level(&mut self, contracted_state: &[f64]) -> TemporalResult<()> {
389        // Calculate new emergence level
390        let new_emergence = self.calculate_emergence_factor(contracted_state)?;
391        
392        // Smooth update
393        let alpha = 0.1;
394        self.emergence_level = (1.0 - alpha) * self.emergence_level + alpha * new_emergence;
395        
396        Ok(())
397    }
398    
399    fn store_loop_state(&mut self, state: LoopState) {
400        self.loop_states.push_back(state);
401        
402        // Keep history bounded
403        while self.loop_states.len() > 1000 {
404            self.loop_states.pop_front();
405        }
406    }
407    
408    fn update_metrics(&mut self, convergence_info: ConvergenceInfo) -> TemporalResult<()> {
409        self.metrics.iterations_to_convergence = convergence_info.iterations;
410        self.metrics.contraction_achieved = convergence_info.converged;
411        
412        // Calculate convergence rate from recent history
413        if self.contraction_history.len() >= 2 {
414            let recent_distances: Vec<f64> = self.contraction_history.iter()
415                .rev()
416                .take(10)
417                .cloned()
418                .collect();
419            
420            if recent_distances.len() >= 2 {
421                let rate = recent_distances[0] / recent_distances[recent_distances.len() - 1].max(1e-10);
422                self.metrics.convergence_rate = rate.min(1.0);
423            }
424        }
425        
426        self.metrics.lipschitz_constant = self.params.lipschitz_bound;
427        self.metrics.final_fixed_point = self.fixed_point.clone();
428        
429        // Calculate stability measure
430        self.metrics.stability_measure = self.calculate_stability_measure();
431        
432        Ok(())
433    }
434    
435    fn calculate_stability_measure(&self) -> f64 {
436        if self.contraction_history.len() < self.params.stability_window {
437            return 0.0;
438        }
439        
440        let recent_distances: Vec<f64> = self.contraction_history.iter()
441            .rev()
442            .take(self.params.stability_window)
443            .cloned()
444            .collect();
445        
446        let mean: f64 = recent_distances.iter().sum::<f64>() / recent_distances.len() as f64;
447        let variance: f64 = recent_distances.iter()
448            .map(|x| (x - mean).powi(2))
449            .sum::<f64>() / recent_distances.len() as f64;
450        
451        // Stability is inverse of variance (lower variance = higher stability)
452        1.0 / (1.0 + variance)
453    }
454}
455
456/// Convergence information for internal use
457#[derive(Debug, Clone)]
458struct ConvergenceInfo {
459    converged: bool,
460    distance: f64,
461    iterations: usize,
462}
463
464#[cfg(test)]
465mod tests {
466    use super::*;
467    
468    #[test]
469    fn test_strange_loop_creation() {
470        let operator = StrangeLoopOperator::new(0.9, 100);
471        assert_eq!(operator.params.lipschitz_bound, 0.9);
472        assert_eq!(operator.params.max_iterations, 100);
473        assert_eq!(operator.emergence_level, 0.0);
474    }
475    
476    #[test]
477    fn test_contraction_mapping() {
478        let mut operator = StrangeLoopOperator::new(0.8, 100);
479        let state = vec![1.0, 2.0, 3.0];
480        
481        let contracted = operator.apply_contraction_mapping(&state).unwrap();
482        assert_eq!(contracted.len(), state.len());
483        
484        // Contracted values should be bounded
485        for &value in &contracted {
486            assert!(value.abs() <= 1.0);
487        }
488    }
489    
490    #[test]
491    fn test_convergence_detection() {
492        let mut operator = StrangeLoopOperator::new(0.9, 100);
493        let state = vec![0.1, 0.1, 0.1];
494        
495        // Set up fixed point
496        operator.fixed_point = vec![0.1, 0.1, 0.1];
497        
498        let convergence = operator.check_convergence(&state).unwrap();
499        assert!(convergence.converged);
500        assert!(convergence.distance < 1e-6);
501    }
502    
503    #[test]
504    fn test_self_reference_calculation() {
505        let mut operator = StrangeLoopOperator::new(0.9, 100);
506        let state = vec![1.0, 2.0, 3.0];
507        
508        // Process a few iterations to build history
509        for i in 0..5 {
510            operator.process_iteration(i as f64, &state).unwrap();
511        }
512        
513        assert!(operator.self_reference_strength > 0.0);
514        assert!(operator.emergence_level >= 0.0);
515    }
516    
517    #[test]
518    fn test_loop_depth_calculation() {
519        let mut operator = StrangeLoopOperator::new(0.9, 100);
520        let state = vec![1.0, 1.0, 1.0];
521        
522        // Process multiple iterations with similar states
523        for _ in 0..10 {
524            operator.process_iteration(0.0, &state).unwrap();
525        }
526        
527        assert!(operator.get_loop_depth() > 0);
528    }
529    
530    #[test]
531    fn test_emergence_level_growth() {
532        let mut operator = StrangeLoopOperator::new(0.9, 100);
533        let mut state = vec![0.5, 0.5, 0.5];
534        
535        let initial_emergence = operator.get_emergence_level();
536        
537        // Process iterations with evolving state
538        for i in 0..20 {
539            state[0] += 0.01 * (i as f64).sin();
540            operator.process_iteration(i as f64, &state).unwrap();
541        }
542        
543        let final_emergence = operator.get_emergence_level();
544        assert!(final_emergence >= initial_emergence);
545    }
546    
547    #[test]
548    fn test_metrics_update() {
549        let mut operator = StrangeLoopOperator::new(0.9, 100);
550        let state = vec![1.0, 2.0, 3.0];
551        
552        let metrics = operator.process_iteration(0.0, &state).unwrap();
553        
554        assert!(metrics.iterations_to_convergence > 0);
555        assert!(metrics.lipschitz_constant == 0.9);
556        assert!(metrics.stability_measure >= 0.0);
557    }
558}