In an adaptive arithmetic coder, how does the decoder's probability model stay identical to the encoder's?
answer
- no table on the wire
- both sides learn from the same history
- code first, update after
- integer counts, never floating point
- one divergence and everything after is garbage
basics
~20 sBoth sides code a symbol with the model's current probabilities, then apply the same update, so the model depends only on already-coded history. The decoder rebuilds it step for step, so no table is transmitted, provided the arithmetic is deterministic.
solid answer
~40 sThe rule is **code first, update after**. The encoder narrows the interval using the probabilities the model holds right now, then feeds the symbol into the model; the decoder recovers the symbol using those same probabilities, then applies the identical update. Because every update depends only on symbols both sides have already seen, the two models track each other exactly, and no probability table is ever transmitted. Keeping that invariant demands strict determinism: integer counts rather than floating-point arithmetic, the same initial counts, the same count-rescaling trigger, the same tie-breaking. Every symbol also needs non-zero probability or it cannot be coded at all, which is why models start every symbol at count 1 or reserve an escape. A single divergence is unrecoverable — from that point on everything decodes to garbage.
go deeper
Recall that nothing about an adaptive model is sent: both sides learn from the symbols already coded, so the decoder rebuilds the same probabilities as it goes.
State the ordering invariant and why it holds — code with the current probabilities, update afterwards, because an update may only use history the decoder already has.
Name the determinism requirements and the failure mode: integer counts, matching rescale and initial state, and a divergence that compounds silently with no resync point.
Treat the update rule as part of the archival format, not an implementation detail, and decide how blocks, verification and checksums bound the damage when it is ever got wrong.
## The coder is not where the compression comes from An interval coder is a mechanical device: give it a probability, it spends `log2(1/p)` bits. All the compression comes from the **model** — the component that says how likely each symbol is next. An adaptive model is one that starts nearly ignorant and sharpens as it reads, so an archival text stream ends up coded under probabilities learned from that very document rather than from a generic table. That creates the obvious question: the decoder needs the same probabilities, and they change every symbol. Shipping them would cost more than they save. ## Code first, update after The invariant that makes it work is an ordering rule: 1. The encoder codes symbol `s` using the model's **current** probabilities. 2. The encoder then updates the model with `s`. 3. The decoder decodes `s` using its own model's current probabilities — which match, because it has applied the same updates from the same history. 4. The decoder then applies the identical update. The update at step 2 depends only on symbols that are already in the stream, so by the time the decoder needs it, it has them. Nothing about the model travels on the wire. Reverse the order on either side — update before coding — and the encoder is coding under probabilities the decoder cannot yet have, and the stream is unreadable from the first symbol. ## What determinism actually requires "Same update" is a stronger requirement than it reads: - **Integer arithmetic only.** Frequency counts and the slice computation are integers precisely so that both sides compute the identical boundaries. Floating-point probabilities can differ in the last place depending on how expressions are ordered or evaluated, and one differing boundary is enough. - **Same starting state.** Initial counts, the alphabet's order along the line, and the presence of an escape symbol are all part of the format. - **Same rescaling.** Models periodically halve all counts to bound the total and to weight recent history. The threshold and the rounding of that halving must match exactly on both sides. - **Same handling of the unseen.** A symbol with zero probability has a zero-width slice and cannot be coded at all. Either every symbol begins with count 1, or the model reserves an escape symbol that means "the next symbol comes from a fallback distribution". ## The failure mode Desynchronisation is total and silent. If the two models disagree by one count, the decoder picks a slice boundary the encoder did not use, decodes a different symbol, and then updates its model with that wrong symbol — so the divergence compounds. There is no self-synchronising structure in the stream, no codeword boundary to resume from, and the output after the divergence point is plausible-looking garbage rather than an error. Practical defences are external to the coder: decode-after-encode verification on write, a checksum over the decoded content, and framing the stream into independently coded blocks so a fault's blast radius ends at a block boundary. ## Where the stream ends The same lockstep argument applies to termination. The digit string carries no end marker of its own, and a decoder that keeps going will happily turn the flush bits into extra symbols. Two options, and a format must pick one: | approach | cost | notes | |---|---|---| | transmit the symbol count | a few bits or bytes of header | needs the length known before writing, awkward for streaming | | reserve an end-of-message symbol | a few bits, charged as its probability | self-terminating; the symbol needs a permanent non-zero slice | ## What adaptation buys, and what it costs - **Buys:** no table shipped, and probabilities that track local statistics — a document that changes character partway through is coded well in both halves. - **Costs:** the first few hundred symbols are coded under a poor model (the learning cost), the model update is on the hot path for every symbol on both sides, and the decoder now depends on the exact update rule forever, which makes that rule part of the archival format rather than an implementation detail. Ecosystems differ in how they express the shared model — some implementations share one routine compiled into both roles, others specify it in prose and implement it twice — but the requirement is the same either way: one definition of the update, exercised by round-trip tests rather than by review.
- What happens if a symbol has probability zero under the adaptive model?It cannot be coded: a zero probability means a zero-width slice, and there is no sub-interval to narrow into. Models therefore give every symbol a count of at least one, or reserve an escape symbol that switches to a fallback distribution for symbols not yet seen. Skipping this shows up as an encoder that works until the first unusual byte.
- Why do these models use integer counts rather than floating-point probabilities?Because encoder and decoder must compute byte-identical slice boundaries. Floating-point results can differ with expression order, precision and compilation, and a single boundary that differs by one unit decodes a different symbol and desynchronises the stream permanently. Integers make the update reproducible on any machine, including one built years later.
- How does a decoder know the stream has ended?Only because the format told it. Either the symbol count is transmitted, or the alphabet reserves an end-of-message symbol with a permanent non-zero slice that the encoder codes last. Without one, the decoder turns the encoder's flush bits into extra symbols that look like real content.
Two clerks keep identical ledgers from the same entries in the same order. Neither ever posts their ledger to the other, and a single skipped line makes every later entry disagree.
saying these in an interview costs you the question
- Thinks the probability table is transmitted with the stream
- Updates the model before coding the symbol on one side
- Uses floating-point probabilities and expects both sides to match
- Gives an unseen symbol probability zero and still tries to code it
- Assumes the decoder resynchronises after a mismatch
- Expects the digit string to announce its own end