What is taught wrongly

A sampling that costs more than the array

On four-symbol text the transform has 0.75 runs a character, so a sampling of two suffix-array values per run is one and a half values per position — 271,565 bits against the 131,088 that keeping every value costs. The structure built to remove a term proportional to the text is twice the thing it replaced.

Two essays ago this strand replaced a suffix-array sampling proportional to the text with one proportional to the number of runs in the transform, and the collection it was measured on repeats itself thirty-two times.

Here is the same structure on eight thousand characters of four-symbol text, which repeats itself hardly at all. The sampling is 271,565 bits. Keeping every suffix-array value — the thing a sampling exists to avoid — costs 131,088.

A sampling in r against a sampling that makes a locate freeThe run-boundary sampling's bits divided by the bits of a sampling at one value in one — which is every suffix-array value kept, and the only regular rate that locates an occurrence in no steps at all. Both policies then answer a locate in constant work per occurrence, so the ratio is a like-for-like size comparison. On a collection of copies it is a twentieth; on ordinary English it is 0.80; on four symbols, uniform it is over one, because 0.75 runs a character means 2r is one and a half times n and the structure that removed the term in n has more values than there are positions.English-like, 32 copies0.05x0.017 runs/charEnglish-like, 8 copies0.12x0.045 runs/chara text that repeats itself0.08x0.029 runs/charEnglish-like0.80x0.292 runs/charfour symbols, uniform2.07x0.753 runs/charthe whole suffix arraysampling bits, run boundaries / every valuen = 8,192
Fig. 1 The run-boundary sampling against a sampling that makes a locate free, on five collections of about the same length. Under one it is the smaller policy; the bottom row is at 2.07.

The condition, which is arithmetic and not a caveat

A run-boundary sampling keeps 2r2r suffix-array values. A regular sampling at one value in ss keeps n/sn/s of them. So the first is smaller exactly when

2r<n/s,that isrn<12s.2r < n/s, \qquad \text{that is} \qquad \frac{r}{n} < \frac{1}{2s}.

At one value in thirty-two that threshold is 0.0156 runs per character. Measured: a collection of thirty-two copies is at 0.017, an eight-copy collection at 0.045, an internally repetitive text at 0.029, ordinary English at 0.292, and a four-symbol text at 0.753.

One of those five is near the threshold and four are above it, three of them by more than an order of magnitude. The structure is smaller on the collections it was designed for and larger on everything else, which is a sentence its own literature contains and which is easy to read as a hedge rather than as a factor of fifty.

Two measures of repetition, five texts, two orderingsEach bar is the number of runs in the transform of 2,048 characters; the number beside it is z, the phrases in the self-referential parse of the same text. Both fall when a text repeats and neither is a function of the other — ordered by r the texts run repetitive, english, dna, periodic, uniform, and ordered by z they run repetitive, english, dna, uniform, periodic. Ordered by H₃, which is what every earlier size on this site follows, they run repetitive, english, periodic, uniform, dna. Three measures of "how compressible", three orderings, and a claim that one text is more compressible than another is not a statement until one of them is named.a text that repeats itself129z = 104 · H₃ 0.28English-like677z = 385 · H₃ 0.85four symbols, uniform1,531z = 463 · H₃ 1.94periodic, period 171,781z = 721 · H₃ 1.72eight symbols, uniform1,788z = 718 · H₃ 1.74r, runs in the transform2,048 characters of eachone unit = one run
Fig. 2 The quantity the condition is about, across five texts. Everything in this essay is this plate divided by a length.

Two point zero seven

The last row of the plate at the top is the one worth dwelling on, because it is not a near miss.

On four-symbol text, r/nr/n is 0.753. Two values per run is therefore 1.5 values per character, and the whole suffix array is one value per character. The sampling is half as large again as the array it stands in for, before the predecessor structure that φ\varphi needs is added, and with it the ratio reaches 2.07.

A structure in that state is not a compressed index with a poor constant. It is a suffix array with extra machinery, answering the same questions more slowly, and its locate is one predecessor query per occurrence where an array’s is a read.

The reason is not subtle and it does not need a proof. The transform of a text with no long repeats does not cluster: neighbouring rows in the suffix array begin with the same character and their preceding characters are unrelated, so a run of length one is the normal case. The measure the structure is proportional to has degenerated to the length of the text, and a structure proportional to a degenerate measure is proportional to nn.

An r-index over 1 copies, in partsThe structure over 8,193 characters with 6,172 runs in its transform. Every part is a function of r: the two suffix-array values kept per run are 172,816 bits and the predecessor structure that makes phi computable is 98,749, so the whole sampling is 271,565 bits — 84% of the structure and containing no term in n but the width each value is written in. The parts are checked to sum to the reported total on the plate.sampled positions172,81653%phi predecessor98,74930%run starts18,5166%run lengths per symbol18,5156%run heads16,5225%C table1000%four symbols, uniform · n = 8,193 · r = 6,172the sampling is the two shaded rowsone unit = one bit325,218 bits · 39.69 bits/char
Fig. 3 The structure in that state, opened up. The two sampling rows are most of it, and the transform’s own parts are the minority.

The floor underneath, and what it does not say

There is a lower bound in this collection on structures sized by a run count, and it is worth putting beside the failure above because it settles what kind of failure this is.

A floor under a run count counts the texts with at most rr runs and takes the logarithm: a structure whose size is a function of rr has to give a different bit string to every one of them, so it needs log2N(n,σ,r)\log_2 N(n,\sigma,r) bits. That argument is about what any such structure must spend, and it says nothing about what this one does spend.

The two are different claims and it is easy to read the first as excusing the second. The floor says a run-based representation cannot be arbitrarily small; the measurement here says a particular run-based sampling is, on a particular text, larger than the array it replaces. Neither implies the other, and the gap between them on short texts is enormous — a floor of 7.27 bits against a measured 142 at twelve characters, as that essay reports.

What the floor does supply is the shape of the excuse that is not available. A structure sized by rr cannot be rescued on non-repetitive text by a better encoding of the same information, because the information itself is Θ(n)\Theta(n) when rr is Θ(n)\Theta(n). The failure is in choosing the measure, not in coding it.

The counting floor under a run count, and what the structure actually costsThere are exactly N(r) texts of 12 characters over 2 symbols whose transform has at most r runs, counted by exhaustion over all 4,096 of them. Any representation that can hand its text back and whose size is a function of r must give a different bit string to each of them, so it needs at least log₂ N(r) bits — the lower curve. The upper points are the smallest run-length index measured over texts with exactly that many runs, at a sampling rate of one in 4. The gap runs from 14.1x to 92.0x and it is entirely the constant: the floor says how much information there is and the structure says what it costs to store it in a form that can also be searched. Both axes are logarithmic.10110100runs in the transform, rbitsthe structurelog₂ N(r)12 characters · 2 symbols · all 4,096 texts walkedgap 14.1x–92.0x
Fig. 4 The floor that a run-based representation cannot get under, walked exhaustively at twelve characters. It bounds every structure in this strand and excuses none of them.

The same failure at one copy

The condition bites on collections as well as on texts, and the sweep this strand is built on contains its own counterexample at the left-hand end.

At one copy — a single 512-character English text — the r-index is 10,974 bits and the run-length index with a regular sampling at one value in thirty-two is 3,939. Nearly three times larger. The two structures hold the same transform, represented identically, and the entire difference is the sampling: 7,324 bits against 289.

That point is on every sweep plate in this strand and it is the first point of each of them. It is not hidden, and it is also not what a reader looking at a falling line takes away, which is why it gets an essay rather than a footnote. The index that stores the runs made the same shape of claim about the transform and drew the negative half on the same axes for the same reason.

Two compressed indexes over one growing collectionEnglish-like of 512 characters repeated up to 32 times, identically. The upper curve is the run-length index's regular sampling at one value in 32; the lower is the r-index's two values per run. Across the sweep the first grows 4.42x and the second 1.55x, and the second's growth is entirely the ⌈log₂ n⌉ each value is written in — r itself does not move once there is a second copy. Both axes are logarithmic.1,00010,00010⁴bits12481632characters in the collection · copies aboverun-length, sample 32r-indexEnglish-like · divergence 0r = 233 at n = 16,385
Fig. 5 Both structures across the collection, including the left-hand end where the new one is three times the old. The lines cross at four copies and the crossing is the essay.

What a rate can do that a measure cannot

There is a defence of the run-boundary sampling that has to be dealt with, because it is correct and it is not enough.

The comparison above is at a fixed rate of one in thirty-two, and a rate is a choice. Faced with four-symbol text an implementer would not use one in thirty-two; they would use one in 128, or one in 1,024, and the sampling would be 5,397 bits or 674, and the structure would be far smaller than the r-index still.

That is exactly right, and it is the point. A rate can be turned down and a measure cannot. The cost of turning it down is on the other axis — one value in 1,024 walks up to a thousand LF steps per occurrence — and the choice belongs to whoever knows how often locates happen.

So the correct statement of the trade is not that one policy is better. It is that a rate offers a curve and the run count offers a point, and on a repetitive collection the point is off the good end of the curve while on ordinary text it is off the bad end. Every occurrence at the same price draws the good case; this is the same picture with the axes’ meaning unchanged and the text changed.

The measure was not chosen to be small

It is tempting to treat this as a design flaw, and it is worth resisting because the same property is what makes the good case work.

rr is not an approximation to anything. It is a count of runs in a particular permutation of the text, and its value on a text with no repeats is a fact about that text rather than a failure of the structure. What the structure does is make its own size a function of that count — faithfully, in both directions.

That faithfulness is what repetition is not entropy has been arguing since the measure was introduced. An entropy cannot see a copy: two copies of a text have the symbol distribution of one, so nHknH_k doubles when nothing new arrives. rr can see a copy and does not move. The price of a measure that can see one thing is that it is blind to another, and here the blindness is that rr has no idea whether nn is large.

Where the crossing actually sits

The threshold r/n<1/2sr/n < 1/2s has a rate in it, so “where does the r-index win” is not a single number. It is a curve in two variables, and a reader deciding between structures wants it stated in the direction they will use.

Fix the locate cost instead. At one predecessor query per occurrence the r-index costs 2r2r values plus its predecessor structure; the only regular rate that matches is one value in one, which costs nn values. So at equal speed the r-index wins whenever 2r<n2r < n — that is, whenever the transform has fewer than half a run per character.

Measured against that threshold, the five texts read: 0.017, 0.045, 0.029, 0.292 and 0.753. Four of the five are under a half and the four-symbol text is over it. At equal locate cost the structure wins on ordinary English too, by 1.25 times, and loses on four-symbol text by 2.07.

That is a different and more useful statement than the one the fixed-rate plate makes, and it is the reason this essay carries both.

A sampling in r against a sampling that makes a locate freeThe run-boundary sampling's bits divided by the bits of a sampling at one value in one — which is every suffix-array value kept, and the only regular rate that locates an occurrence in no steps at all. Both policies then answer a locate in constant work per occurrence, so the ratio is a like-for-like size comparison. On a collection of copies it is a twentieth; on ordinary English it is 0.80; on four symbols, uniform it is over one, because 0.75 runs a character means 2r is one and a half times n and the structure that removed the term in n has more values than there are positions.English-like, 32 copies0.05x0.017 runs/charEnglish-like, 8 copies0.12x0.045 runs/chara text that repeats itself0.08x0.029 runs/charEnglish-like0.80x0.292 runs/charfour symbols, uniform2.07x0.753 runs/charthe whole suffix arraysampling bits, run boundaries / every valuen = 8,192
Fig. 6 The same five collections against a different rate. The ordering does not change and the position of the line does, which is the sense in which the crossing is a choice rather than a fact.

The term that grew, one strand later

This is the second time in this strand that a structure’s dominant part has turned out to be the one it is not named after, and the two are worth reading together because they point in opposite directions.

What is still proportional to n found a run-length index whose transform-sized parts grew 1.45 times across a collection while its sampling grew 18.3 times, until half the structure was the part that had nothing to do with runs. The repair was to make the sampling a function of rr as well.

This essay is the repair’s own failure case: once every part is a function of rr, a text where rr is Θ(n)\Theta(n) makes all of them proportional to the text, and there is no longer a small part to point at. The structure is uniformly bad rather than lopsided.

That is a better failure and worth saying so. A lopsided structure hides its cost in a term described as negligible; a uniform one is exactly as large as its measure says it is, and its measure is a number anybody can print in one pass. The earlier defect needed a plate with the parts separated to see; this one needs a division.

Three ways to be wrong about a structure sized by a measure

The general form is worth extracting, because this collection has now hit it three times in three fields and each time it looked like a different mistake.

Quoting the size on the collection the structure is for. Every published size for a run-length structure is on a repetitive corpus, correctly, and every one of them is an upper bound of the form O(rlog(n/r))O(r\log(n/r)) that is silent about what rr is on anything else. The bound is true; it becomes a claim about a structure only after rr is measured.

Assuming the measure is bounded. rr is at most nn and its worst case is reached, near enough, by a random text over a small alphabet. A structure whose size is Θ(r)\Theta(r) has a worst case of Θ(nlogn)\Theta(n\log n) bits, which is a suffix array.

Comparing at fixed size instead of at fixed speed. Two structures that answer a question at different prices per answer cannot be ranked by their sizes, and the fixed-rate comparison in this strand’s first essay reads as a near-tie exactly because it makes that mistake deliberately, so that the essay after it can correct it.

The check that must fail

The gate for this claim is written as a rejection rather than as a measurement, and the direction matters.

It requires that on English and on four-symbol text the run-boundary sampling is larger than a regular sampling at one value in thirty-two. If it ever stops being larger, something has changed that the rest of the strand’s plates would not notice — a sampling that quietly stopped storing run ends, say, which halves the size and breaks only the locate.

The companion check requires the opposite on a repetitive collection, and the pair is what makes either one worth running. A check that only demanded the win would pass on a structure that had stopped measuring the text at all; a check that only demanded the loss would pass on a structure with no sampling in it.

What share of each structure is its samplingThe regular sampling's share of the run-length index climbs from 7% to 65% across a collection that is the same text repeated, because the sampling is n/32 values while everything else follows r. The number beside each bar is the same share for the r-index, which does not move: its sampling is 2r values whatever n is. Both structures hold the same transform.1 copy7%r-index 67%2 copies12%r-index 66%4 copies21%r-index 66%8 copies33%r-index 65%16 copies49%r-index 65%32 copies65%r-index 64%English-like · base 512 · sample 32share of the structure's own bitsn = 16,385
Fig. 7 The quantity both checks watch, drawn as a share. The two policies swap places along this sweep, and a gate that did not know which side it was on could not tell a fix from a regression.

An index is allowed to be larger than its text

One more comparison belongs here, because a reader who has followed the field from its first essay will already be holding it.

An index larger than what it indexes opened this field with the observation that a suffix array plus its text is about five times the file on ordinary English, and that the phrase “smaller than the text” names four different numbers depending on which size of the text is meant. The r-index on four-symbol text is 325,218 bits over 8,193 characters — nearly forty bits a character, against a packed text’s two.

So the structure being larger than its input is not by itself a scandal; every index in this field except the compressed ones is. What makes this one a finding is that it is larger than the structure it was derived from, on a text where the derivation’s premise is false, while carrying the machinery that only pays off where the premise holds.

The text that does not have to be kept is the essay that makes the size comparison meaningful at all, by establishing what “self-indexing” has to mean before a size can be quoted. Every structure in this strand is measured under that seal, including this one in its failure.

What a practitioner should take from this

Three sentences, and none of them is “it depends”.

Measure r/nr/n on the actual corpus before choosing the structure — it costs one transform and one pass, and it decides the question. If it is under about 0.02, the run-boundary sampling is smaller than any rate that matches its speed and the decision is made. If it is over a half, the structure will be larger than the suffix array it replaces and the question is which regular rate to use.

The measurement is cheap because rr is not an asymptotic quantity, and it is the kind of number a limit is not a prediction says to take rather than to reason about. It is a number a program prints, on the corpus in hand, before any structure is built — which is the whole argument of fitting a class to measurements applied to a size rather than to a running time.

The equal-speed comparison holds at exactly one rate

At equal locate cost the structure wins on ordinary English too is the most favourable sentence on this page, and it is worth checking which rate makes it true, because the answer is one.

The condition is r/n<1/2sr/n < 1/2s. English is at 0.292, so it clears the threshold only when 1/2s>0.2921/2s > 0.292 — that is, when s<1.7s < 1.7, which for an integer rate means s=1s = 1. At s=2s = 2 the threshold is 0.25 and English is already over it; at the strand’s usual thirty-two it is over by nineteen times.

And s=1s = 1 is not a sampling. It is the whole suffix array, kept. So the equal-speed comparison is the r-index against an uncompressed array — the one case where the r-index is 1.25 times smaller and, per occurrence, one predecessor query slower than an array read.

Which puts the sentence’s own footing in question, in the way this page is otherwise careful about. Calling those two costs equal converts a predecessor query into an array read at par, and a predecessor query is a binary search over the samples or a rank on a sparse vector — several array reads, on the same accounting that prices a succinct range-minimum query at nine or ten. The comparison that flatters the structure most is the one that sums unlike units, which is the habit this collection refuses everywhere else.

Redo it at an honest rate. If a predecessor query is worth about ten array reads, the matching regular sampling is the one whose mean walk is ten LF steps — a rate of about twenty — and the threshold becomes r/n<0.025r/n < 0.025. Measured against that: the thirty-two-copy collection at 0.017 clears it, the internally repetitive text at 0.029 is just over, and English at 0.292 misses by a factor of twelve.

So the strand’s original fixed-rate statement was closer to right than the reframing that replaced it. The r-index is smaller at matched speed on repetitive collections and on nothing else, and the threshold is near 0.02 rather than near 0.5 — within a small factor of the 0.0156 the one-in-thirty-two plate uses, rather than an order of magnitude away from it.

That does not weaken every occurrence at the same price’s result, which is about the locate being flat per answer rather than about the size. It narrows this page’s own most generous claim back to the band the sampling that follows the runs measured in, and it removes the one line here that a reader could take as licence to build the structure over ordinary prose.

The honest limit

Four of the five texts here are generated rather than collected, and the generators are this collection’s own: an English-like source, a four-symbol source, a periodic one and a uniform one. Their run counts are plausible and they are not measurements of any real corpus, so the ordering is the claim and the exact ratios are properties of these sources.

The other limit is the length. At eight thousand characters, log2n\lceil\log_2 n\rceil is thirteen and the predecessor structure’s low parts are small; both grow slowly with the collection, and a sweep over four doublings cannot separate a term in logn\log n from one in log2n\log^2 n. The crossing condition itself has no such problem — it is a comparison of counts of values, and the widths cancel.

What is missing is a corpus where r/nr/n sits near the threshold rather than an order of magnitude either side of it. Everything measured here is decisively on one side or the other, and the behaviour of both structures in the middle is an interpolation nobody has run.

Named alongside this one

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

What links here

The 8 essays that link to this one and share the most of its objects, of 11 that link here.

The objects this essay names

Each one links to every other essay that touches it.

Burrows-wheeler transformCompressibilityFM-indexHonest limitIndex sizeMeasurementR-indexRepetitionRun boundary samplingRun-lengthSamplingSelf-indexSpace overheadTrade off