Skip to main content

pacr_types/
complexity.rs

1//! Pillar: III. PACR field: Γ (Cognitive Split).
2//!
3//! Computational mechanics fundamental theorem (arXiv:2601.03220):
4//! any data stream admits a unique decomposition into two inseparable projections
5//! of the same ε-machine:
6//!
7//!   `S_T` — statistical complexity (bits)
8//!         Minimum causal-state information needed to optimally predict the stream.
9//!         Rising `S_T` → the system is discovering learnable structure.
10//!
11//!   `H_T` — entropy rate (bits per symbol)
12//!         Residual unpredictability that cannot be further compressed.
13//!         Rising `H_T` → the system is encountering irreducible noise.
14//!
15//! These two quantities are OBSERVER-DEPENDENT (the observer's computational
16//! budget `T_budget` determines the ε-machine approximation order) and
17//! INSEPARABLE — removing either one from the record permanently loses
18//! information that cannot be recovered from the other.
19
20use crate::estimate::Estimate;
21
22// ── Core type ─────────────────────────────────────────────────────────────────
23
24/// The cognitive split Γ = (`S_T`, `H_T`): intrinsic information structure of the
25/// processed data stream, as computed by the ε-machine approximation.
26///
27/// PACR field Γ.  Derived from Pillar III (computational mechanics).
28#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
29pub struct CognitiveSplit {
30    /// Statistical complexity `S_T` (bits).
31    /// Minimum information needed to optimally predict the stream.
32    pub statistical_complexity: Estimate<f64>,
33
34    /// Entropy rate `H_T` (bits per symbol).
35    /// Residual unpredictability even with the optimal predictor.
36    pub entropy_rate: Estimate<f64>,
37}
38
39impl CognitiveSplit {
40    /// Structure-to-noise ratio: `S_T` / `H_T`.
41    ///
42    /// - **High** → structured, predictable stream (e.g. chess move sequences).
43    /// - **Low** → simple but random stream (e.g. fair-coin outputs).
44    /// - `None` → `H_T` ≈ 0, stream is fully deterministic; ratio is effectively ∞.
45    #[must_use]
46    pub fn structure_noise_ratio(&self) -> Option<f64> {
47        if self.entropy_rate.point.abs() < f64::EPSILON {
48            return None; // deterministic stream; avoid division by near-zero
49        }
50        Some(self.statistical_complexity.point / self.entropy_rate.point)
51    }
52
53    /// Returns `true` when `S_T` > `H_T` (or `H_T` ≈ 0), indicating a stream with
54    /// more learnable structure than irreducible randomness.
55    #[must_use]
56    pub fn is_structured(&self) -> bool {
57        self.structure_noise_ratio().is_none_or(|r| r > 1.0)
58    }
59}
60
61// ── Unit tests ────────────────────────────────────────────────────────────────
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66    use crate::estimate::Estimate;
67
68    #[test]
69    fn structured_stream_ratio_gt_one() {
70        let g = CognitiveSplit {
71            statistical_complexity: Estimate::exact(4.0),
72            entropy_rate: Estimate::exact(1.0),
73        };
74        let r = g.structure_noise_ratio().unwrap();
75        assert!((r - 4.0).abs() < f64::EPSILON);
76        assert!(g.is_structured());
77    }
78
79    #[test]
80    fn noisy_stream_ratio_lt_one() {
81        let g = CognitiveSplit {
82            statistical_complexity: Estimate::exact(0.5),
83            entropy_rate: Estimate::exact(2.0),
84        };
85        assert!(!g.is_structured());
86    }
87
88    #[test]
89    fn deterministic_stream_returns_none_and_is_structured() {
90        let g = CognitiveSplit {
91            statistical_complexity: Estimate::exact(3.0),
92            entropy_rate: Estimate::exact(0.0),
93        };
94        assert!(g.structure_noise_ratio().is_none());
95        assert!(g.is_structured()); // deterministic → always structured
96    }
97
98    #[test]
99    fn equal_complexity_and_entropy_ratio_is_one() {
100        let g = CognitiveSplit {
101            statistical_complexity: Estimate::exact(2.0),
102            entropy_rate: Estimate::exact(2.0),
103        };
104        let r = g.structure_noise_ratio().unwrap();
105        assert!((r - 1.0).abs() < f64::EPSILON);
106    }
107}