The 64-byte enwik9 prefix, settled one time step at a time under
live settling rules. A time step in f is one application of the total
(visible) pattern — the part of P inside the window of indeterminacy — and it is
built from pattern applications, three per unclamped position: forward
k=1, backward k=1, and the k=2 token. Spec:
#p8v2_e64_viewer_goal_20260805;
prerequisites:
#hutter_e64_viewer_prereq_20260805.
#viz_standard, "Versioning a viewer".
One LPP's contribution to one position, computed from one neighbouring source position. Three per unclamped position per time step: forward k=1 from the position to the left, backward k=1 from the right, and the k=2 token from the two to the left through the AND gate. The step bar counts them; it is the same count the compressor reports as its settling cost.
Each entry of an application is min(w_p, w_s) — the pattern's own
weight capped by the source's activation. That is the inner min of the UM's
max-min forward pass, f_p(t)_j = max_i min(t_i, p_ij), with the
source restricted to its argmax event by the admitted optimization (exact when the
source is absolute, an approximation elsewhere; the detail pane unfolds it by
naming the source event). Under A1 the forward and backward applications are then
combined with the outer max. So the machinery here is not
new: it is the forward pass written out longhand.
Two places that departure matters, and both are visible on this page:
#f-p8 argues that is correct because k=2 is a subset of k=1 and the
two are fully correlated. It is also exactly why axis D can remove nothing: the
settled argmax at a candidate position is then just the causal composite
prediction, which is wrong there by construction. That is Q4.Every weight on this page is a log support: the value v
stands for a magnitude of about 2v, which is why 255 is an absolute
rule and 1 is a thing seen once. That is the whole reason the arithmetic below is
not the arithmetic it looks like. Nothing on this page names an operation without
a row here.
| operation | in ordinary arithmetic | saturates | draws from the entropy stream |
|---|---|---|---|
| min(wp, ws) | the smaller of the two. It is the whole of a pattern application's entry: the pattern's own weight, capped by how strongly its source is active. | no | no |
| the outer max | the larger of the two. Two applications arriving at one position keep the stronger; neither reinforces the other. This is what A2 and A3 replace. | no | no |
| LSA addition | adding the magnitudes, not the values. Equal values give one more than either — 2v+2v is 2v+1. Values d apart give the larger one, except that with probability 2−d it rounds up by one instead, which is how the fraction that will not fit in a byte is carried. |
at 255 | yes — one draw per unequal pair |
| LSA subtraction | the difference of the two values, which is the ratio of the magnitudes. Never negative: below zero it is zero, and a zero is silence, not impossibility. | at 0 | no |
| the LSA total of a position | LSA addition folded across all 256 entries from index 0 upward, giving the magnitude of the whole vector. A3 uses it to find how far the position overshoots a constant sum. | no — A3 needs the overshoot, so the fold is left to run past 255 | yes — up to 255 draws |
| the ceiling of the base-2 logarithm | how many bits it takes to name one of n things: 0 for one, 1 for two, 2 for three or four, 3 for five to eight. B1 charges it to every predecessor when it divides a backward weight over the set that leads to the same byte. |
no | no |
| wp − (255 − ws) | the rejected application rule, kept as a control. It charges the source's distance from certainty against the pattern, so anything short of an absolute source annihilates the application. Drive it and watch the window collapse. | at 0 | no |
The two rows that draw from the entropy stream are the reason a
variant can be uncheckable: the stream is shared with learning, so by the time
settling starts it sits wherever learning left it, and a recomputation cannot land
on the same draws. Which variants that costs is counted above, under the
conformance check, rather than asserted here. Implementation:
#pp_lsa, in ../cmpr-src.
| byte | the sample. Non-printable bytes are shown as ·; the detail pane gives the value. |
| argmax | the settled argmax at this time step — the largest entry of the position's LSA vector, ties to the smaller index. Blue = clamped (the trace records it, so it is held at 255 on its own event and never updates). Green = agrees with the byte, red = disagrees. |
| w1 | the weight of that entry. Clamped positions read 255. |
| chg | shaded where this time step changed the position's argmax. When the whole row is clear, the window's argmax sequence has stopped changing — that step is conv. |
| control | what it changes |
|---|---|
| A1 A2 A3 | The update rule — this is f. A1 assignment: the longest k that fires assigns. A2 LSA addition against decay of 2 units per step. A3 addition with renormalisation to constant sum 255. Applied live. |
| B1 B2 | The backward k=1 application. B1 reconstructs it from the forward argmax table by normalising over the predecessor set, each predecessor paying the ceiling of the base-2 logarithm of how many there are. B2 reads a stored 65536-byte LPP. Applied live — but only one model carries that LPP, so B2 is refused where it would be borrowed from a model with a different learned k=1. |
| C1 C2 | The AND gate at partial activation. C1 min(w_a,w_b). C2 sums and thresholds at 128, activation sum−128 capped at 255. Applied live. |
| min / sub | The application rule (Q5). min(w_p,w_s) is what every run used. w_p−(255−w_s) is the form that was tried and rejected. It is implemented in no variant, so there is no dump of it and every frame under it is unverified, including the endpoint. The agreement readout under it is the viewer's own computation, live from the model on screen, not a quoted measurement. Set it on the baseline and step: every non-absolute application dies one hop from a clamped position and the window collapses. |
| D E F | Which learned model is loaded. Unlike A/B/C these are not settling rules: sparsification, replay and pruning change what was learned and recorded, so each selects a different model file rather than a different computation. Only single-axis combinations were run, so setting two of them away from the baseline has no model and is refused. |
| steps | How far f runs (Q7). An application travels one position per time step, so stopping short of W leaves the far end of the window on its initial state. Drive it on the baseline and the agreement readout gives 11, 12, 14, 27, 49, 62, 64 at 1, 2, 4, 8, 16, 24 and 32 steps: the window is fully settled by 32, and stopping at 24 costs two positions. The step count is what these numbers measure; the application rule is a separate control, and under w_p−(255−w_s) agreement is 10 of 64 at every step count. Both are reproducible here. |
Diagnostics from gen2.tsv. D and F genuinely coincide with the baseline at 64 bytes — every context is kept, so a prune rule has nothing to prune, and the settled state is never consulted by D1's causal pass. They keep their controls anyway: a control whose alternatives coincide at this sample is still a control, and it says so here rather than being omitted.
And the measured e64 values of those columns, from gen2.tsv:
min(255, ws), which is the source's activation passed
through unattenuated. On a log-support scale those are not near-misses. 1 says
seen once; 255 says an absolute rule.
../cmpr-src's to fix, in whichever direction it decides. It reports
both, in the detail pane, on every forward application, rather than quietly
printing the one that agrees with what the engine did. The k=2 token strengths
have no such gap: the model stores them, the query layer reports them, and the
shell applies them, and all three agree.
| models/p8v2/enwik9/64/ | the retained models; k=1 argmax table at offset 48, backward LPP at 304, then four bytes per token rule. No k=0 section |
| gen2-pos/ | the recorded endpoints the conformance check compares against |
| gen2.tsv | measured facts, including the e64 settling diagnostics above |
| axes.json | the axes, their alternatives and the definitions on this page — the page reads it, it is not copied here |
| the generation 2 report | what these runs say, and the picks it asks for |
| p8v2-words.md | the fixture; § Axis A is the settling shell this page implements |
| build-p8v2-e64 | rebuilds this page. Runs no compression |
| #pprog_p8v2_gen2_goal_20260806 | the goal generation 2 was run against, and what it reserved each variant id for |
| p8v2-gen1/ | the generation panels: every variant of a generation over the same input positions. Generation 1's runs are comparable with these, having been re-run post-k=0 |
| #hutter_e64_viewer_prereq_20260805 | the prerequisites this was built against |
| #p8v2_e64_viewer_goal_20260805 | the goal this was built from |
| #hutter_publication_handoff | the division of labour, and what is not a result |
| #variant_protocol | why there is no winner here |
Published under #viz_standard. Self-contained: no
external stylesheet, no script, no font, no image, nothing fetched. Data
symlinked from ../cmpr-src/tests/pprog/; page regenerated by
docs/pprog/build-p8v2-e64, never hand-edited. The blocks are the
authority.