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