Contents
Where this sits
The reference takes the step and polystep, and feeds the browser core and the proofs page.
Install and run
# from Pages/Geometric Calculator/Hyperbolic PolyStep/reference python3 -m venv .venv && . .venv/bin/activate pip install --index-url https://download.pytorch.org/whl/cpu torch # CPU build (or plain `pip install torch`) pip install -r requirements.txt # polystep 1.1.1, numpy, pytest python -m pytest -q tests # 82 tests, about half a minute python run_traces.py # writes traces/*.json for the browser core python run_bench.py smoke # every benchmark and method once, tiny sizes
The PyTorch CPU index was unreachable, so the default PyPI build of torch (2.15) was installed; it runs on the CPU too. Its first import takes most of a minute, which is most of the test suite’s first-run time.
Module map
Six modules in reference/hpstep/, two runners, and the tests. Arrows point from a module to the modules that use it. Hover a box to light up its connections.
| Module | Holds | Key names |
|---|---|---|
| prng.py | The shared generator: xoshiro128** seeded by splitmix32, and the draws built on it | Rng, next_u32, random, below, sample, rational |
| hyperbolic.py | The hyperboloid in float: the Lorentz form, boosts, exp and log at the origin, charts, the Lorentzian centroid and its Klein weights | lorentz, boost, exp_at, lorentz_centroid, klein_weights |
| exact.py | The exact track: rational linear algebra, Cayley rotations, the ghost map, exact corners, the snap, Lorentz displacements and the pump | cayley, ghost, point_at, snap, displacement, pump |
| step.py | The hyperbolic step and its curvature-0 counterpart on product spaces; polystep’s solvers for the weights; exact mode; the horizon; elitist incumbents | StepConfig, PolyStepH.step, clamp |
| problems.py | B1–B4: instances, float and exact decoders, objectives, Helix B; the anchored tree embedding; memory words | ThreeColouring, MaxSat, TreeAddress, HardThresholdNet |
| channels.py | Three channels on the 24-frame schedule: pairing, Helix B, the clutch modes, the membrane, memory and the exact register | TriChannel, schedule_facts, ON, OFF |
| run_traces.py | Writes the seeded traces the browser core must reproduce | traces/*.json |
| run_bench.py | The preregistered runners, tuning and the decision rule | smoke, tune, run, decide |
Using the step
from hpstep import Rng, PolyStepH, StepConfig, TriChannel from hpstep.problems import ThreeColouring prob = ThreeColouring(60, 4.4, Rng(1000)) # B1: n = 60, average degree 4.4 cfg = StepConfig(epsilon=0.5, step_radius=0.6, block=8) # move 8 vertices per step solvers, states = [], [] for j in range(3): # channels A, B, C s = PolyStepH(prob, prob.m, 2, cfg, Rng(10 + j)) states.append(s.init_state(prob.init_points(Rng(20 + j), 4))) solvers.append(s) tc = TriChannel(solvers, states, prob, clutch='membrane').run(budget=24_000) print(tc.memory[-1]) # the last zero point's word: certified costs, their sum Y, the chain link
StepConfig covers:
- the temperature and the radii, as floats or polystep schedules such as
CosineEpsilonandPowerDecay; - the solver (
'softmax'or'sinkhorn'); - the geometry (
'hyperbolic'or'flat'); - the rotation (
'cayley','cayley_exact'or polystep’s'haar'); - exact mode, the snap grid and the horizon;
probe_jitter, for polystep’s theory mode.
What the tests check
82 tests, all passing: the 80 of Phase 1, and two added in Phase 4. One checks that the batched membrane equals the factor loop; the other, that float states stay on the sheet (Amendment 3). The properties are checked on random instances, in exact arithmetic wherever the claim is exact.
| Claim | Check | Instances | Result |
|---|---|---|---|
| H1 | Every corner, probe and snapped state satisfies \(\langle y,y\rangle = -1\) exactly; one-factor steps build their corners exactly, product steps snap them | 1,000 + products | pass |
| H2 | One factor moves at most r; in a product each factor moves at most r; the horizon never lengthens a move | 1,300 + 300 | pass |
| H3 | No nearby point of the sheet beats the centroid’s weighted Lorentzian distance | 1,000 | pass |
| H4 | Corners at \(gx\) equal \(g\) times corners at \(x\) exactly, for rational Lorentz \(g\); the step agrees to \(10^{-9}\) | 1,000 | pass |
| H5 | At curvature \(-c\) the step approaches the flat step, the gap shrinking at least fivefold per decade of \(c\) | c = 10⁻² … 10⁻⁵ | pass |
| H6 | Tiny ε lands on the best corner; the incumbent never rises | 1,000 + run | pass |
| H7 | Q⁽¹⁰⁾ = Q⁽⁸⁾ = H = P⁻¹ exactly in the Lorentz group, and P carries the register’s first state to its last | 50 registers + 2 live | pass |
| polystep parity | The weights are polystep’s SoftmaxSolver; the curvature-0 step lands where polystep.PolyStep.step lands, given the same rotation, for both solvers | 2 | pass |
| Problems | Decoders agree exactly and in float; Helix B equals the search cost; polystep’s MAX-SAT generator reproduced; tree words distinct, right-division recovers them, anchored decoding exact; B4 shapes | 9 tests | pass |
| Schedule | Onloads at k = 2, offloads at k = 6, twelve frames apart, never sharing a frame, two packets in flight at most; 30 steps per channel per register; the budget counted exactly | 5 tests | pass |
| Generator | The published xoshiro128** vector from state (1, 2, 3, 4) | 3 tests | pass |
These checks are numerical and exact evidence, not proofs. The claims ledger now marks H1–H7 as COMPUTED; the written proofs that would make them PROVEN are Phase 4.
Three findings from building it
The Phase 0 pages said polystep makes no convergence claim. Its experiment code shows otherwise: its paper proves a convergence theorem in a “theory mode”. That mode uses a power-decay step radius \(r_t = r_0(t+1)^{-(1/2+\gamma)}\), square-summable and not summable, with a flat ε and probe jitter. The pages are corrected. Whether the theorem transfers to the hyperbolic step is a new open row in the ledger, T1, and the reference implements theory mode so that it can be tested.
B3’s deepest targets are about 24 units from the origin. There the hyperboloid coordinates are near \(e^{24} \approx 10^{10}\), and the constraint \(\langle y,y\rangle = -1\) falls below float64’s resolution: a depth-8 node computed from the root has \(\langle y,y\rangle \approx -48\). The limit sits near distance \(\tfrac12\ln(1/\varepsilon_{\text{mach}}) \approx 18\). The fix is the standard one for hyperbolic embeddings (a tiling-based model): each point is held in the frame of a tree node near it, and re-anchored after every step. The step does not care which frame it runs in (H4), so nothing about the method changes. A test now pins the failure, so it cannot quietly return.
A colour depends only on a point’s angle, and a truth value only on a sign, so nothing stops particles drifting outward. In a trace run one did, past distance 18, where the exact snap’s \(2^{-24}\) grid can no longer hold it, and the next centroid overflowed. Every factor now stays in a ball of radius 8, the same in both geometries. A point that leaves is moved radially back: the nearest point of a convex ball, so a move never gets longer (H2 survives) and the decoded answer never changes. The membrane’s recentring has to respect it too; at first it did not.
Findings 2 and 3, and two smaller choices, are recorded in the preregistration as Amendment 1, dated before any tuning or measured run. None changes a preregistered size, budget, metric or decision rule.
Traces for the browser
Phase 2’s JavaScript core is trusted only if it reproduces these files. Rationals are written as "p/q".
| File | Holds | Must match |
|---|---|---|
| prng.json | The published vector, seeded outputs, floats, bounded draws, a sample, rationals and a Cayley rotation | Exactly |
| geometry.json | Ghost map, exp at a point, distance and Klein chart on 12 cases; exact ghost points and boosts | Exact fields exactly, floats within \(10^{-12}\) |
| step_b1.json | 24 steps of one channel on a 9-vertex 3-colouring, one vertex per step: rotations, exact corners, costs, weights, snapped states, Helix B | Rotations, corners, costs, states and counts exactly; weights within \(10^{-12}\) |
| channels_b1.json | Three channels for two registers with the membrane: memory words, 60 steps each, both registers closing with H = P⁻¹ | Exactly |
The benchmark runner
python run_bench.py smoke # checks the code runs; results are labelled smoke, never evidence python run_bench.py tune B1 # Phase 4: 24 tuning runs per method, seeds 9000-9023 -> settings.json python run_bench.py run B1 # Phase 4: every cell, instance and seed -> results/B1.jsonl python run_bench.py decide B1 # Phase 4: the paired bootstrap decision per claim and cell
| Method | What it is | Role |
|---|---|---|
| hyper3 | Three channels of 4 particles on the clock, hyperbolic step | The method |
| flat3 | The same at curvature 0 | Primary baseline for C1 |
| hyper1 | One channel of 12 particles | C3 ablation |
| hyper3_free | Membrane off | Membrane ablation |
| polystep | polystep 1.1.1 itself: PolyStep on the flattened problem, PolyStepOptimizer for B4 | Second baseline |
| random | Random search; random address order without replacement on B3 | Floor; B3’s control |
The smoke run completes every benchmark with every method at tiny sizes and untuned settings. Its numbers say nothing about any claim. For C2, every hyperbolic step of B1 and B2 logs its Klein length and the block’s mean Klein radius, and each run reports their Spearman correlation.