The index that replaces the text

A waste charged to what arrived

A growing directory's document array is coded by a Huffman code over its files' lengths, and the best rule for when to refit that code priced the choice as it is: refit when the escape's rebuilds since the last refit, plus the waste a refit would remove at an exchange rate, pass the characters a refit reads. It beat the escape clock's quarter-growth hold everywhere but the first stretch of the history, where it lost 0.116 bits a symbol against the hold's 0.073, because it charged the waste on every character stored and so counted a version that added nothing as much as one that added a third. Charged instead on the characters each version adds, the first stretch was predicted to fall under 0.08 with the rest little changed. It falls to 0.073 — through version 18 the rule refits at exactly the hold's versions — and the middle stretch rises from 0.051 to 0.087, because a version that adds nothing now lets a stale code serve the whole collection for free.

A growing collection’s document array names, for every character, the document it belongs to, and the array is the length distribution found it best coded by a Huffman code over the documents’ lengths. A collection that grows needs an escape in that code for documents added after the fit, and a rule for when to refit. Three essays have now argued about the rule on one history: a source directory replayed from twenty files to 222 over 47 versions, its characters growing from 319 thousand to 6.9 million, with every rule charged two things — the loss its code in force has against a Huffman code refitted at every version, in bits a symbol averaged over the versions, and the characters it reads, in whole-array refits and in rebuilds of the escape’s subtree between them, counted in final arrays.

Refitting when the escape is wrong refitted when the escape’s share of characters passed twice its code word’s share, held back until the characters had grown by a quarter since the last refit: 0.098 bits a symbol for 4.52 arrays. A price that cannot see the array tried to replace the hold with a price and lost, because the array’s size cancelled from both sides. The quarter was a lucky number charged the choice as it is: waiting reads the escape’s subtree at every version, and keeps whatever loss a refit would remove; refit when the waiting’s reading since the last refit, plus that removable waste at an exchange rate of characters per bit, passes the array. That price beat the hold wherever both read more than about five arrays — 0.080 bits a symbol for 5.04 arrays at a rate of two — and showed that the hold’s quarter was one good setting between two worse ones.

It lost one stretch. Over versions 0 to 14, where the directory grows by a third in some versions and by nothing in others, the price lost 0.116 bits a symbol where the hold lost 0.073. Its closing section located the reason in a single multiplication. The removable waste was charged as the loss a symbol times every character stored, so a version that added nothing counted for as much waste as a version that added a third of the collection. The hold counts growth, and early in a history growth is what matters.

The proposal was to charge the waste on what arrived: the loss a symbol a refit would remove, times the characters added at that version, rather than the characters stored. The rebuild reading was already counted in characters added, since the escape’s subtree grows only with new documents, so both halves of the waiting cost would then be paced by arrivals. The prediction was that the first stretch’s loss would fall from 0.116 to under 0.08 at about the same reading, and that the middle and late stretches would change little, their growth being slower and steadier. The named risk was the quiet versions — eighteen and nineteen add nothing — which a rule charged by arrivals will let a stale code serve for free.

The same history, one multiplication changed

Everything is the earlier essay’s except the charge. The same 47 versions; the Huffman code fitted to the documents’ lengths with the escape weighted as one document; the same rebuild reading at every version without a refit; the same refit condition, waiting cost since the last refit passing the characters stored. The removable waste at a version is still the Huffman code in force’s bits beyond those of the Huffman code a refit would install there, escape included, computed from the lengths alone. It is now multiplied by the characters that version added. A version that adds nothing still rebuilds the escape’s subtree over everything added since the last refit, but it adds no waste at all.

That change alters what the exchange rate means. Charged on storage, a rate of two characters a bit put the price at about five arrays read. Charged on arrivals, the same rate charges a twentieth as much waste or less, since a typical version adds a few per cent of what is stored, and the rule waits far longer. So the rate is swept wider, from nought to 256, and the two rules are compared where their readings agree.

Nearly one frontier

Charged on the characters that arrived, the waste price draws nearly the frontier it drew charged on every character stored: at 5.50 arrays 0.081 against 0.070, 6.00 arrays 0.059 against 0.060, 6.80 arrays 0.045 against 0.048 bits a symbol — worse at the cheap end, within a hundredth from six arrays upMean loss against reading for three families, the escape weighted as one document. The escape clock's hold: 1: 0.042 for 10.59, 1.05: 0.043 for 8.82, 1.1: 0.071 for 5.84, 1.15: 0.077 for 5.58, 1.2: 0.112 for 5.35, 1.25: 0.098 for 4.52, 1.33: 0.149 for 4.65, 1.5: 0.189 for 3.84, 1.75: 0.464 for 4.28, 2: 0.458 for 5.15. The waiting price with waste charged on stored characters, rates 0: 0.292 for 4.72, 0.25: 0.213 for 4.29, 0.5: 0.130 for 4.74, 1: 0.117 for 4.63, 2: 0.080 for 5.04, 4: 0.052 for 6.38, 8: 0.043 for 7.39, 16: 0.034 for 7.90, 32: 0.027 for 10.72. Charged on arrived characters, rates 0: 0.292 for 4.72, 1: 0.261 for 4.48, 2: 0.219 for 3.97, 4: 0.173 for 4.39, 8: 0.150 for 4.25, 16: 0.124 for 4.40, 32: 0.082 for 5.49, 64: 0.059 for 5.99, 128: 0.045 for 6.80, 256: 0.032 for 7.85. Lines join each family's undominated points.00.1000.200468bytes read by refits and rebuilds, in final arraysmean loss, bits a symbolhold, sweptwaste on storedwaste on arrivedfaint dots: beaten on both countsescape as one document
Fig. 1 Mean loss against characters read, in final arrays, for the escape clock’s hold swept, the waiting price with waste charged on stored characters at rates 0 to 32, and charged on arrived characters at rates 0 to 256. At 5.5 arrays: 0.081 on arrivals against 0.070 on storage. At 6.0: 0.059 against 0.060. At 6.8: 0.045 against 0.048. Lines join each family’s undominated points.

Charged on the characters that arrived, the waste price draws nearly the frontier it drew charged on every character stored: at 5.5 arrays 0.081 against 0.070 bits a symbol, at 6.0 arrays 0.059 against 0.060, at 6.8 arrays 0.045 against 0.048 — worse at the cheap end, within a hundredth from six arrays up. Over the whole history the change in charge is close to a change in exchange rate. Both rules refit when a running sum passes the array; the arrivals rule’s sum grows more slowly and its rate has to be about twenty times higher to read the same, and having been scaled that way the two schedules fall on nearly one curve.

Nearly is the point. At the cheap end, around five arrays, the arrivals rule is a hundredth of a bit worse, and it is at the cheap end that the earlier essay’s price beat the hold by least. From six arrays up it is slightly better, by two or three thousandths, and at seven arrays it loses 0.042 where the stored rule loses 0.046 and the hold’s best setting near there loses 0.060. The frontier says the change is not a better rule. It says the change moves the loss around inside the history, and the next plate is where it moves.

The stretch it won and the stretch it gave away

Charged on arrivals, the price's first stretch falls to 0.073 bits a symbol, the hold's 0.073, where charged on storage it lost 0.116 — and its middle stretch rises from 0.051 to 0.087: the stretch the stored price won is the one the arrivals price gives awayMean loss, bits a symbol beyond a Huffman code refitted at each version, over three stretches of the 47 versions, for the quarter's hold and the waiting price charged on stored and on arrived characters (final arrays read in brackets): hold 1.25× (4.52): versions 0–14 0.073, versions 15–29 0.124, versions 30–46 0.098; stored, rate 2 (5.04): versions 0–14 0.116, versions 15–29 0.051, versions 30–46 0.074; arrived, rate 32 (5.49): versions 0–14 0.073, versions 15–29 0.087, versions 30–46 0.084.versions 0–140.073 hold 1.25×0.116 stored, rate 20.073 arrived, rate 32versions 15–290.124 hold 1.25×0.051 stored, rate 20.087 arrived, rate 32versions 30–460.098 hold 1.25×0.074 stored, rate 20.084 arrived, rate 32mean loss in the stretch, bits a symbolescape as one documentthree stretches
Fig. 2 Mean loss over three stretches of the history for the quarter’s hold (4.52 arrays), the stored price at rate 2 (5.04 arrays) and the arrivals price at rate 32 (5.49 arrays). Versions 0–14: 0.073, 0.116 and 0.073. Versions 15–29: 0.124, 0.051 and 0.087. Versions 30–46: 0.098, 0.074 and 0.084.

Charged on arrivals, the price’s first stretch falls to 0.073 bits a symbol, the hold’s 0.073, where charged on storage it lost 0.116 — and its middle stretch rises from 0.051 to 0.087: the stretch the stored price won is the one the arrivals price gives away. The first part of the prediction holds, at a reading half an array higher than the stored price’s: the early loss is now exactly the hold’s, to three places, and for a reason the next plate makes plain. The second part fails. The middle stretch was the stored price’s best, a third of the hold’s loss there, and charged on arrivals it gives up most of that advantage; the late stretch moves less, from 0.074 to 0.084.

Each of the three schedules is now best somewhere and worst somewhere. The hold is best early and worst in the middle. The stored price is worst early and best in the middle and late. The arrivals price is the hold early and between the two afterwards. No schedule measured on this history wins every stretch, and the earlier essay’s question — whether a schedule can be judged on one history when its best threshold is the one that happens to land after a pair — is sharper for it: the three rules differ less in their totals than in which part of the history they are good at.

Where each one refits

Through version 18 the arrivals price refits at exactly the hold's versions — 0, 2, 3, 6, 9, 11, 13 — where the stored price refits at 0, 3, 6, 9, 12, 15; after that the arrivals price refits 6 more times, the stored price 5Characters stored at each of the 47 versions (0.32, 0.32, 0.45, 0.64, 0.72, 0.72, 0.91, 1.05, 1.05, 1.21, 1.36, 1.59, 1.81, 2.07, 2.07, 2.24, 2.38, 2.38, 2.38, 2.38, 2.55, 2.79, 3.03, 3.03, 3.34, 3.58, 3.58, 3.58, 3.58, 3.60, 3.60, 3.61, 3.61, 3.96, 3.97, 4.21, 4.43, 4.75, 5.00, 5.12, 5.33, 5.52, 5.73, 6.02, 6.32, 6.68, 6.91 million), and the versions where each schedule refits: hold 1.25×: 0, 2, 3, 6, 9, 11, 13, 21, 25, 37, 43; stored, rate 2: 0, 3, 6, 9, 12, 15, 21, 25, 35, 42, 45; arrived, rate 32: 0, 2, 3, 6, 9, 11, 13, 19, 22, 25, 35, 43, 46. Versions adding under 0.2% of the characters: 1, 8, 14, 17, 18, 19, 23, 26, 27, 28, 31, 32.024601020304046versioncharacters stored (millions)hold 1.25×stored, rate 2arrived, rate 32charactersshaded: versions adding under 0.2%refits by version
Fig. 3 Characters stored at each of the 47 versions (line), with versions that add under 0.2% shaded, and the versions at which each schedule refits. Hold 1.25: 0, 2, 3, 6, 9, 11, 13, 21, 25, 37, 43. Stored price at rate 2: 0, 3, 6, 9, 12, 15, 21, 25, 35, 42, 45. Arrivals price at rate 32: 0, 2, 3, 6, 9, 11, 13, 19, 22, 25, 35, 43, 46.

Through version 18 the arrivals price refits at exactly the hold’s versions — 0, 2, 3, 6, 9, 11 and 13 — where the stored price refits at 0, 3, 6, 9, 12 and 15; after that the arrivals price refits six more times, the stored price five. Charging the waste on arrivals made the price into the hold for the first eighteen versions. That is the strongest form the first prediction could have taken: the rule did not merely approach the hold’s early loss, it chose the hold’s schedule, because in the early history the hold and the arrivals price are reading the same thing. A quarter’s growth since the last refit and a quarter’s growth’s worth of waste are, early on, the same signal.

They part where the history goes quiet. Between versions 14 and 32 the directory grows in bursts with long pauses: versions 17, 18 and 19 add nothing, 23 adds nothing, and 26 to 28 add a few dozen characters between them. The hold refits at 21 and 25, after bursts. The stored price refits at 15, 21 and 25. The arrivals price refits at 19 — on a version that added nothing, because the escape’s rebuilds still accrue — and then at 22 and 25. The plate shows the difference in where the refits fall; the next shows what that difference costs on the versions between.

What a quiet version costs

On the 10 versions between 13 and 34 that add under a fifth of a per cent, the arrivals price leaves a stale code losing 0.057 bits a symbol on average where the stored price's code loses 0.030: those versions charge it nothing, and they are stored as long as any otherVersions 13 to 34: the loss in force at each version for the waiting price at rate 2 charged on stored characters and at rate 32 charged on arrivals, and the characters each version adds. 13: added 266,727, stored 0.108, arrived 0.022; 14: added 601, stored 0.107, arrived 0.022; 15: added 169,402, stored 0.023, arrived 0.086; 16: added 139,222, stored 0.027, arrived 0.223; 17: added 0, stored 0.027, arrived 0.223; 18: added 0, stored 0.027, arrived 0.223; 19: added 0, stored 0.027, arrived 0.023; 20: added 172,652, stored 0.170, arrived 0.063; 21: added 236,203, stored 0.023, arrived 0.245; 22: added 239,718, stored 0.053, arrived 0.023; 23: added 0, stored 0.053, arrived 0.023; 24: added 312,883, stored 0.274, arrived 0.115; 25: added 234,968, stored 0.012, arrived 0.012; 26: added 0, stored 0.012, arrived 0.012; 27: added 36, stored 0.012, arrived 0.012; 28: added 6, stored 0.012, arrived 0.012; 29: added 20,952, stored 0.012, arrived 0.012; 30: added 7,307, stored 0.012, arrived 0.012; 31: added 2,850, stored 0.012, arrived 0.012; 32: added 3,748, stored 0.012, arrived 0.012; 33: added 347,876, stored 0.193, arrived 0.193; 34: added 16,214, stored 0.195, arrived 0.195.00.1000.2000.30015182124273033versionloss, bits a symboladdedwaste on storedwaste on arrivedbars: characters each version addsloss in force
Fig. 4 Versions 13 to 34: the loss in force at each version for the stored price at rate 2 and the arrivals price at rate 32, with the characters each version adds as bars. Arrivals: 0.022 at 13 and 14, 0.223 at 16 to 18, 0.245 at 21. Stored: 0.107 at 13 and 14, 0.027 at 16 to 19, 0.170 at 20 and 0.274 at 24.

On the ten versions between 13 and 34 that add under a fifth of a per cent, the arrivals price leaves a stale code losing 0.057 bits a symbol on average where the stored price’s code loses 0.030: those versions charge it nothing, and they are stored as long as any other. The risk the proposal named is the one that arrived. Versions 16, 17 and 18 show it most clearly. Version 16 adds 139 thousand characters, enough to make the Huffman code in force 0.223 bits a symbol worse than a refit, and the arrivals price charges that loss on the 139 thousand characters that arrived — not enough to fire. Versions 17 and 18 add nothing, so they add no waste, and the stale Huffman code goes on losing 0.223 bits a symbol on all 2.38 million characters stored, for two more versions, at no charge.

The stored price sees the same versions differently. It refitted at 15 and its code at 16 to 19 loses 0.027; it charges every version for the waste on everything stored, so a stale code standing over a large collection is expensive whether or not anything arrived. The plate also shows the opposite case, which is why the totals stay close: at versions 13 and 14 the arrivals price, having refitted at 13 like the hold, loses 0.022 where the stored price, which waited for 15, loses 0.107. And at 24, a large arrival of 313 thousand characters, the stored price’s code loses 0.274 where the arrivals price’s loses 0.115.

What the plate decides is the question the earlier essay ended on: whether the loss a stale code causes belongs to the characters that made it stale or to the characters it is asked to code. On this measurement it is the second. The mean loss is averaged over versions, each version’s loss is a loss on every character it stores, and a stored character is coded by whatever code is in force when it is read, whenever it arrived. A charge that follows the arrivals measures the cause of the staleness and misses most of its cost.

Twenty times the rate

To read the same, the arrivals price needs an exchange rate 12.14 to 24.24 times the stored price's — about the stored characters over the characters a typical version adds — and at each reading the two lose within 0.033 bits a symbol of each otherAt readings of 4.5, 5, 5.5, 6, 7 final arrays, the exchange rate each charge needs (interpolated between swept rates along its undominated points), the loss it then gives, and the hold's loss at that reading: 4.5: stored rate 0.72 loss 0.153, arrived rate 17.50 loss 0.120, hold 0.101; 5: stored rate 1.90 loss 0.084, arrived rate 24.82 loss 0.101, hold 0.089; 5.5: stored rate 2.69 loss 0.070, arrived rate 32.61 loss 0.081, hold 0.079; 6: stored rate 3.44 loss 0.060, arrived rate 64.70 loss 0.059, hold 0.069; 7: stored rate 6.45 loss 0.046, arrived rate 152.79 loss 0.042, hold 0.060.waste on storedwaste on arrivedholdexchange rate · mean loss, bits a symbol4.50 arrays0.72 · 0.15317.50 · 0.1200.1015.00 arrays1.90 · 0.08424.82 · 0.1010.0895.50 arrays2.69 · 0.07032.61 · 0.0810.0796.00 arrays3.44 · 0.06064.70 · 0.0590.0697.00 arrays6.45 · 0.046152.79 · 0.0420.060rates interpolated between swept pointssame reading, three rules
Fig. 5 At readings of 4.5, 5, 5.5, 6 and 7 final arrays: the exchange rate each charge needs and the loss it then gives, and the hold’s loss there. Stored: 0.72, 1.90, 2.69, 3.44 and 6.45 characters a bit. Arrivals: 17.5, 24.8, 32.6, 64.7 and 152.8. The losses at each reading are within 0.033 of each other, and the hold’s from 0.060 to 0.101.

To read the same, the arrivals price needs an exchange rate twelve to twenty-four times the stored price’s — about the ratio of the characters stored to those a version adds — and at each reading the two lose within 0.033 bits a symbol of each other. The plate makes the frontier’s resemblance arithmetic. Over this history the characters a version adds are, on a typical version, a few per cent of those stored, and a rule charged on arrivals reaches the same reading when its rate makes up that factor. The ratio is not constant — it grows from twelve at 4.5 arrays to twenty-four at seven — because the collection’s growth slows as it gets larger, so a later version’s arrivals are a smaller share.

That drift is also the shape of the trade. At the cheap end, where the rule refits rarely, a large rate on arrivals behaves like a small rate on storage except on the quiet versions, and the quiet versions are where the history’s long stale stretches are; the arrivals rule is worse there by up to 0.017. At the expensive end, where both refit often, the quiet stretches are short whoever refits, and the arrivals rule’s better timing early in the history shows through: 0.042 against 0.046 at seven arrays. At 4.5 arrays, the cheapest reading compared, the order turns over again: the arrivals rule loses 0.120 where the stored rule loses 0.153, and the hold, which is cheapest of the three there, 0.101.

What the two charges are measuring

The stored charge is a statement about the present. It says: this Huffman code is wrong by so much a symbol on everything the directory holds now, and every version this lasts costs that much. It is right about the cost and blind to the cause; it cannot tell a code made stale by a large arrival from a code that has been slightly wrong for a long time, and early in the history, when each arrival is a large share of what is stored, it is slow to respond to the first kind because a waste that grows with the whole collection is small while the collection is small.

The arrivals charge is a statement about change. It says: this much new material has come in under a code that does not fit it. It responds to the first kind of staleness immediately, which is why it chooses the hold’s schedule early, and it forgets a stale code as soon as nothing new arrives, which is why it loses in the quiet middle. Choosing a growth factor prices a dynamic array in the same two currencies: what a resize costs is set by what is stored, and when to resize by what arrives. The document array has met the distinction before, in the escape’s weight rather than the refit’s timing: one doubling late weighed the escape by the share of characters that arrived since the previous refit, against the share still to come.

The shape arrived early and the bytes late is the reminder of why this history makes the distinction visible: it found the spread of the files’ sizes set early, 0.88 at 56 files and 0.90 at 222, and a code fitted early still losing badly by the end. A Huffman code depends on more than the spread, and what arrives in bursts is the rest of it. A history that grew evenly would make both charges nearly proportional and both rules nearly the same. The collections the saving was quoted for found that the document array’s saving itself depends on which collection it is measured on, and so, it now appears, does the rule for keeping it.

What one history cannot settle

One collection. A source directory with bursts of growth and long pauses, refitted against a single code family. A collection that grew steadily would not separate the two charges, and one that shrank as well as grew would charge removals, which this replay never sees.

The escape’s weight. Under the escape weighted as half the coding space a refit removes nothing, as the earlier essay found, so both charges are nought and the rule refits only to stop rebuilding; the arrivals charge changes nothing there. Under an escape weighted by growth the arrivals rule refits less often and loses more — 0.251 bits a symbol for 4.59 arrays at a rate of two, against 0.178 for 6.60 on storage — which the plates above do not show.

Means over versions. Every loss is averaged over versions, so a quiet version counts as much as a busy one. A store that weighted versions by how often they are read would price the quiet middle differently, and if old versions are rarely read, the arrivals charge may be the right one after all.

Still open: a refit called by either charge

The plates say each charge is right about one kind of staleness. The arrivals charge fires on a burst, which is when the Huffman code becomes wrong; the stored charge fires on a wrong code that lasts, which is when the wrongness becomes expensive. A rule can listen to both. Keep both running sums since the last refit — the rebuilds plus the removable waste on arrivals at one rate, and the rebuilds plus the removable waste on storage at another — and refit when either passes the array.

The measurement that follows sweeps both rates over the same history and keeps the undominated pairs. The prediction is that the combined rule takes the hold’s schedule through version 18 and the stored price’s afterwards, so that its stretches come to about 0.073, 0.05 and 0.075, and its whole-history loss to about 0.065 at about 5.5 arrays — under both single charges by about a hundredth. It could fail on the reading: a rule that refits whenever either sum fires refits at the union of two schedules, and the union of the hold’s early refits and the stored price’s later ones may read six arrays or more. The question is whether a refit rule can know both why a code went stale and what its staleness costs, or whether every schedule on a bursty history must choose which of the two it is late for.

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.

AmortisationDocument arrayDocument collectionEntropyHuffman codingIndex sizePrediction