The 64-byte enwik9 prefix, settled one time step at a time under live settling rules. Select a position; step f; the patterns that reach it light up the data they were learned from. Generation 5, in which f is split in two: what a k=1 application delivers is axis G and what a position does with the applications that reach it over time is axis H, so for the first time the decay rule can be moved with the delivery held still. Below the grid, the k=2 LPP on rings: three memory cell positions and the 65536-event AND that joins the first two. Notes and open questions · what licenses any of this.
| control | what it changes |
|---|---|
| G1 · pass · att | What a k=1 application DELIVERS. Since generation 5 this is an axis of its own (#f-p8-forward, model header byte 42) rather than half of a pair. G1 is the built baseline: the argmax is delivered at min(8, ws), forward and backward agreeing on wp after the backward direction has paid its predecessor split. pass-through delivers ws unchanged — 255 is the identity of min — and attenuate delivers lsa_sub(ws, c), a rate rather than a ceiling, which is the only form in which a strength of 1 can be applied at all. Both are named in #f-p8-forward as the points the axis exists for and neither is built: generation 5 moved the decay axis only, so every frame under them is this viewer's own. Under B2 the stored weights are the delivery and this axis has no effect. |
| H1…H7 | What a position does with the applications that reach it over time (#f-p8-decay, model header byte 43). All seven ran. H1 accumulate, constant fall-off 1 — the baseline, and the same run as generation 4's v024. H2 assignment: the longest k that fires assigns, no accumulation and therefore no decay; the one rule on this axis that draws no entropy. H3 accumulate, constant fall-off 2 — the one-constant control that fills in the corner of the square generation 4 could not measure. H4 renormalise: subtract enough that the position's total support is what the arriving evidence justifies, which is the LSA sum of the supports of the applications that fired. H5 decay by the support deficit smax−s of the strongest arrival. H6 no decay; a pattern of support s is applied only on time steps that are multiples of 2smax−s, so the schedule is the fall-off. H7 decay by the number of applications that arrived. Read every one against the constraint #f-p8-decay states: a uniform fall-off cannot reorder an event space, because lsa_sub is monotone — it can only act through the 0 floor and through what the next time step accumulates. |
| smax | The reference support H5 and H6 measure a deficit from. Which reading the runs used is an open choice, so it is a control and not a constant. |
| B1 B2 | The backward k=1 application. B1 reconstructs it from the forward argmax table, each of the n predecessors paying the ceiling of the base-2 logarithm of n. B2 reads a stored 65536-byte LPP — refused where that would borrow it from a model with a different learned k=1. |
| C1 C2 | The AND gate at partial activation. C1 min(wa,wb). C2 sums and thresholds at 128. C2 never binds at any runnable sample: the learned k=2 weights are 1 and 2 and the gate has nothing to bite on. |
| min / sub | The application rule. min(wp,ws) is what every run used and is frozen normatively in #f-p8. wp−(255−ws) was tried and rejected, is implemented in no variant, and every frame under it is unverified. Set it on the baseline and step: every non-absolute application dies one hop from a clamped position and the window collapses. That collapse is the single most useful thing on this control. |
| D E F | Which learned model is loaded — not settling rules. Sparsification, replay and pruning change what was learned, so each selects a different model file. Only single-axis combinations were run; two at once is refused rather than borrowed. |
| steps | How far f runs. An application travels one position per time step, so stopping short of W leaves the far end of the window on its initial state. |
| preset | The eight runs. Each carries its recorded settled_ok (positions whose settled argmax is the sample byte, clamped ones included, so it is bounded below by the recorded positions, which is why the ladder reports the unrecorded ones separately) and conv (the time step after which the window's argmax sequence stops changing; equal to W means it never did). Anything not on a preset is the viewer's own and is marked as such. |
| byte | the sample. Non-printable bytes are ·. Shaded where the selected pattern or application was learned from, in that application's colour; striped where two of them share a position. |
| argmax | the settled argmax at this time step. Blue = clamped (the trace records it, held at 255 on its own event, never updated). Green = agrees with the byte, red = disagrees. |
| w1 | the weight of that entry, in log support: v stands for a magnitude of about 2v. Over 99 is shown as tens with a subscript zero. |
| bpc | How far this position is from the truth, in bits — −log2 of the share the true byte holds once the settled event space is read as the distribution it is. 8 is a position that knows nothing (uniform over 256), ~0 a clamped one. It is not a compression rate: what it is, and what it is not. Exact value on hover. |
| chg | shaded where this time step changed the position's argmax. A clear row means the window has stopped changing. |
The causal pass is omega’s, and “causal” here means one thing
only: left to right, left context only, no lookahead. It is the NLP sense of the
word — most literally true of a character-level RNN, one symbol at a time —
and it is not a claim about causation. Concretely
(the fixture, #omega-p8-frozen): one
left-to-right sweep that predicts each byte from its left context — the kept k=2
rule for (p−2, p−1) if there is one, the k=1 table from p−1
otherwise — and records the byte into the trace exactly when that prediction is
wrong. Everywhere below, read causal as left-context.
Do not carry the word forward onto f, because settling is deliberately not causal in that sense, and that is the whole point of it. A transformer, or that RNN, goes one token at a time and can only ever look left. Settling does the opposite: put a set of salient points into a memory trace, then work out the intermediate points through the window of indeterminacy from both sides. Every position on this page takes a forward application from its left neighbour and a backward application from its right one; the second is information the causal pass structurally could not use. Backward causality from a memory trace is a claim this work makes — in these models and, the argument goes, in the brain — and it is exactly what a borrowed word about one left-to-right pass would quietly deny.
Kept and glossed rather than renamed, per MJC 2026-08-17: short and clear
once you know what it means, but overloaded enough that it does not travel unannotated
(#viz_standard).
Softmax of the log support of each event in an event space is that event
space’s probability distribution — by definition, not by derivation.
A support is the log of a count, so 2w is the count and the shares of the
counts are the probabilities. The bpc row is
−log2 of the share the true byte holds in the settled event
space at that position: log2(∑ 2w) − wtrue,
computed live from the vector on screen.
IT IS NOT A COMPRESSION RATE AND MUST NOT BE READ AS ONE. MJC,
2026-08-17, in the goal this was built from
(#p8v2_ring_viz_goal_20260817):
“here bpc doesn’t relate to the compression because we are storing a memory
trace and not entropy coding. However, the bpc still measures how far away a position is
from truth, and when the argmax is wrong, that’s interesting. It also gives a sense
of what the model is doing ‘under’ the argmax, and everything that the argmax
throws away.” Nothing here is entropy coded, no k is measured, and this number is
not on any chart (#viz_standard,
#hutter_metrics).
Three readings that follow from it. A clamped position sits at 255
on its own event and 0 on the other 255, so its bpc is ~0 by construction and says
nothing about settling. A position whose vector is all zeros is uniform over 256 events,
so its bpc is exactly 8 — the floor a position starts from, and the number to read
every other one against. And where the argmax is wrong the bpc says by how much:
a near-miss and a position that has put its mass somewhere else entirely are the same
red cell in the argmax row and different numbers here.
Every weight here is a log support, which is why the arithmetic is not the arithmetic it looks like. Nothing on this page names an operation without a row here.
Three memory cell positions and the AND that joins the first two.
p−2 and p−1 are event spaces of 256 events each; the pair of
them is an event space of 65536, one event per two-byte context, and that is the
ring a grid cannot draw. The k=2 LPP is what connects that ring to p. MJC,
2026-08-17: “the point of a ring is that it shows the full picture of an LPP such
as the k=2 one which is captured as 65536 values”
(#p8v2_ring_viz_goal_20260817).
Ported from the UM viewer at umr.html, laid out left to
right because that is the memory chain. Drag to turn, wheel to zoom, hover any event
to hold it at 255 and see where it projects, click to freeze it — freeze one on
p−2 and one on p−1 and the AND ring is left holding a single event.
Nothing is drawn over the picture: what the cursor touches is written into the SN
pane on the right, as an SN state, with a held event at 255. — three
layouts of that pane ship side by side (the chain, one space, the
rules) so the reading can be chosen against real data rather than described.
Full screen gives it the screen — browser chrome and all, where the browser
allows it, and the whole viewport where it does not; the surface is wide and the page
column is not. Press f, or the button; Escape comes back. The fibre ink slider trades the two readings of a bundle
against each other — faint and thin, where a hundred fibres lying together read as
a density; or thick and cased, where one fibre can be followed by eye but paints out its
neighbours. Neither end is the honest one, so it is a slider, and no number on the page
moves with it.
Every pattern the model holds inside the window — 256 k=1 rules
and the k=2 tokens — each expanding to the input positions that formed it.
Selecting one writes its concordance and lights those positions in the grid above.
At this sample the model header says n = M = 64, so the training set
is the 64 bytes on screen and the expansion is exact, not sampled.
Every settled prediction, the patterns that produced it, and the input positions those patterns record. One row per position, over the full run of f under the current controls. Click a row to drive the instrument to it.
Two things in that table are not defects. A row often lists a pattern
out of 0x00: at the first time steps an unclamped neighbour is all
zeros, its argmax is byte 0, and the rule out of byte 0 is genuinely what fired. And
the backward direction is named as a reconstruction rather than by an atom, because
under B1 it is not a stored pattern — the query layer prints no atom for it and
this page will not mint one. It has a support set all the same.
Every decay rule at every rung of the prefix ladder, from the dumps. The instrument above is e64 only — one 64-byte window, one sample — and #viz_standard is explicit that a number measured on one prefix is a point on a curve and is read as one. This is the curve.
The chain the instrument puts on screen is: input positions → a pattern's log support for a joint event → f → the log support values of the settled event space. What licenses each link. Nothing here is this page's own derivation — everything asserted is quoted from a document published beside this page, and where no document says it, this section says that instead.
| the link | what licenses it |
|---|---|
| input positions → a pattern. A pattern is about the positions the concordance lists. | #f-p8: “the M-1 pattern with
one byte and the next byte being input and output spaces … is a sufficient
statistic on the frequency of the joint events, i.e. the byte pairs.” So the
antecedent–consequent pair names a joint event and the strength is a log count of
it. That count is what the concordance enumerates, which is why LATD is not a debugging
view but the pattern's own definition read back. |
| a count → a byte. Why a strength of 1 is not “seen twice”. | LSA.md: an LSA value “represents the log
value of a count”, the error is uniform in the log domain, two values are
required to have uncorrelated error distributions, and the increment gives
w+1 with probability 2−w. The stored weight is a
stochastic estimate of the count, so the two are not required to agree — and on
this sample they do not. |
| one pattern → a probability, from an absolute antecedent. | #f-p8: “In the case of
assignment, given the full joint pattern on the ESs in which t_i and t_j participate,
we see immediately that softmax on the ES of t_j gives the correct probability
distribution given the event e_i (corresponding to t_i = 255) and the information
about the frequency of the joint events, the sufficient statistic, captured by the
pattern.” With LSA.md: “LSA variables which form an
event space are interpretable as probabilities via softmax.” Read the
conditions: assignment, not accumulation; t_i = 255; before f has run. |
| two patterns → one distribution, and the condition under which that is correct. | #f-p8 states it with its condition
attached: “If another pattern that is derived from a disjoint set of
observations is brought in, these two distributions can be combined into the
correct (per probability theory) combined distribution, which is not true if this
additional parameter is not known (or if the observations are not disjoint, or more
generally, are correlated in a way that is unknown).” |
t_i = 255. In f a forward application delivers
min(wp, ws) where ws is the
source position's current activation — after one time step that is
neither 255 nor a count of anything observed, it is the output of the previous time
step. min of a log count of a joint event and an activation is not
derived anywhere we can find. Axis B is frozen at b1 normatively, but
a freeze is a decision, not a derivation.
log2(2a +
2b): addition in the count domain. Adding the counts of two
event sets that share observations counts the shared observations twice. Whether
that is the intended reading, and what the operation should be when the sets are known
to overlap, is not written down in any document published beside this page.
min(8, ws), where 8 is the
weight that makes the argmax carry half the mass of an event space whose other 255
events sit at 0, and the argmax’s measured share expresses as 9 / 8 / 7 at
e64 / e1k / e10k — so 8 is the measured value at e1k and within one unit of it
everywhere (#f-p8-forward). Under B2 the same
pattern is applied at its actual learned weight, which at this sample is 0, 1 or 2.
Whether a stated constant or the stored count is the right delivery is exactly what
v024 against v025 measures, and it cuts both ways: at e64 and e1k the stated 8
recovers more unrecorded positions than the stored truth does (14 against 1, and 220
against 151), and at e10k the truth wins (1369 against 1288). A 1-unit delivery drowns
in a window where the stochastic add is the same size; by e10k there is enough of it to
be worth reading. What the split changed is that this is now separable from the
fall-off: generation 4 could only move the pair, and the three runs H1, H3 and generation
4’s (255, 2) now show that the fall-off carries essentially the whole gain and
the delivery carries two positions at e1k
(the report).
#p8v2_gen3 removed
it: “There is no constant sum ever in an ES. The only thing constant is total
probability = 1 and that is after softmax.” That passage of
#f-p8 is marked WITHDRAWN and nothing has
replaced it. H4 is the one setting on this page that addresses the question rather
than inheriting it: it rescales the position to the support the arriving evidence
justifies, so its vectors mean the same thing at time step 5 and at time step 100 —
and because the subtraction is uniform it cannot reorder the event space, so it changes
what the position claims to rest on and never which byte it favours. That is not an
answer to whether the settled vector is a distribution; it is the only alternative here
for which the question is well posed.
ANSWERED, 2026-08-17, and the answer is that the question
was misput. MJC, in
#p8v2_ring_viz_goal_20260817:
“Softmax of the log support of each event in an ES is the probability distribution
by definition. I'm not sure what #f-p8 is referring to, but something has been misread
somewhere. It's worth including this if nothing else because it eliminates any
misunderstandings about what an ES is, which apparently is an ongoing source of
confusion.” So the distribution does not need licensing from the assignment
passage: it is what an event space of log supports is, before and after f alike,
and the bpc row renders it. What this does not settle is gaps 1
and 2, which are about the arithmetic that produced the vector — min against an
activation that is not 255, and LSA addition over observation sets that overlap — and
those are still open. A distribution can be read off any event space; whether this
event space is the one f should have produced is the other question.
One of the four is now answered — gap 4, above, and the answer
is that softmax of an event space's log supports is its distribution by definition, so
there was nothing to derive. The other three remain a request for a document, not a
finding: the
derivation is the programmer's, and inventing one here would be the same failure as
rendering a rule that was never run. Written up as
#p8v2_latd_probability_ask_20260815.
When the document exists, this section renders it instead of asking for it.
Generation 5. Generation 4's instrument is
/hutter/pprog/p8v2-gen4-e64/, frozen as
that generation's record; generation 3's is
/hutter/pprog/p8v2-gen3-e64/ and generation
2's is /hutter/pprog/p8v2-e64/. A page is not
rebuilt in place when its generation is superseded: the generation-1 page was, and no
longer exists to be compared with. The convention is in
#viz_standard, “Versioning a
viewer”.
Eight variants were run — v024 (the baseline, which is (G1, H1) and
is generation 4's run unchanged), v025 (B2 off it, the ground-truth column and the only
one here that stores the count matrix) and v026…v031, the six restated decay
rules — and are marked RUN. The two forward settings
other than G1 are not built in any variant, and every other combination is the
viewer's own; all of them are marked not a measurement.
There is no pick, no ranking and no compression number here; the picks are the
programmer's (#variant_protocol).
settled_ok is partly circular and the page reports around it. H2's readout is the argmax of the single strongest application, which is very nearly the predictor omega used to decide which bytes to record — so a rule whose readout coincides with the sparsifier's scores near-perfectly without settling doing any work. Every settled_ok in generations 1–5 is a measure of agreement with the causal pass — that is, the left-context pass, not of recovery (the report). The ladder below therefore reports the UNRECORDED positions separately, which is the number the recorded ones cannot flatter. And on that set the two readings are the same event: the unrecorded positions are, by construction, exactly the ones the left-context predictor already got right — — so “settled back to the true byte” and “agreed with the left-context prediction” cannot be told apart there. That is the circularity, and it is why a rule whose readout collapses back to the left context scores near-perfectly while contributing nothing that settling is for.
| 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 |
| gen5-pos/ | generation 5's recorded endpoints, which the conformance check compares against |
| gen5.tsv | generation 5's measured facts, including the e64 settling diagnostics. gen4.tsv is published beside it because the split’s central claim is that v024 and v025 reproduce their generation-4 rows byte for byte |
| axes.json | the axes, their alternatives and their definitions — the page reads it, it is not copied here |
| #f-p8 | f itself: the single normative statement. The application rule, the window and its tiling, the time steps, initialisation, clamping and the argmax tie-break are all in it |
| #f-p8-forward, #f-p8-decay | the two halves of f, each in its own words: what an application delivers, and what a position does with the applications that reach it. #f-p8-cap8 is the pair they were carved out of |
| #f-p8-decay-assign, #f-p8-decay-const2, #f-p8-decay-renorm, #f-p8-decay-deficit, #f-p8-decay-period, #f-p8-decay-indegree | H2…H7, each in its own words — the six retired axis-A ideas restated on the cap-8 delivery |
| LSA.md | what an LSA value is: the log of a count, uniform expected error in the log domain, uncorrelated between values by construction |
| #p8v2_latd_probability_ask_20260815 | the four questions above, written as a request for a derivation |
| p8v2-words.md | the fixture; the f blocks are the settling shell this page implements |
| the generation 5 report | what these runs say, including the finding that settled_ok is partly circular |
| #pprog_p8v2_gen5_goal_20260815 | the goal generation 5 was run against, with the programmer’s answers inline |
| #p8v2_gen3 | the push that opened the generation, with the programmer's answers inline |
| #p8v2_gen3_viz_goal_20260810 | the goal this page was built from |
| #viz_standard | what goes on anything we publish, including how a viewer is versioned |
| #hutter_publication_handoff | the division of labour between the two trees |
| build-p8v2-gen5-e64 | rebuilds this page and the notes. Runs no compression |
| check-p8v2-gen5-e64 | runs this page’s own script headlessly and drives it: all 168 combinations of the controls against every pane, every position at every step, the ring surface under both modes, and the two checks that carry the most — that H2 still conforms exactly, and that the bpc of a clamped position is 0 and of an untouched one is 8. What the page claims about itself, run rather than asserted |
| p8v2-gen1/ | the generation panels: every variant of a generation over the same input positions |
Published under #viz_standard. Self-contained: no external
stylesheet, no script, no font, no image, nothing fetched. Data symlinked from
../cmpr-src/; page regenerated by
docs/pprog/build-p8v2-gen5-e64, never hand-edited. The blocks are the
authority.