The index that replaces the text

The quarter was a lucky number

A growing directory's document array was refitted best by a clock read off its escape and held until the characters had grown by a quarter: 0.098 bits a symbol for 4.52 final arrays read. A price that weighed the refit against the loss alone did worse, because the array's size cancelled and the price left out the reading that waiting costs. Priced with that reading — refit when the escape rebuilds since the last refit, plus the waste a refit would remove at an exchange rate, pass the characters a refit reads — the rule beats the hold wherever both read more than about five arrays: 0.080 for 5.04 against the hold's best 0.088, 0.052 for 6.38 against 0.066. It loses only at the quarter's own point, and the quarter turns out to be a lucky setting: held to 1.2 or to 1.33 the clock is worse on both counts, because two bursts of growth arrive two versions at a time and only a quarter refits after both halves.

A growing collection’s document array — the array that names, for every character, the document it belongs to — is best coded by a Huffman code over the documents’ lengths, as the array is the length distribution found, and a collection that grows needs an escape in that code for documents added after the fit. Refitting when the escape is wrong refitted the Huffman code when the share of characters named through the escape passed twice the share its code word stands for, held back until the characters had grown by a quarter since the last refit. Replayed through a source directory’s history, from twenty files to 222 over 47 versions, that clock lost 0.098 bits a symbol against the Huffman code refitted at every version and read 4.52 final arrays’ worth of characters in refits and rebuilds of the escape. Every schedule that refitted when the files doubled did worse.

A price that cannot see the array tried to replace the hold, a fixed quarter, with a price, and failed for two reasons it could separate. Refitting when the bits wasted since the last refit reach a constant times the characters a refit reads puts the array’s size on both sides of the comparison, so the size cancels and what remains is a clock counted in versions; and the rule weighs the refit only against the loss, though waiting is also paid in characters read — at every version without a refit, the escape’s subtree is rebuilt over everything added since the last one. At the hold’s reading the price lost about 0.119 where the hold lost 0.098.

That essay’s closing section proposed charging the choice as it actually is. Refitting now reads the array. Waiting reads the escape’s subtree, at this version and every version until the next refit, and keeps whatever loss the Huffman code in force has that a refit would remove. A rule could add up the waiting’s reading since the last refit, add the removable waste at some exchange rate of characters per bit, and refit once the sum passes the array. The prediction was that the frontier would pass under the held clock, to about 0.09 bits a symbol for 4.3 arrays, and that an escape weighted as half the coding space would stop refitting at every version. It named the early history as the risk: the rebuilds are small while the escape is small, and in the first stretch, where the characters grow by a third in a version, a rule paced by them may wait too long.

Waiting, priced in characters

The history, the Huffman code and the charges are the earlier pages’. At every version after the first the rule computes two things. The rebuild reading is the characters in documents added since the last refit, which is what rebuilding the escape’s subtree reads. The removable waste is the Huffman code in force’s bits beyond those of the Huffman code a refit would install at that version — the same escape weight, escape included — times the version’s characters. Both are computed from the documents’ lengths alone. The rule keeps a running total of the rebuild reading plus the removable waste times a rate, and refits when the total, with this version’s share added, reaches the version’s characters; then the total starts again from nought.

The rate is in characters per bit. At a rate of nought the rule refits whenever the rebuilds since the last refit have read one whole array, and ignores the loss. At a rate of sixteen a bit of removable waste counts as much as sixteen characters of rebuild. Rates of 0, a quarter, a half, and 1 to 16 doubling were run. The removable waste replaces the earlier price’s loss because the earlier price counted the escape’s own coding space as waste, and a refit does not remove that.

The escape clock’s hold was run as a sweep this time, at holds from nothing to a doubling of the characters, because the earlier essay ran three — nothing, a quarter and a half — and reported the quarter as the clock’s good setting.

Better than the hold, except at the hold’s own point

Priced with the reading that waiting costs, the refit rule beats the escape clock's hold wherever the two read more than about five final arrays — 0.080 bits a symbol for 5.04 where the hold's best gives 0.088, 0.052 for 6.38 against 0.066 — and loses only at the quarter's own point, 0.098 for 4.52, where it gives about 0.147Mean loss against reading for three families of schedule, the escape weighted as one document. The escape clock at a factor of 2 with holds of 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 size-blind price at 0.05: 0.026 for 11.76, 0.1: 0.033 for 8.01, 0.2: 0.045 for 6.57, 0.4: 0.082 for 5.19, 0.8: 0.119 for 4.51, 1.6: 0.207 for 4.92, 3.2: 0.338 for 4.31. The price with the waiting at exchange rates of 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 characters a bit. Lines join each family's undominated points; points off the axes' range are left out of the drawing and kept here.00.1000.20046810bytes read by refits and rebuilds, in final arraysmean loss, bits a symbola quarterhold, sweptprice with the waitingprice, size-blindfaint dots: beaten on both countsescape as one document
Fig. 1 Mean loss against reading, three families, the escape weighted as one document. The hold swept from 1 to 2 (factor 2); the size-blind price from 0.05 to 3.2; the price with the waiting at rates from 0 to 16. Lines join each family’s undominated points. The waiting price: 0.117 for 4.63 at a rate of 1, 0.080 for 5.04 at 2, 0.052 for 6.38 at 4, 0.034 for 7.90 at 16. The hold at a quarter: 0.098 for 4.52.

Priced with the reading that waiting costs, the rule beats the hold wherever both read more than about five final arrays — 0.080 bits a symbol for 5.04 where the hold’s best gives 0.088, 0.052 for 6.38 against 0.066 — and loses only at the quarter’s own point, 0.098 for 4.52 arrays, where the waiting price gives about 0.147. At its cheap end it reaches 0.034 bits a symbol for 7.90 arrays at a rate of sixteen, where the swept hold gives about 0.052 at the same reading. Against the size-blind price it is better at five arrays and within a few thousandths of it, slightly behind, from six arrays to eight: the two rules agree once refits are frequent, since a rule that refits every two or three versions has little rebuild reading to count.

The prediction was right that the frontier would move under the hold and wrong about where. It expected 0.09 for 4.3 arrays. At 4.29 arrays the waiting price loses 0.213, at a rate of a quarter, and nothing the rule offers reaches the quarter’s corner of the plot. The interesting point on the plate is not the new line at all. It is that the hold’s line, swept, is not a line: its points jump back and forth in reading as the hold rises, and only a few of them survive as undominated. The quarter is one of the survivors, and it sits far below its neighbours.

A quarter among worse neighbours

The escape clock's quarter is a lucky setting: held to growth of 1.25 it loses 0.098 bits a symbol for 4.52 final arrays, but held to 1.2 it loses 0.112 for 5.35 and held to 1.33 0.149 for 4.65 — worse on both counts on both sidesThe escape clock at a factor of two, the escape weighted as one document, held until the characters have grown by each factor since the last refit: 1: 0.042 bits a symbol, 10.59 arrays, 25 refits; 1.05: 0.043 bits a symbol, 8.82 arrays, 23 refits; 1.1: 0.071 bits a symbol, 5.84 arrays, 17 refits; 1.15: 0.077 bits a symbol, 5.58 arrays, 14 refits; 1.2: 0.112 bits a symbol, 5.35 arrays, 12 refits; 1.25: 0.098 bits a symbol, 4.52 arrays, 11 refits; 1.33: 0.149 bits a symbol, 4.65 arrays, 10 refits; 1.5: 0.189 bits a symbol, 3.84 arrays, 7 refits; 1.75: 0.464 bits a symbol, 4.28 arrays, 5 refits; 2: 0.458 bits a symbol, 5.15 arrays, 5 refits.mean loss, bits a symbolreading, final arrayshold 1×0.04210.59 · 25hold 1.05×0.0438.82 · 23hold 1.1×0.0715.84 · 17hold 1.15×0.0775.58 · 14hold 1.2×0.1125.35 · 12hold 1.25×0.0984.52 · 11hold 1.33×0.1494.65 · 10hold 1.5×0.1893.84 · 7hold 1.75×0.4644.28 · 5hold 2×0.4585.15 · 5factor 2, escape as one documentright: arrays read · refits
Fig. 2 The escape clock at a factor of two, held to growth from 1 to 2. Loss and reading: 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 quarter is a lucky setting: held to growth of 1.25 the clock loses 0.098 bits a symbol for 4.52 final arrays, but held to 1.2 it loses 0.112 for 5.35 and held to 1.33 it loses 0.149 for 4.65 — worse on both counts on both sides. A schedule whose loss and reading move in opposite directions as a parameter turns is a trade; one whose neighbours are both worse on both counts is a coincidence of that parameter with something in the data. The sweep shows the second. From a hold of 1.5 upward the clock gets worse on both counts at once again: held to 1.75 it loses 0.464 for 4.28, held to a doubling 0.458 for 5.15, since the rebuilds of an escape left to cover most of the collection outweigh the refits saved.

The earlier essay quoted the quarter’s 0.098 as the clock’s result and drew the frontier between a quarter and a half from two points. Both statements were true of the settings run. What the sweep adds is that the clock’s frontier has no smooth shape for a rule of any kind to approach, so a rule judged against its best point is being judged against the best of ten draws.

Two arrivals that come in pairs

Either side of a quarter the hold refits at nearly the same versions and misses by one: versions 20–21 and 24–25 each grow the collection twice running, by 7% then 9% and 10% then 7%, and held to 1.2 the clock refits at 20 and 24, between the two arrivals, where a quarter refits at 21 and 25, after both; the waiting price at a rate of 2 refits 11 timesThe versions at which each schedule refits, of 47: hold 1.25×: 0, 2, 3, 6, 9, 11, 13, 21, 25, 37, 43; hold 1.2×: 0, 2, 3, 6, 9, 11, 13, 20, 24, 35, 41, 45; hold 1.33×: 0, 2, 3, 6, 10, 12, 20, 25, 38, 45; waiting, rate 1: 0, 3, 6, 10, 13, 18, 22, 27, 36, 44; waiting, rate 2: 0, 3, 6, 9, 12, 15, 21, 25, 35, 42, 45.hold 1.25×hold 1.2×hold 1.33×waiting, rate 1waiting, rate 2v0v10v20v30v40v46versiondots: refits47 versions
Fig. 3 The versions at which each schedule refits. Hold 1.25: 0, 2, 3, 6, 9, 11, 13, 21, 25, 37, 43. Hold 1.2: 0, 2, 3, 6, 9, 11, 13, 20, 24, 35, 41, 45. Hold 1.33: 0, 2, 3, 6, 10, 12, 20, 25, 38, 45. Waiting at a rate of 1: 10 refits; at 2: 11, the last at version 45.

Either side of a quarter the hold refits at nearly the same versions and misses by one: versions 20–21 and 24–25 each grow the collection twice running — by 7% then 9%, and by 10% then 7% — and held to 1.2 the clock refits at versions 20 and 24, between the two arrivals, where a quarter refits at 21 and 25, after both. The first seven refits are the same under both holds. Then 1.2’s lower threshold is met one version sooner, and its code is fitted to a collection that is about to grow by another 9% or 7%. That code is wrong as soon as it is fitted, the share behind its escape climbs at once, and the clock with 1.2’s hold refits again four versions later, still a version early. The quarter, waiting one version more, fits both halves of each pair.

That is what luck means here. The quarter is not a better rule than 1.2 in any sense a store could know; it is the threshold that, on this history, happens to fall after both halves of two paired arrivals. A history that brought its large changes in single versions, or in threes, would favour a different hold, and one where the pairs were spaced differently would favour another. One doubling late found that the growth already seen predicts the growth to come only one doubling late, because this directory’s growth slowed at every doubling; the same history’s arrivals are lumpy at a finer scale too, and a rule tuned to its lumps is tuned to this history.

The waiting price refits at versions 21 and 25 at a rate of two, after both halves of each pair, without being tuned to them. Its threshold is met by an accumulation rather than a jump, and a pair of arrivals adds to the rebuild reading for two versions before the total crosses.

The early stretch, still

The waiting price still loses the first stretch — 0.116 bits a symbol in versions 0 to 14 where the quarter's hold loses 0.073 — and wins the last, 0.074 against 0.098; the hold of 1.15, which reads about what the price does, loses 0.066 early and 0.079 lateMean loss, bits a symbol beyond a Huffman code refitted at each version, over three stretches of the 47 versions: hold 1.25× (4.52 arrays): versions 0–14 0.073, versions 15–29 0.124, versions 30–46 0.098; hold 1.15× (5.58 arrays): versions 0–14 0.066, versions 15–29 0.087, versions 30–46 0.079; waiting, rate 2 (5.04 arrays): versions 0–14 0.116, versions 15–29 0.051, versions 30–46 0.074.versions 0–140.073 hold 1.25×0.066 hold 1.15×0.116 waiting, rate 2versions 15–290.124 hold 1.25×0.087 hold 1.15×0.051 waiting, rate 2versions 30–460.098 hold 1.25×0.079 hold 1.15×0.074 waiting, rate 2mean loss in the stretch, bits a symbolescape as one documentthree stretches
Fig. 4 Mean loss over three stretches of the history. Versions 0–14: the hold at a quarter 0.073, the hold at 1.15 0.066, the waiting price at a rate of 2 0.116. Versions 15–29: 0.124, 0.087, 0.050. Versions 30–46: 0.098, 0.079, 0.074.

The waiting price still loses the first stretch — 0.116 bits a symbol in versions 0 to 14, where the hold at a quarter loses 0.073 — and wins the other two, 0.050 against 0.124 in the middle and 0.074 against 0.098 late. The hold of 1.15, which reads about what the waiting price reads, loses 0.066 early and 0.079 late, and is the fairer comparison: at matched reading the price wins the middle stretch by 0.037 and the late one by a few thousandths, and gives back half a tenth of a bit a symbol in the first fifteen versions.

So the risk the proposal named is the one that occurred. Early in the history the escape is small, because it has been only a version or two since the last refit, and the documents behind it are few; the rebuild reading accumulates slowly while the loss per version is large. At a rate of two characters a bit, the removable waste then dominates the total, and the rule behaves like the size-blind price it was meant to correct, counting versions. In the first stretch, where a version can add a third of the characters, that is the wrong unit, and the hold’s unit, growth, is right.

A price that cannot see the array blamed the early loss on the version as the unit of waste. The waiting price inherits that unit for its loss term, and the plate shows it inheriting the failure with it.

What the rule reads

With the waiting priced, rebuilding the escape never reads more than 2.16 final arrays; at an exchange rate of nought — refit when the rebuilds since the last refit have read one array — it refits 7 times and the two halves are nearly equal, 2.55 and 2.16, and from a rate of 1 the refits take over, 3.62 against 1.00The characters each exchange rate reads, in final arrays, split into whole-array refits and rebuilds of the escape's subtree at the versions between: rate 0: 2.55 in 7 refits, 2.16 in rebuilds; rate 0.25: 2.93 in 8 refits, 1.35 in rebuilds; rate 0.5: 3.49 in 9 refits, 1.25 in rebuilds; rate 1: 3.62 in 10 refits, 1.00 in rebuilds; rate 2: 4.36 in 11 refits, 0.69 in rebuilds; rate 4: 5.92 in 15 refits, 0.45 in rebuilds; rate 8: 7.07 in 18 refits, 0.33 in rebuilds; rate 16: 7.68 in 20 refits, 0.22 in rebuilds.rate 04.72 · 7 refitsrate 0.254.29 · 8 refitsrate 0.54.74 · 9 refitsrate 14.63 · 10 refitsrate 25.04 · 11 refitsrate 46.38 · 15 refitsrate 87.39 · 18 refitsrate 167.90 · 20 refitsdark: whole-array refits · light: escape rebuildsbytes read, in final arraysescape as one documentcharacters a bit of waste
Fig. 5 The characters each rate reads, in final arrays, split into refits and rebuilds of the escape. Rate 0: 2.55 in 7 refits and 2.16 in rebuilds. Rate 1: 3.62 in 10 refits and 1.00. Rate 4: 5.92 in 15 refits and 0.45. Rate 16: 7.68 in 20 refits and 0.22.

With the waiting priced, rebuilding the escape never reads more than 2.16 final arrays; at a rate of nought — refit when the rebuilds since the last refit have read one array — the rule refits seven times and its two halves are nearly equal, 2.55 and 2.16, and from a rate of one the refits take over, 3.62 against 1.00. The rate of nought is the rule choosing a growth factor would recognise: a structure that pays as much in upkeep as in rebuilding has balanced its two costs, and the total is within a constant of the cheaper one. The rule loses 0.292 bits a symbol there, because it ignores the loss entirely.

The same balance appears in the hold’s numbers. The hold at a quarter reads 3.52 arrays in refits and 1.00 in rebuilds, nearly the split of the waiting price at a rate of one, 3.62 and 1.00. Neither rule was tuned to that split, and both arrive at it because a refit roughly every quarter’s growth keeps the escape’s subtree small enough that rebuilding it costs about a quarter of what refitting does. The difference between them is entirely when the refits fall: the hold’s are placed by growth, the price’s by an accumulation of rebuilds and waste, and on this history the hold’s are placed better early and worse late.

The rebuild total also explains why the size-blind price could not read under 4.3 arrays however high its constant: it counted none of these characters, and they grew as its refits thinned. A rule that counts them cannot let them grow past the array between refits, by construction, and its reading is bounded by its refits plus at most one array’s worth of rebuilding per refit.

A code that should not be refitted

Under an escape weighted as half the coding space a refit never removes a bit — the Huffman code in force is as good as the one a refit would install at all 47 versions — so the waiting price refits only to stop rebuilding, 7 times for 4.72 arrays, and loses 0.599 bits a symbol where a Huffman code fitted once and never refitted loses 0.384 for 17.04At an exchange rate of 2 characters a bit, beside the Huffman code fitted at the first version and never refitted, under each escape weight: escape as one document: the waiting price 0.080 for 5.04 with 11 refits; never refitted 2.365 for 17.04. escape as half the coding space: the waiting price 0.599 for 4.72 with 7 refits; never refitted 0.384 for 17.04. escape growth seen, half at first: the waiting price 0.178 for 6.60 with 15 refits; never refitted 0.384 for 17.04.escape as one document0.080 · 5.04 arrays2.365 (bar cut) · 17.04escape as half the coding space0.599 · 4.72 arrays0.384 · 17.04escape growth seen, half at first0.178 · 6.60 arrays0.384 · 17.04upper bar: waiting, rate 2 · lower bar: never refittedmean loss, bits a symbolrate 2mean loss
Fig. 6 At a rate of 2, beside the Huffman code fitted at the first version and never refitted, under three escape weights. As one document: the waiting price 0.080 for 5.04, never refitted 2.365 for 17.04 (its bar cut). As half the coding space: the price 0.599 for 4.72 with 7 refits, never refitted 0.384 for 17.04. Growth seen, half at first: 0.178 for 6.60, never refitted 0.384.

Under an escape weighted as half the coding space a refit never removes a bit — the Huffman code in force is as good as the one a refit would install at all 47 versions — so the waiting price refits only to stop rebuilding, seven times for 4.72 arrays, and loses 0.599 bits a symbol where the Huffman code fitted once and never refitted loses 0.384, for 17.04 arrays of rebuilding. That half of the prediction holds: the half-space escape stops refitting at every version, as it did under the size-blind price. But what it shows is stranger than the prediction. A code whose escape takes half the coding space is a two-level code, documents known at the fit in one half and every later document in the other, and the later half is rebuilt at every version as a Huffman code of its own. Refitting moves documents from the later half to the earlier, which gives them nothing, and resets the later half to empty, which wastes its bit. The refits buy reading and cost loss.

So under that weight the trade runs backward. The fewer the refits, the lower the loss and the higher the reading, all the way to a code that is never refitted, and a rule that prices waiting can only choose a point on that trade by its exchange rate. A code word is at least one bit is the reason the half-space escape cannot be made cheaper in return: its own code word is already one bit, and an escape that hedges cannot be wrong in the direction a refit corrects.

What the history decides

Paired arrivals. The quarter’s advantage is two pairs of versions, and nothing here says how common such pairs are in directory histories. Another history would place the hold’s lucky points elsewhere. The sweep of holds is the measurement that matters, and it was run on one history.

One unit of waste. The loss term still counts each version once. The early stretch is lost because of it, and a rule whose loss term counted characters arriving rather than versions elapsing was not run here.

Rates on a doubling grid. Eight exchange rates. The waiting price’s frontier between rates of one and two is read through two points, and its loss at the quarter’s reading is read off the line between rates of a quarter and one.

Reading, not time. Every cost here is characters read. A store whose refits run in the background and whose rebuilds run on the query path would weigh the two differently, and the rate would then have a price outside the history.

The shape arrived early and the bytes late and the collections the saving was quoted for both found that a document array’s numbers are numbers about one collection. The schedules that keep it compressed turn out to be the same: a threshold that looks like a result can be a coincidence with the history’s lumps, and only a sweep says which.

Still open: waste counted by what arrived

The waiting price loses only the first stretch, and loses it for the reason the size-blind price lost it: its loss term adds the removable waste once a version, so a version that changed nothing counts as much as one that added a third of the collection. The hold is right early because it counts growth. A rule could count both of its costs by what arrived: the rebuild reading is already counted in characters added, and the removable waste could be charged per character that arrived since the last refit — the loss a symbol times the characters added at that version — rather than per character stored.

The measurement that follows charges the waste that way, keeps the rebuild reading and the exchange rate, and sweeps the rate as here, on the same history and the same three weights. The prediction is that the first stretch’s loss falls from 0.116 to under 0.08 at about the same reading, because a version that adds a third of the characters then counts for a third of an array of waste, and that the middle and late stretches change little, since growth there is slower and steadier. It could fail on the quiet versions: versions 18 and 19 add nothing, and a rule charged by arrivals will let a stale code serve them for free, which is right for the rule and wrong if those versions are stored as long as any other. The question is whether the loss a stale code causes belongs to the characters that made it stale or to the characters it is asked to code — and whether a schedule can be judged on one history when its best threshold is the one that happens to land after a pair.

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