The floors

The order inside a tie

Sort the rotations of a text by their first four characters rather than by everything that follows, and the output clusters slightly better than the full Burrows–Wheeler transform: 1.780 bits a symbol against 1.802, from 63% of the character reads. It also costs nothing to undo. The prediction that a shorter context leaves ties for the inverse to pay for was wrong. The cost to undo comes from how a tie is ordered, not from how long the context is, and at k = 0 the wrong tie rule is exactly the sort.

What a reordering costs to undo set two permutations side by side and priced them in full. Sorting a text’s characters clusters them perfectly and costs the text’s whole floor to undo. The Burrows–Wheeler transform clusters less and costs nothing. It ended with a prediction about the range between them. Sort the rotations by their first kk characters instead of by everything that follows, and a shorter context should leave ties. The ties should be exactly what the inverse is missing, so the cost to undo should grow as kk falls until at k=0k = 0 it is the whole multinomial. If so, the sort and the transform would be one family with one parameter, buying clustering with side information at a stated exchange rate.

The family exists and the parameter is real. The prediction about side information is wrong. It is wrong for a reason that argument could not see, because it treated one decision as if there were only one way to make it.

Two rules for a tie

Sort the rotations by their first kk characters and many of them compare equal. What happens to the equal ones has to be decided, and there are two natural rules.

Keep ties in text order. Rotations whose first kk characters agree stay in the order they have in the text. This is what any stable sort does without being asked. At kk larger than the longest repeated substring no two rotations tie, and the output is the Burrows–Wheeler transform exactly.

Order ties by the symbol they emit. Inside each tied group, arrange the rotations so the characters in the output column come out sorted. That is the rule that clusters hardest, because a tied group becomes a run of each symbol it holds. At k=0k = 0 every rotation ties, and the output is the sorted characters, the sort whose cost to undo was the text’s whole floor.

The rotations of "banana-bandana" sorted by their first character: 6 tied groups, and two ways to order inside themEvery rotation of "banana-bandana#", with # marking the end, sorted by its first character only, with the context shaded. Horizontal rules divide the 6 groups of rotations whose contexts agree. The middle column is the last character of each rotation with ties kept in text order: aabnnbdn#-naaaa. The right-hand column is the same groups with each one sorted by that character: aabbdnnn#-naaaa. The right-hand column has longer runs and has forgotten the order inside each group, which is exactly what an inverse needs.rotation, first 1 shadedtext orderby symbol#banana-bandanaaa-bandana#bananaaaanana-bandana#bbbana-bandana#bannba-bandana#bananndandana#banana-bbnana#banana-banddna#banana-bandannnbanana-bandana###bandana#banana---dana#banana-bannnnana-bandana#baaana-bandana#banaaandana#banana-baaana#banana-bandaaak = 1 · # marks the end of the text6 groups · 15 rotations
Fig. 1 The fifteen rotations of “banana-bandana” with an end marker, #, sorted by their first character only. Horizontal rules mark the six groups whose first characters agree. The middle column is the output with each group kept in text order, aabnnbdn#-naaaa. The right-hand column sorts each group by the symbol it emits, aabbdnnn#-naaaa. The right-hand column has longer runs and has lost the order inside each group.

So the sort and the transform are not the two ends of one parameter. They sit at different corners of a square with two sides. The transform is a long context with ties kept in text order. The sort is no context with ties ordered by symbol. The prediction ran along the diagonal between them and so changed both at once.

Every string, both rules, every context

Whether a permutation costs something to undo is a counting question: how many inputs share each output. At eight characters over three letters there are 6,561 strings, and each one can be put through both rules at every kk.

All 6,561 strings of 8 characters over 3 letters: ties in text order cost nothing to undo at any k; ties sorted by symbol cost 8.02, 2.44, 0.24, 0.01, 0.00, 0.00 bitsEvery string of length 8 over abc, sorted by its first k characters for k from 0 to 5, and the outputs tallied. With ties kept in text order every k gives 6,561 distinct outputs — each string its own, so nothing is needed to undo it. With ties sorted by the symbol emitted the outputs number 45, 1,578, 5,814, 6,543, 6,561, 6,561, at most 560, 20, 4, 2, 1, 1 strings sharing one, and a mean of 8.016, 2.438, 0.236, 0.005, 0.000, 0.000 bits needed to say which. The pale bars are how many arrangements the ties hide, 11.186, 5.151, 1.611, 0.406, 0.093, 0.019 bits: always at least the measured amount, and far above it. At k = 0 the symbol rule is the sorted string, and its 8.016 bits are the sort's.bits needed to undo, mean over every stringk = 08.016 of ≤ 11.19k = 12.438 of ≤ 5.15k = 20.236 of ≤ 1.61k = 30.005 of ≤ 0.41k = 40.000 of ≤ 0.09k = 50.000 of ≤ 0.02every string of 8 over abc · dark: measured · pale: arrangements inside tiestext order: 0 at every k
Fig. 2 All 6,561 strings of eight characters over a, b and c, sorted by their first k characters for k from 0 to 5. Kept in text order, every k gives 6,561 distinct outputs, one for each string, so nothing is needed to undo them. Ordered by symbol, the outputs number 45, 1,578, 5,814, 6,543, 6,561 and 6,561, and naming the input takes a mean of 8.016, 2.438, 0.236, 0.005, 0 and 0 bits. The pale bars count the arrangements the ties hide, which is always more than the amount measured.

Kept in text order, the limited sort gives every string its own output at every kk, including k=0k = 0. That holds whether the context is zero characters, one, or two. A shorter context leaves more ties, and the ties cost nothing, because their order is information the output still carries.

Why this should be so is less obvious than for the full transform. What a reordering costs to undo explained that transform’s inverse by a walk: each row’s predecessor is found because sorting by the whole following context is consistent from one row to the next. With a limited context that consistency fails, since a rotation one character earlier shares only part of the context. An inverse has to rebuild the contexts first and walk afterwards. The limited-context sort with stable ties is known as Schindler’s transform, and an inverse of that kind has been published since the late 1990s. The enumeration does not rely on that argument. It counts outputs, and every string has its own.

Ordered by symbol, the cost to undo is real, and at k=0k = 0 it is the sort’s cost exactly. At k=0k = 0 the mean is 8.016 bits, exactly the sort’s figure from the earlier enumeration, because it is the sort. At k=1k = 1 it falls to 2.438, at k=2k = 2 to 0.236, and by k=4k = 4 it is gone at this length, because four characters of context are enough to make almost every rotation of an eight-character string unique. The pale bars show a quantity that is easy to confuse with the measured one: the number of ways the characters inside each tied group could have been arranged. At k=0k = 0 that is 11.186 bits against 8.016 measured. The arrangements a tie hides overstate what an inverse lacks, because most arrangements are not the output of any text.

So the prediction was right about one corner of the square and wrong about the rest. A tie costs side information only when its order is thrown away, and a shorter context costs nothing unless its ties are ordered by the symbol they emit.

What the context buys

If every kk is free to undo under text-order ties, the question left is what each kk gives a coder. On 8,192 symbols of text built from a fixed vocabulary, the output at each kk goes through move-to-front and is charged at its zeroth-order entropy, the same pipeline the ledger used.

Sorting rotations by their first k characters: 4.16 bits a symbol at k = 0, 1.780 at k = 4, and the full transform's 1.802 from k = 248,192 symbols of words from a fixed vocabulary, zeroth-order entropy 3.898 bits. The rotations of the text are sorted by their first k characters and the last column is put through move-to-front and charged at its zeroth-order entropy. With ties kept in text order: k = 0: 4.155, k = 1: 2.935, k = 2: 2.100, k = 3: 1.886, k = 4: 1.780, k = 6: 1.782, k = 8: 1.793, k = 12: 1.797, k = 16: 1.802, k = 32: 1.802. At k = 24 and above the output is the Burrows–Wheeler transform exactly, at 1.802. With ties sorted by the symbol emitted the stream alone costs 0.037, 0.129, 0.306, 0.582, 0.780, 1.218, 1.566, 1.777, 1.795, 1.802 at the same k — cheaper, because a tied group comes out as runs, and not free to undo. The horizontal axis is spaced by log₂(k + 1).01234characters of context the sort reads, kbits a symbol after move-to-front012481632the full transform, 1.802ties kept in text orderties sorted by symbol: the stream alonethe text's own floormodel: order 0 after move-to-front · Words from a fixed vocabularyexactly the transform from k = 24
Fig. 3 8,192 symbols of words from a fixed vocabulary, zeroth-order entropy 3.898 bits. Rotations sorted by their first k characters, the output put through move-to-front and charged at order zero. With ties in text order: 4.155 bits a symbol at k = 0, 2.935 at 1, 2.100 at 2, 1.886 at 3, 1.780 at 4, 1.782 at 6, 1.793 at 8, 1.797 at 12 and 1.802 from 16 on. The output is the full transform exactly from k = 24. Ordered by symbol, the stream alone costs 0.037 to 1.802 over the same k, and none of that is free to undo.

Three things in that curve were not predicted.

At k=0k = 0 the limited sort is not the sort at all. With nothing to compare every rotation ties, text order keeps them where they are, and the output is the text shifted by one character. It costs 4.155 bits a symbol after move-to-front, essentially the untransformed text’s figure from the earlier ledger. The sorted characters only appear under the other tie rule. “Sorting with no context gives the sort” joined two separate choices into one.

The curve falls fast and then stops. Two characters of context take the cost from 4.155 to 2.100, and four take it to 1.780. Past four, nothing improves. The mean run length says the same thing: 1.01 at k=0k = 0, 3.43 at k=4k = 4, and 3.38 for the full transform.

The stopping point is partly a property of the source and partly a property of the coder, and the two can be separated. The character a row emits is predicted by the context after it. So the relevant floor is the conditional entropy of a character given the kk characters that follow it, which is the ordinary order-kk entropy of the text read backwards. On this source that is 2.246 bits a symbol for one character of context, 1.167 for two, 0.948 for three and 0.850 for four. The transform’s curve has the same shape, a steep fall that flattens by three or four characters. It sits between 0.69 and 0.93 bits above the floor at every one of those kk, and that gap is the price of move-to-front followed by a zeroth-order code. The model is the compressor describes that pipeline as a model in its own right, and a poor one for this purpose. Past four characters the conditional entropy keeps falling, to 0.470 at eight, but by then most eight-character contexts have occurred only once. An estimate built on contexts seen once has learned nothing, and the transform’s flat curve is the more honest reading of how much longer contexts help.

Four characters beat the full transform. At k=4k = 4 the output costs 1.780 bits a symbol against the full transform’s 1.802, and the gap closes steadily as kk grows: 1.782, 1.793, 1.797, 1.802. A longer context breaks each four-character tie by what comes later in the text. On this source, that later order evidently separates occurrences whose preceding characters had been lined up by text order. The difference is 1.2%, it is measured on one source, and the measurement says nothing about why. The last section takes that question up.

The symbol-ordered line is there as a warning. Its stream is always cheaper, from 0.037 bits a symbol at k=0k = 0 to 1.566 at k=8k = 8, and a table reporting streams alone would rank it first at every kk. What a reordering costs to undo was written to catch exactly that. At k=0k = 0 the side information brings the total back to 3.924 bits a symbol, near the text’s floor. At k=1k = 1 the arrangements hidden in the ties are enough to undo it, since a group’s size is the count of its first character and the decoder can read that from the output. The total there is 2.343 bits a symbol, worse than two characters of context kept in text order, which reach 2.100 with nothing to send.

Two sources, two different answers

The vocabulary source has structure at several lengths: letters within words, and words within a grammar. Two simpler sources show what the curve looks like when that structure is removed.

Sorting rotations by their first k characters: 2.13 bits a symbol at k = 0, 1.403 at k = 32, and the full transform's 1.402 from k = 558,192 symbols of order-1 Markov chain, zeroth-order entropy 3.000 bits. The rotations of the text are sorted by their first k characters and the last column is put through move-to-front and charged at its zeroth-order entropy. With ties kept in text order: k = 0: 2.134, k = 1: 1.407, k = 2: 1.405, k = 3: 1.408, k = 4: 1.408, k = 6: 1.410, k = 8: 1.409, k = 12: 1.406, k = 16: 1.404, k = 32: 1.403. At k = 55 and above the output is the Burrows–Wheeler transform exactly, at 1.402. With ties sorted by the symbol emitted the stream alone costs 0.014, 0.074, 0.282, 0.469, 0.618, 0.851, 1.001, 1.221, 1.332, 1.399 at the same k — cheaper, because a tied group comes out as runs, and not free to undo. The horizontal axis is spaced by log₂(k + 1).0123characters of context the sort reads, kbits a symbol after move-to-front012481632the full transform, 1.402ties kept in text orderties sorted by symbol: the stream alonethe text's own floormodel: order 0 after move-to-front · Order-1 Markov chainexactly the transform from k = 55
Fig. 4 8,192 symbols from an order-1 Markov chain over eight symbols, zeroth-order entropy 3.000 bits. With ties in text order: 2.134 bits a symbol at k = 0, then 1.407, 1.405, 1.408, 1.408, 1.410, 1.409, 1.406, 1.404 and 1.403 as k runs from 1 to 32. The full transform, reached exactly from k = 55, costs 1.402. One character of context gets within 0.4% of it.

The Markov chain makes each symbol depend on the one before it and on nothing earlier. The context that predicts a character is the character after it in rotation order, which is one character. So one character of context gets within 0.4% of the full transform, and the next 54 characters contribute nothing measurable. The context a transform needs is the order of the source, not the length of its longest repeat. On this chain the two differ by a factor of 55.

Sorting rotations by their first k characters: 3.00 bits a symbol at k = 0, 3.002 at k = 1, and the full transform's 3.006 from k = 98,192 symbols of uniform over 8 symbols, zeroth-order entropy 2.999 bits. The rotations of the text are sorted by their first k characters and the last column is put through move-to-front and charged at its zeroth-order entropy. With ties kept in text order: k = 0: 3.003, k = 1: 3.002, k = 2: 3.006, k = 3: 3.006, k = 4: 3.005, k = 6: 3.006, k = 8: 3.006, k = 12: 3.006, k = 16: 3.006, k = 32: 3.006. At k = 9 and above the output is the Burrows–Wheeler transform exactly, at 3.006. With ties sorted by the symbol emitted the stream alone costs 0.014, 0.075, 0.358, 1.747, 2.992, 3.006, 3.006, 3.006, 3.006, 3.006 at the same k — cheaper, because a tied group comes out as runs, and not free to undo. The horizontal axis is spaced by log₂(k + 1).0123characters of context the sort reads, kbits a symbol after move-to-front012481632the full transform, 3.006ties kept in text orderties sorted by symbol: the stream alonethe text's own floormodel: order 0 after move-to-front · Uniform over 8 symbolsexactly the transform from k = 9
Fig. 5 8,192 symbols uniform over eight, zeroth-order entropy 3.000 bits. With ties in text order every k costs between 3.002 and 3.006 bits a symbol, and the full transform, reached from k = 9, costs 3.006. There is no order to find at any context length. Ordered by symbol the stream alone falls to 0.014 at k = 0, all of it paid back to undo.

The uniform source is the control, and it behaves as it must. No context helps, the transform costs what the text costs, and the one line that appears to save something is the symbol-ordered stream, which is the sort again under another name. The model is the compressor makes the general point: a transform can only rearrange structure that a model could have used, and on a source with none there is nothing to rearrange.

What a shorter sort saves

The reason anyone wanted a shorter context is cost. The transform that emits nothing priced the block sort as the transform’s expensive step, and a sort that compares at most kk characters cannot read more than kk characters a comparison. The sort used here is a merge sort that counts every character it reads, so the saving can be set directly against the clustering lost.

What a shorter context saves: words from a fixed vocabulary at k = 4 reads 63% of the characters for 99% of the bits; order-1 Markov chain at k = 4 reads 43% of the characters for 100% of the bitsFor two sources of 8,192 symbols, the characters a merge sort of the rotations reads when it compares at most k characters, as a share of what the full sort reads (730,822 and 1,281,282), and the bits a symbol after move-to-front as a share of the full transform's. Words from a fixed vocabulary: reads 0.000, 0.263, 0.433, 0.542, 0.631, 0.779, 0.887, 0.979, 0.997; bits 2.307, 1.629, 1.166, 1.047, 0.988, 0.989, 0.995, 0.998, 1.000. Order-1 Markov chain: reads 0.000, 0.143, 0.247, 0.344, 0.432, 0.581, 0.694, 0.845, 0.923; bits 1.523, 1.004, 1.003, 1.005, 1.005, 1.006, 1.006, 1.003, 1.001. Ties are kept in text order throughout, so every point is free to undo. The horizontal axis is spaced by log₂(k + 1).00.50011.50characters of context the sort reads, kshare of the full transform0124816vocabulary: characters readMarkov chain: characters readMarkov chain: bits, at 1 from k = 1vocabulary: bits a symbolsolid: characters read · dashed: bits a symbol1 is the full transform
Fig. 6 Characters read by a merge sort of the rotations that compares at most k characters, as a share of the full sort’s reads, and bits a symbol after move-to-front as a share of the full transform’s, for two sources of 8,192 symbols. Vocabulary: 26% of the reads at k = 1, 43% at 2 and 63% at 4, where the bits are 98.8% of the full transform’s. Markov chain: 14% of the reads at k = 1 for 100.4% of the bits, and 43% at 4.

The saving is real and smaller than the phrase “a shorter context” suggests. On the vocabulary source the full sort reads 730,822 characters. Four characters of context read 461,156 of them, 63%, and give a slightly better result. Most comparisons between rotations were already settled within a few characters, so a limit rarely cuts one short. The expensive comparisons are the rare ones between rotations inside long repeats, and a limit removes only those.

On the Markov chain the saving is much larger, because the full sort pays for accidental repeats of up to 54 characters that carry no information about the source. One character of context reads 14% of the full sort’s characters and gives up 0.4% of the clustering. In this model that is where a limited context earns its place. A comparison count is not a running time, and one run, four counts, four answers is the page about how far apart those can be. A real block sort uses suffix-sorting algorithms whose cost is not a count of pairwise character reads. The measurement prices the comparison model, not a production compressor.

What the runs are worth elsewhere

Coding is one use of the transform, and not the one that kept it alive. The index that is the text and the essays after it use the transform’s output as a searchable index. That use asks for more than clustering, and the difference shows where a limited context stops being a substitute.

A search over the full transform works backwards through a pattern one character at a time. Each step narrows a range of rows, and it can do that because the rows are sorted by their entire following text: every row that begins with the pattern’s last jj characters sits in one contiguous block, for every jj. Under a limited context that holds only while jkj \le k. Past kk characters, rows that share a longer prefix are ordered by text position, not by what follows, so they no longer form a block, and the narrowing step has nothing to narrow. A four-character context supports searches for patterns of up to four characters and no further. That follows from the ordering and was not measured here.

The runs themselves transfer better. The index that stores the runs sized an index by the number of runs in the transform’s output rather than by its entropy. On the vocabulary source the full transform has 2,427 runs. A context of four characters has 2,387, and six and eight give 2,396 and 2,405. So the limited sort’s slightly better clustering is also slightly fewer runs. A run-length index built on it would be slightly smaller, and could not answer the one question an index is built for once a pattern runs past four characters. For a compressor that never searches, the limited context gives up nothing on this source. For an index, the long context is the point.

The comparison count has a similar limit. The suffix array in the index that is the text was built by a method that examines no characters pairwise at all, so the 730,822 reads above are what a comparison sort pays, not what the fastest construction pays. A limited context saves reads within that model. Whether it saves time against a suffix-sorting algorithm is a different measurement.

What is settled and what is not

Settled by enumeration: at eight characters over three letters, the limited sort with ties kept in text order gives every string its own output at every context length from zero to nine. Ordering ties by symbol collapses 6,561 strings to 45 outputs at k=0k = 0, which is the sort, and the side information falls to nothing by k=4k = 4. The arrangements hidden in ties are always at least the measured side information, and at k=0k = 0 they overstate it by more than three bits.

Settled by measurement on 8,192 symbols: four characters of context match the full transform on a vocabulary source, and beat it by 1.2%. One character matches it on an order-1 source. Nothing helps on a uniform source. The limited sort becomes the full transform exactly at 24, 55 and 9 characters on the three sources.

Not settled:

Injectivity at other lengths. Every string was checked at length eight, and a second enumeration at length seven agrees. The general inverse is a published result, not a measurement here.

The symbol rule’s side information at realistic sizes. At 8,192 symbols the only numbers available are the arrangements hidden in ties, which are sufficient at k1k \le 1 and an upper bound on what is lost. Enumeration shows they can overstate the true cost by a factor of two or more. Where exactly the symbol rule’s total lands at k=2k = 2 and above is not known here.

The coder. Every stream is charged at order zero after move-to-front, the same pipeline the earlier measurements of the transform used. A different second stage would rank the contexts differently, and the 1.2% advantage of four characters on the vocabulary source is well within the range such a change could move.

Still open: why four characters beat everything that follows

A limited context beating the full transform on the vocabulary source is the one result here that should not have happened, and its size, 1.2%, is small enough to be an accident of the source. What differs between the two outputs is only the order inside ties at k=4k = 4. Text order puts them by position. The full context puts them by the text that follows the four shared characters.

On a source made of whole words, the four characters after a position are often the rest of a word. The characters after that are the next word, chosen by a grammar that is independent of the character before the context. Sorting by the next word may therefore scatter occurrences whose preceding characters would have run together in text order. The prediction is that the effect depends on the word-length distribution, and that it disappears on a source whose long-range structure depends on the preceding character.

The measurement that follows builds two variants of the vocabulary source: one with words chosen independently of their neighbours, and one where the next word depends on the last letter of the previous one. It sweeps kk on both and measures, inside each four-character tied group, how many run breaks each tie rule creates. If the explanation holds, the full context wins on the second source and loses on the first, and the crossing point is the average word length. That would tie the context a transform needs to a measurable property of the source rather than to a constant.

Named alongside this one

Essays reaching for the same objects. Nobody chose these; they are what the concept index makes visible.

The objects this essay names

Each one links to every other essay that touches it.

Bits per symbolBurrows-wheeler transformContext modelCounting argumentEntropyHonest limitInvertibilityMeasurement designModel orderMove to frontPermutationSide information