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}