Contents
Where this sits
The simulation is the end of the build: it runs the browser core, which reproduces the Python reference, and shows the three channels, the step, the memory and Helix B working together. Its results feed the proofs-and-results page of Phase 4.
Quick start
- Open the page. It opens paused at frame 0 with B1 (60 vertices) built, and replays six of the reference’s trace files through the core. The Self-test panel should read 105/105 match within a second or two.
- Press Play (or Space). The clock turns, each channel steps at its offload frame, and every 24 frames a zero point certifies the three incumbents and writes a memory word.
- Watch the answer. On B1, red edges are conflicts in the best certified colouring. The count falls as the channels work. The run pauses itself when the evaluation budget is spent.
- Change something. Every setting except speed rebuilds the run from frame 0, so two runs with the same settings and seed are identical.
Space plays or pauses, . advances one frame and z jumps to the next zero point. Keys are ignored while a control has focus.
How it is wired
The page holds no solver logic of its own. Controls build objects from the core, the core advances them, and the panels read them. The chart shows which control reaches which object and which panel reads which object.
A build makes one problem instance from problem, size, objective and seed; three PolyStepH solvers, one per channel, each with its own generator (seeded \(1000\,s + 10 + j\)) and its own starting particles (seeded \(1000\,s + 20 + j\)); and one TriChannel that owns the clock. Play calls TriChannel.run({ frames }) in batches of at most 24 frames, spending no more than about 28 ms per animation frame, so the page stays responsive at any speed.
Controls
The control bar stays at the top of the screen while you scroll. Changing any setting except speed pauses the run and rebuilds it.
| Control | What it does |
|---|---|
| Play / Pause | Runs the clock at the chosen speed. Pauses itself when the evaluation budget is reached. |
| +1 frame | Advances exactly one frame. A channel steps only on its offload frame, so most single frames change the clock and nothing else. |
| → zero point | Advances to the next frame with \(n = F \bmod 24 = 0\), where certification, the memory word and the clutch happen. |
| Reset | Rebuilds the current settings at frame 0. |
| speed | Frames per second, on a log scale from 1 to about 2,500. The default is 40. At high speeds the page runs as many frames as fit in its time slice, so the true rate depends on the problem. |
| problem | B1 planted 3-colouring, B2 MAX-3-SAT at clause ratio 4.27 (polystep’s own generator), B3 address search in the norm-5 quaternion tree, B4 a hard-threshold network on hierarchical data. Choosing one loads its defaults (below). |
| size | B1: 30, 60 or 120 vertices. B2: 100, 200 or 500 variables. B3: depth 4, 6 or 8 (750, 18,750 or 468,750 addresses). B4: 500 or 2,000 training points. |
| objective (B3 only) | graded scores a point by its tree distance to the target; membership only says whether it is the target, the control from the preregistration. |
| geometry | hyperbolic runs the step on the hyperboloid; curvature 0 runs the same step in flat space, the comparison every benchmark makes. |
| clutch | What the zero point does after certifying. free: nothing. hold: a channel with three zero points without improvement rests (takes no steps) until another channel improves, and at least one channel always runs. membrane: every channel moves a fraction \(\mu\) of the way towards the weighted common point of the three incumbents. B3 cannot use the membrane, because its particles live in different charts, and runs it as free. |
| \(\mu\) | The membrane’s pull, from 0 to 0.8. Each channel’s particles move by one rigid motion (a transvection in hyperbolic factors) that takes its incumbent \(\mu\) of the way to the common point. |
| \(\varepsilon\) | The softmax temperature that turns the polytope’s corner costs into weights. Small \(\varepsilon\) chases the best corner; large \(\varepsilon\) averages. |
| r | The step radius: corners sit at hyperbolic distance r from the particle (H2: a step never moves a point further than r). |
| particles | 2, 4 or 8 particles per channel. Each particle costs \(2d\) evaluations per factor it steps. |
| seed | Seeds the instance and, through the formulas above, every generator. Same settings and same seed give the same run. |
| exact track | B1 and B2, hyperbolic only. Corners come from exact Cayley rotations and rational step lengths, states are snapped to the \(2^{-24}\) Poincaré grid and held as rationals, one factor moves per step, and every 720-frame register closes with the pump check (chapter 6). |
| Problem defaults | \(\varepsilon\) | r | factors per step | clutch | budget (evaluations) |
|---|---|---|---|---|---|
| B1 3-colouring | 0.5 | 0.6 | 8 | membrane | 400 × n |
| B2 MAX-3-SAT | 0.05 | 0.5 | 4 | membrane | 300 × n |
| B3 tree address | 0.5 | 2.0 | all (one) | free | the number of addresses at that depth |
| B4 threshold net | 0.05 | 0.3 | 6 | membrane | 200,000 |
B3’s budget equals the number of addresses, so the search is allowed exactly what exhaustive enumeration would need.
Panels and readouts
The Poincaré view
What it draws depends on the problem.
- B1 and B2: one factor of the product space, as a Poincaré disk (or, at curvature 0, the plane scaled so the horizon of radius 8 is the edge). Solid dots are each channel’s particles; rings are each channel’s incumbent. The faint spokes are the last step’s polytope: geodesics from each particle to its \(2d\) corners, with corner dots sized by their softmax weight. On B1 the three tinted sectors are the three colours; a vertex takes the colour of the sector its point lies in. On B2 the factor is a point of \(H^8\) and the view shows its first two axes; a variable is true when its point lies on the positive side. The view starts on factor 0; on B1, click a vertex in the answer panel to show its factor. The spokes appear only when the last step moved the factor on show, so with 8 of 60 factors per step they come and go.
- B3: the tree drawn in the frame of channel A’s best particle’s anchor node, one level up and three down. Every edge is a geodesic, so the tree fans out towards the rim, as trees do in hyperbolic space. The gold path leads to the target. The dots are particles anchored at this node.
- B4: the eight class prototypes of the best certified network (rings, numbered) and up to 250 test inputs mapped through its encoder, coloured by true class. The network assigns each input to its nearest prototype.
The clock
The dial shows the eight spinor stages (Snap, Seed, Onload, Project, Invert, Fold, Offload, Index) with the current one lit, \(k = F \bmod 8\). The three inner arcs are the branches, \(j = F \bmod 3\). Beside the dial, each channel’s packet: in flight for the 12 frames from its onload (\(n\) = 18, 10, 2) to its offload (\(n\) = 6, 22, 14), where it steps. The strip below lays out the whole 24-frame joint cycle, with ▼ at each offload. The readouts give the register (720 frames), the spinor cycle (90 per register), the joint cycle (30 per register) and, on the exact track, the pump result. The bar fills through the current register.
The answer
Helix B’s view: the best certified answer so far, decoded and checked exactly.
- B1: the graph on a circle, vertices coloured by their decoded colour, conflicting edges in red. conflicts (exact) is the integer count; 0 means a proper colouring.
- B2: one cell per variable (green true), and the share of clauses satisfied. unsatisfied clauses (exact) is the integer count.
- B3: the target address and each channel’s decoded incumbent, digit by digit; green digits agree with the target from the root. best tree distance 0 means the target was found, and certified by right-division confirms the decoded word divides back out of its quaternion of norm \(5^L\).
- B4: the confusion matrix on held-out test data (rows true class, columns predicted), test accuracy, accuracy at the coarse level of the class tree, and the exact count of training errors, which is what Helix B certifies.
Channels
One row per channel: steps taken, evaluations used, the incumbent’s objective value (the search’s own, possibly graded, score), its best certified cost, how many zero points since it last improved (stale), and whether it is running or resting. The chart plots each channel’s certified cost at every zero point. Below it: evaluations against the budget, the number of zero points, the memory chain and the largest move the membrane made at the last zero point.
The memory words list the latest eight records: frame, the three certified costs, their sum Y, the winning channel and the hash. Each hash is SHA-256 of the record together with the previous hash, cut to 16 hex digits. On every redraw the page recomputes the whole chain from the first word and shows intact only if every hash follows.
Self-test and log
The self-test replays the reference’s trace files through the core on this page, exactly as the core reference does: 105 lines from six files on load, and all 169 with Run all seven, which adds three channels over two full exact registers. The log lists builds, every improving zero point, channels resting and waking, closed registers and the self-test result, newest first.
The exact track
With the exact track on, every state is a rational point on the sheet, so its history can be checked exactly. Each register is checked with the paper’s 720 → 72 → 10 pump.
Whenever a particle’s factor moves, at a step or in the membrane, the core records the exact Lorentz matrix that moved it, \(\Delta = L_{x_\text{new}} L_{x_\text{old}}^{-1}\), in that frame’s slot. Frames where the factor did not move hold the identity. At frame 720 it forms, for every channel, particle and factor:
2397P = \Delta_{720}\cdots\Delta_1,\qquad Q_{10} = \prod_{m} \delta_m,\qquad Q_8 = \prod_{\ell}\Big(\prod_{m \in \text{block } \ell} \delta_m\Big),\qquad H = Q_8\,Q_{10}\,P,2397
where \(\delta_m\) is the inverse of the product over the \(m\)-th run of ten frames. It then checks \(Q_{10} = Q_8 = H = P^{-1}\) and that \(P\) carries the register’s starting point exactly to its final point. The clock panel’s pill reads closed with H = P⁻¹ only when every check holds for every factor of every particle of every channel.
With the membrane on, every factor moves at every zero point, so a register holds about 30 non-identity matrices per factor. For B1 with 30 vertices and 4 particles that means 360 pumps per register. The first version reduced every rational entry after every product. A register then took 48 seconds, 44 of them in the pump, nearly all spent computing greatest common divisors. The core now runs the pump on integer matrices over one common denominator, never reduces them, and compares by cross-multiplication. It also skips identity frames, builds the Lorentz inverse as \(J L^\top J\) without multiplying, and sums each matrix entry before reducing it once. A whole register now takes about 2.7 seconds, half a second of it in the pump at frame 720.
It shows that the exact track’s bookkeeping is closed: the states recorded across a register compose to the motion actually made, and the paper’s regrouping identity holds exactly in the Lorentz group (H7). It says nothing about the quality of the answer. That is Helix B’s job.
Experiments
Each link opens the simulation with the settings filled in. The results quoted are single runs with seed 1000 to the full budget, computed with the same core. They show what to look for. They are not evidence for or against any claim (chapter 9).
1. Hyperbolic against flat B1 hyperbolic B1 flat
Run both to the budget and compare the certified conflicts. Then do the same at B2, n = 100 and its flat twin.
seed 1000: B1 n=60 hyperbolic 4, flat 2 · B1 n=30 hyperbolic 1, flat 2 · B2 n=100 hyperbolic 21, flat 19 unsatisfied
Single runs show no consistent edge either way. Whether the hyperbolic step beats curvature 0 at equal budget is conjecture C1, tested on B1, B3 and B4. It is decided by the preregistered runs over many seeds, not by any one run here.
2. The clutch membrane free hold
With hold, watch the Channels panel: stalled channels rest and spend no evaluations, so the same budget lasts more frames. With membrane, watch the Poincaré view jump at each zero point as the channels are pulled together.
seed 1000, B1 n=60: membrane 4, free 6, hold 4 conflicts · hold used 2,390 frames for the same 24,064 evaluations, against 1,502
3. The graded objective and its control B3 graded B3 membership
The same tree, the same target, the same budget. Graded scoring tells the search how far it is from the target; membership only tells it whether it is there.
seed 1000, depth 6: graded found the target (distance 0, first certified at frame 312); membership ended at distance 12, the largest possible at depth 6 (not even the first digit agrees). At depth 8 membership ended at 16, again the largest.
A gradient-free search still needs a signal. Against membership alone, no method can beat blind sampling (Prop 5.13 of the paper), and the preregistration uses that as a check on the implementation: under membership, evaluations to the target must match \((N + 1)/2\), and anything faster is treated as a bug.
4. Temperature B2, ε = 0.05 B2, ε = 0.5
Watch the corner dots in the Poincaré view. At small \(\varepsilon\) one corner takes nearly all the weight; at large \(\varepsilon\) the weights spread and the step averages.
seed 1000, n=100: ε 0.05 ended at 21 unsatisfied, ε 0.5 at 23
5. Close a register exactly B1, n = 30, exact
Press z repeatedly, or play at high speed, until frame 720. The page pauses for about half a second at frame 720 while it runs the pump. The log then shows register 1 closed: pump Q10 = Q8 = H = P^-1 exactly and the clock pill turns green.
6. The self-test, in full open
Press Run all seven. All 169 lines should match, including the three-channel trace, whose memory hashes and two closed registers must agree with Python’s bit for bit.
7. Training without gradients B4, 500 points
The network has hard thresholds, so it has no useful gradient. Watch the training errors fall at the zero points and the prototypes separate in the Poincaré view. With eight classes, chance is 12.5%.
Scripting and links
The page reads its settings from the address and exposes its run to the browser console.
| Address parameter | Values |
|---|---|
| prob | B1, B2, B3, B4 |
| size | a value from that problem’s size list (30/60/120, 100/200/500, 4/6/8, 500/2000) |
| geo | hyperbolic, flat |
| clutch | membrane, free, hold |
| obj | graded, membership |
| mu, eps, r | numbers, clamped to the sliders’ ranges (eps 0.01–2) |
| P, seed | 2, 4 or 8 particles; a seed from 1 to 999,999 |
| exact, play | 1 turns the exact track on (where allowed) or starts playing at once |
HPSim.advance(720) // run 720 frames now
HPSim.render() // redraw the panels
HPSim.sim.tc.memory // every memory word: { F, costs, Y, best, hash }
HPSim.sim.tc.registers // [{ F: 720, pump_identity: true }, ...]
HPSim.sim.states[0].X // channel A's particles, float coordinates
document.body.dataset.frame // the current frame, also set for tests
Reading results honestly
- One run is an anecdote. The page runs one seed at untuned defaults. The benchmark decisions come from the preregistered runs of the Python reference: many seeds, tuned on separate seeds, with fixed decision rules. Those runs are Phase 4.
- The certificates are exact; the search is not guaranteed. A certified 0 is a proof that the answer is correct. A certified 4 says only that the search found nothing better within its budget.
- B4 runs are the browser’s own. Its data come from Box–Muller sampling, which is not traced, so a B4 run here need not match the reference’s with the same seed.
- Sizes are small. The core is plain JavaScript with BigInt rationals. The page shows tens to hundreds of variables, not the reference’s largest cells.
- No convergence claim. The paper’s convergence theorem covers polystep’s theory mode, not these settings, and its hyperbolic analogue is open (ledger row T1).