Skip to main content

logicaffeine_proof/
cubical.rs

1//! A general **`d`-dimensional cubical-homology engine** — one engine, every rung of the ladder.
2//!
3//! `progress_complex` produced `π₁` (2 processes) and `π₂` (3 processes) with hand-built 2D and 3D
4//! complexes. Rather than write a 4D one, then a 5D one, this is the lift: a single cubical complex in
5//! *any* dimension, computing the full Betti vector `(β₀, β₁, …, β_d)` over `GF(2)`. Then the ladder is
6//! literal — **`d` processes → a `(d−1)`-sphere void → `π_{d−1}` ≠ 0** — and walking it toward the
7//! `∞`-groupoid is just "one more process, one more dimension," handled by the same code.
8//!
9//! An elementary cube is a [`Cube`]: a minimal corner plus the set of free axes it extends along (its
10//! dimension). Its boundary is the `2k` faces obtained by pinning each free axis low or high. From a set
11//! of filled top cells we take the downward closure, build the boundary matrices `∂_k`, and read
12//! `β_k = #C_k − rank ∂_k − rank ∂_{k+1}` — homology with no shortcuts, in arbitrary dimension.
13
14use crate::progress_complex::gf2_rank_wide;
15use std::collections::{BTreeSet, HashMap};
16
17/// An elementary cube: the minimal corner, and the sorted set of axes it extends along (each by one
18/// unit). The dimension is the number of free axes; fixed axes hold the corner's value.
19#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
20pub struct Cube {
21    pub corner: Vec<usize>,
22    pub dirs: Vec<usize>,
23}
24
25impl Cube {
26    pub fn dim(&self) -> usize {
27        self.dirs.len()
28    }
29
30    /// The `2k` boundary faces — for each free axis, the lower face (pin it at the corner) and the upper
31    /// face (pin it at corner + 1). Over `GF(2)` the boundary is their unsigned sum.
32    pub fn boundary(&self) -> Vec<Cube> {
33        let mut faces = Vec::with_capacity(2 * self.dirs.len());
34        for (idx, &a) in self.dirs.iter().enumerate() {
35            let mut sub = self.dirs.clone();
36            sub.remove(idx);
37            faces.push(Cube { corner: self.corner.clone(), dirs: sub.clone() });
38            let mut up = self.corner.clone();
39            up[a] += 1;
40            faces.push(Cube { corner: up, dirs: sub });
41        }
42        faces
43    }
44}
45
46/// A cubical complex, stored as the cells of each dimension `0..=dim`.
47pub struct CubicalComplex {
48    cells: Vec<BTreeSet<Cube>>,
49    dim: usize,
50}
51
52impl CubicalComplex {
53    /// Build from filled top-dimensional cells, taking the downward closure (all faces of all faces).
54    pub fn from_top_cells(top: Vec<Cube>) -> Self {
55        let dim = top.iter().map(Cube::dim).max().unwrap_or(0);
56        let mut cells: Vec<BTreeSet<Cube>> = vec![BTreeSet::new(); dim + 1];
57        for c in top {
58            let d = c.dim();
59            cells[d].insert(c);
60        }
61        for k in (1..=dim).rev() {
62            let current: Vec<Cube> = cells[k].iter().cloned().collect();
63            for c in current {
64                for f in c.boundary() {
65                    cells[f.dim()].insert(f);
66                }
67            }
68        }
69        CubicalComplex { cells, dim }
70    }
71
72    /// The progress complex of `d` processes with the given step `lengths`: every grid `d`-cell is
73    /// filled, except those in `forbidden` (the mutual-exclusion / synchronization region).
74    pub fn progress(lengths: &[usize], forbidden: &[Vec<usize>]) -> Self {
75        let d = lengths.len();
76        let forbidden: BTreeSet<Vec<usize>> = forbidden.iter().cloned().collect();
77        let mut top = Vec::new();
78        let mut idx = vec![0usize; d];
79        loop {
80            if !forbidden.contains(&idx) {
81                top.push(Cube { corner: idx.clone(), dirs: (0..d).collect() });
82            }
83            let mut a = 0;
84            while a < d {
85                idx[a] += 1;
86                if idx[a] < lengths[a] {
87                    break;
88                }
89                idx[a] = 0;
90                a += 1;
91            }
92            if a == d {
93                break;
94            }
95        }
96        CubicalComplex::from_top_cells(top)
97    }
98
99    pub fn dim(&self) -> usize {
100        self.dim
101    }
102
103    pub fn num_cells(&self, k: usize) -> usize {
104        self.cells.get(k).map_or(0, BTreeSet::len)
105    }
106
107    /// `rank ∂_k` over `GF(2)` — the boundary map from `k`-cells to `(k−1)`-cells.
108    fn boundary_rank(&self, k: usize) -> usize {
109        if k == 0 || k > self.dim {
110            return 0;
111        }
112        let lower: Vec<Cube> = self.cells[k - 1].iter().cloned().collect();
113        let ncols = lower.len();
114        if ncols == 0 {
115            return 0;
116        }
117        let lidx: HashMap<Cube, usize> = lower.into_iter().enumerate().map(|(i, c)| (c, i)).collect();
118        let rows: Vec<Vec<u64>> = self.cells[k]
119            .iter()
120            .map(|c| {
121                let mut row = vec![0u64; ncols.div_ceil(64)];
122                for f in c.boundary() {
123                    let idx = lidx[&f];
124                    row[idx / 64] ^= 1u64 << (idx % 64);
125                }
126                row
127            })
128            .collect();
129        gf2_rank_wide(rows, ncols)
130    }
131
132    /// The Betti vector `(β₀, …, β_d)`: `β_k = #C_k − rank ∂_k − rank ∂_{k+1}` over `GF(2)`.
133    pub fn betti(&self) -> Vec<usize> {
134        let mut ranks = vec![0usize; self.dim + 2];
135        for k in 1..=self.dim {
136            ranks[k] = self.boundary_rank(k);
137        }
138        (0..=self.dim).map(|k| self.cells[k].len() - ranks[k] - ranks[k + 1]).collect()
139    }
140
141    /// `χ = Σ (−1)^k #C_k` — the alternating cell count, equal to `Σ (−1)^k β_k` (Euler–Poincaré).
142    pub fn euler(&self) -> i64 {
143        (0..=self.dim)
144            .map(|k| {
145                let c = self.cells[k].len() as i64;
146                if k % 2 == 0 {
147                    c
148                } else {
149                    -c
150                }
151            })
152            .sum()
153    }
154}
155
156#[cfg(test)]
157mod tests {
158    use super::*;
159
160    fn center(d: usize) -> Vec<Vec<usize>> {
161        vec![vec![1usize; d]]
162    }
163
164    #[test]
165    fn the_general_engine_reproduces_the_hand_built_2d_and_3d_complexes() {
166        // Cross-validation: the general engine must agree with progress_complex's bespoke 2D/3D homology.
167        // 2 processes, one mutex hole ⇒ β = [1,1,0]; 3 processes, forbidden core ⇒ β = [1,0,1,0].
168        let two = CubicalComplex::progress(&[3, 3], &center(2));
169        assert_eq!(two.betti(), vec![1, 1, 0], "2D mutex hole: β₁ = 1 (π₁ = Z)");
170        let three = CubicalComplex::progress(&[3, 3, 3], &center(3));
171        assert_eq!(three.betti(), vec![1, 0, 1, 0], "3D forbidden core: β₂ = 1 (π₂ = Z)");
172    }
173
174    #[test]
175    fn solid_d_cubes_are_contractible_in_every_dimension() {
176        // No forbidden cell ⇒ a solid d-dimensional block, contractible: β = [1,0,…,0], χ = 1.
177        for d in 1..=4 {
178            let lengths = vec![3usize; d];
179            let pc = CubicalComplex::progress(&lengths, &[]);
180            let beta = pc.betti();
181            assert_eq!(beta[0], 1, "connected in dimension {d}");
182            assert!(beta[1..].iter().all(|&b| b == 0), "solid d-cube is contractible (d={d})");
183            assert_eq!(pc.euler(), 1, "χ = 1 for a contractible complex (d={d})");
184        }
185    }
186
187    #[test]
188    fn four_processes_produce_pi_three_a_3_sphere_void() {
189        // THE CRUSH: π₃. Four processes, forbid the center 4-cell — the state where all four are jointly
190        // in the forbidden core. Its eight boundary 3-faces survive, forming a 3-CYCLE that no longer
191        // bounds: a hollow 3-SPHERE (S³). So β₃ = 1, π₃ = Z. The general engine produced the next rung
192        // with no new code — just one more process, one more dimension.
193        let pc = CubicalComplex::progress(&[3, 3, 3, 3], &center(4));
194        let beta = pc.betti();
195        assert_eq!(beta, vec![1, 0, 0, 1, 0], "4 processes, forbidden core ⇒ β₃ = 1: a 3-sphere void, π₃ = Z");
196        // Euler–Poincaré: Σ(−1)^k β_k = 1 − 0 + 0 − 1 + 0 = 0, matching the alternating cell count.
197        let alt: i64 = beta.iter().enumerate().map(|(k, &b)| if k % 2 == 0 { b as i64 } else { -(b as i64) }).sum();
198        assert_eq!(alt, pc.euler(), "Euler–Poincaré holds: Σ(−1)^k β_k = χ");
199        assert_eq!(pc.euler(), 0, "χ = 0, the signature of a 3-sphere shell");
200    }
201
202    #[test]
203    fn infinity_is_a_finite_law_checkable_at_every_rung_not_an_object_we_hold() {
204        // "Can we finally understand infinity?" — yes, but honestly. NOT as a finished object we hold:
205        // no single finite complex carries every πₙ. We understand it as a GENERATIVE LAW one finite
206        // engine obeys at every rung — d processes ↦ a (d−1)-sphere void ↦ π_{d−1} = Z — with no largest
207        // rung. Here we push the SAME engine to π₄ (five processes, forbidden core ⇒ a 4-sphere), with no
208        // new code, and check the law holds across d = 2..=5 in one breath. The ∞-groupoid IS this rule;
209        // we grasp infinity by the rule that generates every level, machine-checked at each finite stage.
210        let pc = CubicalComplex::progress(&[3, 3, 3, 3, 3], &center(5));
211        let mut expected = vec![0usize; 6];
212        expected[0] = 1;
213        expected[4] = 1;
214        assert_eq!(pc.betti(), expected, "5 processes ⇒ β₄ = 1: a 4-sphere void, π₄ = Z — the next rung");
215
216        for d in 2..=5 {
217            let beta = CubicalComplex::progress(&vec![3usize; d], &center(d)).betti();
218            assert_eq!(beta[d - 1], 1, "rung d={d}: π_{{d-1}} is realized");
219            assert_eq!(beta.iter().sum::<usize>(), 2, "exactly β₀ and β_{{d-1}} fire — a clean (d−1)-sphere");
220        }
221    }
222
223    #[test]
224    fn homology_is_not_all_the_invariants_pi3_of_the_2_sphere_is_invisible() {
225        // THE HONEST CEILING, machine-checked. Our engine computes HOMOLOGY (Betti numbers), which is
226        // NOT the full set of invariants. Build the 2-sphere as the hollow surface of a cube: β = [1,0,1]
227        // — β₀ = 1, β₁ = 0, β₂ = 1, and nothing in degree 3. Yet π₃(S²) = Z, the Hopf map — a nontrivial
228        // higher homotopy group homology is utterly blind to. So we did NOT lock infinity down to all its
229        // invariants: the homotopy groups of spheres are an OPEN problem in mathematics, in general
230        // uncomputable, and our own engine provably cannot see π₃ here. We hold a generative LAW and the
231        // 1-truncated OBJECT — not the full invariant catalog, which no finite engine can possess.
232        let s2 = CubicalComplex::from_top_cells(vec![
233            Cube { corner: vec![0, 0, 0], dirs: vec![1, 2] },
234            Cube { corner: vec![1, 0, 0], dirs: vec![1, 2] },
235            Cube { corner: vec![0, 0, 0], dirs: vec![0, 2] },
236            Cube { corner: vec![0, 1, 0], dirs: vec![0, 2] },
237            Cube { corner: vec![0, 0, 0], dirs: vec![0, 1] },
238            Cube { corner: vec![0, 0, 1], dirs: vec![0, 1] },
239        ]);
240        assert_eq!(s2.betti(), vec![1, 0, 1], "the cube's surface is S²: β = [1,0,1]");
241        // homology reports degree-3 emptiness; π₃(S²) = Z lives entirely outside what β can see.
242        assert_eq!(s2.dim(), 2, "a 2-dimensional complex — β has no degree-3 term at all, yet π₃ ≠ 0");
243    }
244
245    #[test]
246    fn the_ladder_one_more_process_is_one_more_homotopy_dimension() {
247        // THE LADDER, as a single test. For d = 2, 3, 4 processes, forbidding the center cell of a 3^d
248        // grid produces a (d−1)-sphere void: β_{d−1} = 1 and every other β_k = 0 (but β₀ = 1). Each
249        // added process climbs exactly one homotopy rung — π₁, π₂, π₃ — and the limit of this staircase
250        // is the ∞-groupoid. One engine, every rung, all computed honestly over GF(2).
251        for d in 2..=4 {
252            let lengths = vec![3usize; d];
253            let beta = CubicalComplex::progress(&lengths, &center(d)).betti();
254            assert_eq!(beta.len(), d + 1);
255            assert_eq!(beta[0], 1, "connected (d={d})");
256            for k in 1..=d {
257                let expected = usize::from(k == d - 1);
258                assert_eq!(beta[k], expected, "d={d}: β_{k} should be {expected} (only π_{{d-1}} ≠ 0)");
259            }
260        }
261    }
262}