Skip to main content

qualia_core_db/modalities/
manifold_logic.rs

1//! Wave-physics substrate **logic** (§20, legal_logic.md) — the continuous→discrete bridge.
2//!
3//! SCOPE (honest): this is the CPU reference *logic* that bridges a continuous physical signal
4//! to a discrete factual quin the epistemic layer can reason over — `∫Ψ > τ → Fact(p)`. The
5//! full GPU-enumerated 10D-tensor manifold *renderer* (`compute_universe.rs`) is a separate,
6//! larger effort (STELLAR tasks #11–13); this module deliberately does NOT implement that.
7//!
8//! Qualitative/quantitative realities (EMF, acoustic, visual evidence) are evaluated as
9//! continuous math here, then thresholded into discrete facts — so e.g. a measured signal
10//! exceeding a legal limit instantiates a factual quin that the deontic/epistemic engines use.
11
12use core::f64::consts::PI;
13
14/// The named physical coordinates of a wave sample Ψ(x,y,z,t,f,a,φ) — the axes of the manifold.
15#[derive(Debug, Clone, Copy)]
16pub struct WaveCoord {
17    pub x: f64,
18    pub y: f64,
19    pub z: f64,
20    pub t: f64,
21    pub f: f64,
22    pub a: f64,
23    pub phi: f64,
24}
25
26/// Evaluate the wave field Ψ at a coordinate: amplitude `a` oscillating at frequency `f` with
27/// phase `φ` at time `t`, attenuated by an inverse-square spatial envelope `1/(1+r²)`.
28/// Deterministic CPU reference.
29pub fn wave_eval(c: &WaveCoord) -> f64 {
30    let r2 = c.x * c.x + c.y * c.y + c.z * c.z;
31    let envelope = 1.0 / (1.0 + r2);
32    c.a * (2.0 * PI * c.f * c.t + c.phi).sin() * envelope
33}
34
35/// Trapezoidal integral of |Ψ| over an ordered sample series — the accumulated signal energy.
36pub fn integrate_abs(samples: &[f64]) -> f64 {
37    if samples.len() < 2 {
38        return samples.first().map(|v| v.abs()).unwrap_or(0.0);
39    }
40    let mut acc = 0.0;
41    for w in samples.windows(2) {
42        acc += (w[0].abs() + w[1].abs()) * 0.5;
43    }
44    acc
45}
46
47/// **Continuous → discrete**: if the integrated signal exceeds `threshold`, instantiate the
48/// discrete fact `fact_id` (`∫Ψ > τ → Fact(p)`); otherwise `None`. The bridge from the manifold
49/// substrate to `epistemic.rs`.
50pub fn continuous_to_fact(samples: &[f64], threshold: f64, fact_id: u64) -> Option<u64> {
51    if integrate_abs(samples) > threshold {
52        Some(fact_id)
53    } else {
54        None
55    }
56}
57
58// ─── Topological data analysis: Vietoris-Rips + persistent H0 ─────────────────────
59//
60// Detect topological features (connected components / clusters) in the continuous signal by
61// building a Vietoris-Rips complex at a scale ε and tracking how components are born and die as ε
62// grows (0-dimensional persistent homology). Bounded + zero-heap (fixed union-find arrays).
63
64/// Bound on points in one topological query.
65pub const MAX_MANIFOLD_POINTS: usize = 64;
66
67#[inline]
68fn uf_find(parent: &mut [usize; MAX_MANIFOLD_POINTS], mut x: usize) -> usize {
69    while parent[x] != x {
70        parent[x] = parent[parent[x]];
71        x = parent[x];
72    }
73    x
74}
75#[inline]
76fn uf_union(parent: &mut [usize; MAX_MANIFOLD_POINTS], a: usize, b: usize) {
77    let (ra, rb) = (uf_find(parent, a), uf_find(parent, b));
78    if ra != rb {
79        parent[ra] = rb;
80    }
81}
82
83/// **Betti-0** (number of connected components) of the **Vietoris-Rips** complex at scale
84/// `epsilon`: connect points `i,j` whenever `dist[i*n+j] <= epsilon` (`dist` is a flattened
85/// `n×n` distance matrix). `0` for invalid input. Bounded + zero-heap.
86pub fn vietoris_rips_b0(dist: &[f64], n: usize, epsilon: f64) -> usize {
87    if n == 0 || n > MAX_MANIFOLD_POINTS || dist.len() < n * n {
88        return 0;
89    }
90    let mut parent = [0usize; MAX_MANIFOLD_POINTS];
91    for (i, p) in parent.iter_mut().enumerate().take(n) {
92        *p = i;
93    }
94    for i in 0..n {
95        for j in (i + 1)..n {
96            if dist[i * n + j] <= epsilon {
97                uf_union(&mut parent, i, j);
98            }
99        }
100    }
101    let mut components = 0usize;
102    for i in 0..n {
103        if uf_find(&mut parent, i) == i {
104            components += 1;
105        }
106    }
107    components
108}
109
110/// **Persistent 0-dim homology**: write the Betti-0 (component count) at each scale in `epsilons`
111/// (assumed increasing) into `out_b0` — the barcode of connected features (born at ε=0, dying as
112/// they merge; b0 is monotonically non-increasing). Returns the count written. Zero-heap.
113pub fn persistent_h0(dist: &[f64], n: usize, epsilons: &[f64], out_b0: &mut [usize]) -> usize {
114    let m = epsilons.len().min(out_b0.len());
115    for k in 0..m {
116        out_b0[k] = vietoris_rips_b0(dist, n, epsilons[k]);
117    }
118    m
119}
120
121/// **Topological dimension-bridging**: lift a lower-dimensional sample `low` (e.g. a 1-D audio
122/// sample, or a 7-axis `WaveCoord`) into a higher `out`-dimensional manifold coordinate, zero-
123/// padding the new axes. Returns `false` if `out` is too small. The 1D→10D bridge.
124pub fn bridge_dimensions(low: &[f64], out: &mut [f64]) -> bool {
125    if out.len() < low.len() {
126        return false;
127    }
128    for (i, o) in out.iter_mut().enumerate() {
129        *o = if i < low.len() { low[i] } else { 0.0 };
130    }
131    true
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137    use crate::q_hash;
138
139    #[test]
140    fn vietoris_rips_and_persistent_h0() {
141        // 4 points on a line at 0,1,2,10 → pairwise |Δ| distance matrix.
142        let pts = [0.0f64, 1.0, 2.0, 10.0];
143        let n = 4;
144        let mut dist = [0.0f64; 16];
145        for i in 0..n {
146            for j in 0..n {
147                dist[i * n + j] = (pts[i] - pts[j]).abs();
148            }
149        }
150        // ε=0.5: nothing connects → 4 components.
151        assert_eq!(vietoris_rips_b0(&dist, n, 0.5), 4);
152        // ε=1.0: the 0-1-2 cluster connects (dist 1 each); 10 stays apart → 2 components.
153        assert_eq!(vietoris_rips_b0(&dist, n, 1.0), 2);
154        // ε=10: everything connects → 1 component.
155        assert_eq!(vietoris_rips_b0(&dist, n, 10.0), 1);
156        // The persistence barcode across an increasing filtration.
157        let mut b0 = [0usize; 3];
158        let m = persistent_h0(&dist, n, &[0.5, 1.0, 10.0], &mut b0);
159        assert_eq!(m, 3);
160        assert_eq!(
161            b0,
162            [4, 2, 1],
163            "b0 is monotonically non-increasing as ε grows"
164        );
165    }
166
167    #[test]
168    fn dimension_bridging_zero_pads() {
169        let low = [1.0f64, 2.0, 3.0]; // a 3-D sample
170        let mut out = [9.0f64; 10]; // into the 10-D manifold
171        assert!(bridge_dimensions(&low, &mut out));
172        assert_eq!(&out[..3], &[1.0, 2.0, 3.0]);
173        assert!(out[3..].iter().all(|&v| v == 0.0), "new axes zero-padded");
174        // Too-small target refuses.
175        assert!(!bridge_dimensions(&low, &mut [0.0; 2]));
176    }
177
178    #[test]
179    fn wave_eval_at_origin_peak() {
180        // origin (envelope=1), f=0, phi=π/2, t=0 → sin(π/2)=1 → Ψ = a.
181        let c = WaveCoord {
182            x: 0.0,
183            y: 0.0,
184            z: 0.0,
185            t: 0.0,
186            f: 0.0,
187            a: 2.0,
188            phi: PI / 2.0,
189        };
190        assert!((wave_eval(&c) - 2.0).abs() < 1e-9);
191        // Off-origin attenuates: same wave at r²=3 (x=y=z=1) → 2 * 1/(1+3) = 0.5.
192        let c2 = WaveCoord {
193            x: 1.0,
194            y: 1.0,
195            z: 1.0,
196            ..c
197        };
198        assert!((wave_eval(&c2) - 0.5).abs() < 1e-9);
199    }
200
201    #[test]
202    fn continuous_signal_crosses_into_a_fact() {
203        let samples = [1.0, 1.0, 1.0]; // trapezoid: 1 + 1 = 2
204        assert!((integrate_abs(&samples) - 2.0).abs() < 1e-9);
205        let fact = q_hash("fact:emfLimitExceeded");
206        // Over threshold → the fact is instantiated.
207        assert_eq!(continuous_to_fact(&samples, 1.5, fact), Some(fact));
208        // Under threshold → no fact.
209        assert_eq!(continuous_to_fact(&samples, 5.0, fact), None);
210    }
211}