Skip to main content

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            // Both vectors have zero variance (constant). Pearson is
347            // undefined here. Fall back to "perfect correlation" if the
348            // constants are equal (signals an exact loop), else 0.0.
349            // Without this, a strange-loop operator fed an identical
350            // state repeatedly never registers any loop depth — the
351            // exact case test_loop_depth_calculation exercises.
352            let v1 = state1.first().copied().unwrap_or(0.0);
353            let v2 = state2.first().copied().unwrap_or(0.0);
354            if (v1 - v2).abs() < 1e-12 {
355                Ok(1.0)
356            } else {
357                Ok(0.0)
358            }
359        }
360    }
361    
362    fn calculate_state_complexity(&self, state: &[f64]) -> f64 {
363        if state.is_empty() {
364            return 0.0;
365        }
366        
367        // Calculate entropy-based complexity measure
368        let mut complexity = 0.0;
369        
370        // Variance component
371        let mean: f64 = state.iter().sum::<f64>() / state.len() as f64;
372        let variance: f64 = state.iter()
373            .map(|x| (x - mean).powi(2))
374            .sum::<f64>() / state.len() as f64;
375        
376        complexity += variance.sqrt();
377        
378        // Information content component
379        for &value in state {
380            if value.abs() > 1e-10 {
381                complexity += -value.abs().ln() / state.len() as f64;
382            }
383        }
384        
385        complexity.min(10.0) // Bound complexity
386    }
387    
388    fn update_self_reference(&mut self, loop_state: &LoopState) -> TemporalResult<()> {
389        // Update self-reference strength based on loop state
390        let alpha = 0.05; // Learning rate
391        self.self_reference_strength = (1.0 - alpha) * self.self_reference_strength 
392            + alpha * loop_state.self_reference;
393        
394        // Bound self-reference strength
395        self.self_reference_strength = self.self_reference_strength.clamp(0.0, 1.0);
396        
397        Ok(())
398    }
399    
400    fn update_emergence_level(&mut self, contracted_state: &[f64]) -> TemporalResult<()> {
401        // Calculate new emergence level
402        let new_emergence = self.calculate_emergence_factor(contracted_state)?;
403        
404        // Smooth update
405        let alpha = 0.1;
406        self.emergence_level = (1.0 - alpha) * self.emergence_level + alpha * new_emergence;
407        
408        Ok(())
409    }
410    
411    fn store_loop_state(&mut self, state: LoopState) {
412        self.loop_states.push_back(state);
413        
414        // Keep history bounded
415        while self.loop_states.len() > 1000 {
416            self.loop_states.pop_front();
417        }
418    }
419    
420    fn update_metrics(&mut self, convergence_info: ConvergenceInfo) -> TemporalResult<()> {
421        self.metrics.iterations_to_convergence = convergence_info.iterations;
422        self.metrics.contraction_achieved = convergence_info.converged;
423        
424        // Calculate convergence rate from recent history
425        if self.contraction_history.len() >= 2 {
426            let recent_distances: Vec<f64> = self.contraction_history.iter()
427                .rev()
428                .take(10)
429                .cloned()
430                .collect();
431            
432            if recent_distances.len() >= 2 {
433                let rate = recent_distances[0] / recent_distances[recent_distances.len() - 1].max(1e-10);
434                self.metrics.convergence_rate = rate.min(1.0);
435            }
436        }
437        
438        self.metrics.lipschitz_constant = self.params.lipschitz_bound;
439        self.metrics.final_fixed_point = self.fixed_point.clone();
440        
441        // Calculate stability measure
442        self.metrics.stability_measure = self.calculate_stability_measure();
443        
444        Ok(())
445    }
446    
447    fn calculate_stability_measure(&self) -> f64 {
448        if self.contraction_history.len() < self.params.stability_window {
449            return 0.0;
450        }
451        
452        let recent_distances: Vec<f64> = self.contraction_history.iter()
453            .rev()
454            .take(self.params.stability_window)
455            .cloned()
456            .collect();
457        
458        let mean: f64 = recent_distances.iter().sum::<f64>() / recent_distances.len() as f64;
459        let variance: f64 = recent_distances.iter()
460            .map(|x| (x - mean).powi(2))
461            .sum::<f64>() / recent_distances.len() as f64;
462        
463        // Stability is inverse of variance (lower variance = higher stability)
464        1.0 / (1.0 + variance)
465    }
466}
467
468/// Convergence information for internal use
469#[derive(Debug, Clone)]
470struct ConvergenceInfo {
471    converged: bool,
472    distance: f64,
473    iterations: usize,
474}
475
476#[cfg(test)]
477mod tests {
478    use super::*;
479    
480    #[test]
481    fn test_strange_loop_creation() {
482        let operator = StrangeLoopOperator::new(0.9, 100);
483        assert_eq!(operator.params.lipschitz_bound, 0.9);
484        assert_eq!(operator.params.max_iterations, 100);
485        assert_eq!(operator.emergence_level, 0.0);
486    }
487    
488    #[test]
489    fn test_contraction_mapping() {
490        let mut operator = StrangeLoopOperator::new(0.8, 100);
491        let state = vec![1.0, 2.0, 3.0];
492        
493        let contracted = operator.apply_contraction_mapping(&state).unwrap();
494        assert_eq!(contracted.len(), state.len());
495        
496        // Contracted values should be bounded
497        for &value in &contracted {
498            assert!(value.abs() <= 1.0);
499        }
500    }
501    
502    #[test]
503    fn test_convergence_detection() {
504        let mut operator = StrangeLoopOperator::new(0.9, 100);
505        let state = vec![0.1, 0.1, 0.1];
506        
507        // Set up fixed point
508        operator.fixed_point = vec![0.1, 0.1, 0.1];
509        
510        let convergence = operator.check_convergence(&state).unwrap();
511        assert!(convergence.converged);
512        assert!(convergence.distance < 1e-6);
513    }
514    
515    #[test]
516    fn test_self_reference_calculation() {
517        let mut operator = StrangeLoopOperator::new(0.9, 100);
518        let state = vec![1.0, 2.0, 3.0];
519        
520        // Process a few iterations to build history
521        for i in 0..5 {
522            operator.process_iteration(i as f64, &state).unwrap();
523        }
524        
525        assert!(operator.self_reference_strength > 0.0);
526        assert!(operator.emergence_level >= 0.0);
527    }
528    
529    #[test]
530    fn test_loop_depth_calculation() {
531        let mut operator = StrangeLoopOperator::new(0.9, 100);
532        let state = vec![1.0, 1.0, 1.0];
533        
534        // Process multiple iterations with similar states
535        for _ in 0..10 {
536            operator.process_iteration(0.0, &state).unwrap();
537        }
538        
539        assert!(operator.get_loop_depth() > 0);
540    }
541    
542    #[test]
543    fn test_emergence_level_growth() {
544        let mut operator = StrangeLoopOperator::new(0.9, 100);
545        let mut state = vec![0.5, 0.5, 0.5];
546        
547        let initial_emergence = operator.get_emergence_level();
548        
549        // Process iterations with evolving state
550        for i in 0..20 {
551            state[0] += 0.01 * (i as f64).sin();
552            operator.process_iteration(i as f64, &state).unwrap();
553        }
554        
555        let final_emergence = operator.get_emergence_level();
556        assert!(final_emergence >= initial_emergence);
557    }
558    
559    #[test]
560    fn test_metrics_update() {
561        let mut operator = StrangeLoopOperator::new(0.9, 100);
562        let state = vec![1.0, 2.0, 3.0];
563        
564        let metrics = operator.process_iteration(0.0, &state).unwrap();
565        
566        assert!(metrics.iterations_to_convergence > 0);
567        assert!(metrics.lipschitz_constant == 0.9);
568        assert!(metrics.stability_measure >= 0.0);
569    }
570}