Counting

A register dropped by what it already knew

Two registers beside a two-ended selection sort's extremes cut the reading of its record of adjacent order to a forty-fifth on short runs, and made it worse than reading the record plainly on long ones: 53.5 words a question on a sorted array of 1,024 keys against 22.1. The swaps were blamed, and the proposed repair kept the part of a broken run beyond the break as a register of its own. It changes the reading by under 1% anywhere. On the sorted array the survivors are kept 523,775 times and asked 1,022 times, and the sort makes no swap at all: every one of the 263,167 relearning drops there is a pair the record already held, rewritten at the same value by a neighbour's question that the previous scan's chains answered. The swap never broke the register. Learning what it already knew did.

A run end kept in a register priced the last expensive part of a sorting record. The two-ended selection sort scans the keys it has not yet placed for both the smallest and the largest, swaps them to the two ends, and repeats. After a pass that compares every key with its neighbour, it keeps a record of adjacent order — two bits a pair saying whether the key at a position is smaller or larger than the one after it — and answers any question about two positions it can from the record, since a run of pairs that all point the same way is a stretch of the array in order. What it costs to consult two bits a pair found that reading the record on every question costs about a word a question on short runs, and a filter that reads the word it saves that on short runs the record is asked 184 questions for every comparison it saves.

Every question starts from one of the sort’s two current extremes, so the essay kept, beside each, the end of the run of known order starting there: a register, filled by one scan of the record to the run’s first break and dropped when any pair inside the run, or the break itself, changes. On 1,024 keys in runs of four it cut the reading to a forty-fifth, 0.024 words a question, and stopped the price of a saved comparison growing with the input. On long runs it failed. On a sorted array of 1,024 keys the registers read 53.5 words a question, two and a half times the plain record’s 22.1, because they were refilled at nearly every question and each refill scanned a run hundreds of pairs long.

Its closing section blamed the swaps. Each scan swaps its extremes to the ends of the unsorted part; the record forgets the pairs around both swapped positions; a register whose run passes through either is dropped and refilled by scanning the whole run again. But a swap does not destroy what the record knew beyond the swapped position. A run from ii to kk that loses its pair at pp becomes two runs, and the second, from p+1p + 1 to kk, is still known in full. The proposal kept that second part as a register in its own right, in the dropped one’s place, and predicted that on the sorted array the reading would fall from 53.5 words a question to under the plain record’s 22.1, with nothing changed on short runs. It named one way to fail: the new extreme after a swap is usually not inside a run the register kept, so the kept part might never be asked about before it was broken again.

Two repairs to one register

The sort, the inputs and the charges are the earlier essay’s: 256, 1,024 and 4,096 keys, cut into sorted runs of 4 keys up to the whole array, a pass between neighbours first, the previous scan’s chains of minima and maxima consulted before the record, and every question to the record charged at the 32-bit words it reads — sixteen pairs to a word. A register that holds the answer reads no word.

The survivor rule is the proposal’s. When a pair strictly inside a register’s run changes, the register’s start moves to the pair after the change and its end stays; when the break itself changes, the register is dropped, since the run may now be longer than it says. A second rule was added once the first had been measured, to test the failure the proposal named rather than to repair it: a register may answer a question from any position inside its run, not only from its start, since the run from there ends where the register’s does. Each register’s answer is checked against the record at every question, so neither rule can buy reading with a wrong answer.

Under one per cent

Keeping the part of a register's run beyond a break changes the reading by under 1% anywhere: on 1,024 sorted keys the registers read 53.54 words a question, with survivors 53.42, answering from anywhere inside a run 53.42, all far above the plain record's 22.13On 1,024 keys, a pass between neighbours first, the words read a question to the record of adjacent order: plain (every question reads its pairs), with two registers, with registers kept past a break, and with registers that answer from any position inside their run. runs of 4: plain 1.094, registers 0.024, survivors 0.024, inside 0.024; runs of 8: plain 1.119, registers 0.026, survivors 0.025, inside 0.025; runs of 16: plain 1.141, registers 0.028, survivors 0.028, inside 0.028; runs of 32: plain 1.425, registers 0.046, survivors 0.045, inside 0.046; runs of 64: plain 1.901, registers 0.097, survivors 0.096, inside 0.097; runs of 128: plain 2.769, registers 0.292, survivors 0.289, inside 0.290; runs of 256: plain 4.204, registers 1.137, survivors 1.129, inside 1.129; runs of 512: plain 5.852, registers 5.374, survivors 5.352, inside 5.352; runs of sorted: plain 22.132, registers 53.541, survivors 53.415, inside 53.415.keys in each sorted run of the inputwords read a question (log scale)0.111048163264128256512sortedregisterskept past a breakanswering from insidetwo bits a pair, plain1,024 keys, a pass firstlogarithmic scale
Fig. 1 Words read a question on 1,024 keys, a pass first, against run length, on a log scale: the plain record, the registers, the registers kept past a break, and registers that answer from anywhere inside their run. On the sorted array: 22.13 plain, 53.54 with registers, 53.42 with survivors, 53.42 answering from inside.

Keeping the part of a register’s run beyond a break changes the reading by under 1% at every run length: on 1,024 sorted keys the registers read 53.54 words a question, with survivors 53.42, and answering from anywhere inside a run 53.42 — all far above the plain record’s 22.13. On runs of four nothing moves at all, 0.024 words a question with or without survivors, as the proposal expected. On runs of 64 the registers read 0.097 and the survivors 0.096; on runs of 512, 5.37 and 5.35. The two repairs land on the same line, and the line is the registers’ own.

So the prediction failed by more than a factor of two on the input it was made for, and the failure mode the proposal named — the kept part never asked — was half of it. Answering from inside a run was the test of that half: if the problem were that questions start in the middle of kept runs rather than at their starts, letting a register answer from the middle would have caught them. It catches 1,022 more questions out of 264,190 and saves an eighth of a word.

Kept and never asked

Survivors are kept and almost never asked: on 1,024 sorted keys a register's far part is kept 523,775 times and a question is put to one 1,022 times, about 2.00 a scan; on runs of four, 675 kept and 78 askedOn 1,024 keys, the times a register was kept past a change to a pair inside its run, and the questions later answered from such a register: runs of 4: 675 kept, 78 asked; runs of 8: 1,323 kept, 140 asked; runs of 16: 2,718 kept, 186 asked; runs of 32: 5,706 kept, 229 asked; runs of 64: 11,817 kept, 256 asked; runs of 128: 26,191 kept, 308 asked; runs of 256: 59,509 kept, 386 asked; runs of 512: 183,325 kept, 563 asked; runs of sorted: 523,775 kept, 1,022 asked. Logarithmic scale.46757881,323140162,718186325,7062296411,81725612826,19130825659,509386512183,325563sorted523,7751,022upper bar: survivors kept · lower bar: questions they answeredrun1,024 keyslogarithmic scale
Fig. 2 On 1,024 keys, the times a register was kept past a change inside its run, and the questions later answered from such a register, at every run length, on a log scale. Runs of four: 675 kept, 78 asked. Runs of 64: 11,817 and 256. The sorted array: 523,775 and 1,022.

Survivors are kept and almost never asked: on 1,024 sorted keys a register’s far part is kept 523,775 times and a question is put to one 1,022 times, about two a scan; on runs of four, 675 kept and 78 asked. The number of survivors kept grows with run length as the proposal expected, since a long run has many pairs inside it to be changed. The questions put to them do not grow at all in proportion. On the sorted array the sort asks 264,190 questions of the record, and a survivor answers 1,022 of them, two in each of its 512 scans.

That is the number that gives the mechanism away. Half a million changes inside registers’ runs, on a sorted array, is two changes for every question the sort asks. A sorted array is the input on which the sort has least to change: the smallest key is already at the left end, the largest at the right, and the scan that finds them has no reason to move anything. Something on that input is changing pairs inside runs at twice the rate the sort asks questions, and it cannot be the swaps.

No swap on a sorted array

What drops a register is rarely a swap: on 1,024 sorted keys none of the 264,190 drops is at a swap, since a sorted array makes none, and 263,167 are a pair relearned at the value the record already held; from runs of 32 keys up, relearning is most of themOn 1,024 keys, register drops by why the pair under the register was touched — forgotten by a swap, learned or changed by a comparison, or relearned by a comparison at the value it held: runs of 4: 1,008 at a swap, 2,067 learned or changed, 1,063 relearned; runs of 8: 998 at a swap, 2,076 learned or changed, 1,393 relearned; runs of 16: 1,001 at a swap, 2,059 learned or changed, 2,086 relearned; runs of 32: 1,005 at a swap, 2,080 learned or changed, 3,673 relearned; runs of 64: 1,009 at a swap, 2,093 learned or changed, 6,850 relearned; runs of 128: 1,015 at a swap, 2,135 learned or changed, 14,142 relearned; runs of 256: 1,007 at a swap, 2,155 learned or changed, 30,932 relearned; runs of 512: 999 at a swap, 2,191 learned or changed, 93,105 relearned; runs of sorted: 0 at a swap, 1,023 learned or changed, 263,167 relearned.426% relearned831% relearned1641% relearned3254% relearned6469% relearned12882% relearned25691% relearned51297% relearnedsorted100% relearneddark: at a swap · middle: learned or changed · light: relearned as it wasrun1,024 keysshare of drops
Fig. 3 On 1,024 keys, register drops by why the pair under the register was touched: forgotten by a swap, learned or changed by a comparison, or relearned at the value the record already held, as shares of all drops at each run length. The sorted array: none at a swap, 1,023 learned or changed, 263,167 relearned.

What drops a register is rarely a swap: on 1,024 sorted keys none of the 264,190 drops is at a swap, because a sorted array makes none, and 263,167 are a pair relearned at the value the record already held; from runs of 32 keys up, relearning is most of the drops. The drops were counted by why the pair under the register was touched. A swap forgets the pairs on either side of both positions it moves. A comparison between neighbours writes its answer into their pair, which is how the record learns; if the pair was unknown or held the other direction, that is learning or a change. If it already held the same direction, nothing about the record is different afterwards — but the rule the registers were given, drop when a pair inside the run is written, does not ask what was written.

On runs of four the three causes are of one size: 1,008 drops at a swap, 2,067 learned or changed, 1,063 relearned. There the registers already held, 98% of questions answered from one. As runs lengthen, the swaps stay at about two a scan, which is all a scan has, and the relearning grows with the runs: 6,850 drops on runs of 64, 30,932 on runs of 256, 263,167 on the sorted array. The earlier essay’s account was wrong about the cause on exactly the inputs where the registers failed. The swaps break registers at the rate of two a scan everywhere; it is the relearning that grows with the run, and so it is the relearning that made a refill scan a long run at almost every question.

The previous scan, written back

The relearning is the previous scan's answers written back: on 1,024 sorted keys 99% of the drops by a pair relearned as it was come from a neighbour's question answered by the chains the scan before left, 1% from the record's own answers and 0% from comparisons madeOn 1,024 keys, register drops caused by a pair relearned at the value it held, by what answered the neighbouring question that relearned it: runs of 4: chains 155, record 908, comparisons made 0; runs of 8: chains 439, record 954, comparisons made 0; runs of 16: chains 1,114, record 972, comparisons made 0; runs of 32: chains 2,649, record 1,024, comparisons made 0; runs of 64: chains 5,774, record 1,076, comparisons made 0; runs of 128: chains 12,939, record 1,203, comparisons made 0; runs of 256: chains 29,502, record 1,430, comparisons made 0; runs of 512: chains 91,307, record 1,798, comparisons made 0; runs of sorted: chains 260,610, record 2,557, comparisons made 0.41,063 drops81,393 drops162,086 drops323,673 drops646,850 drops12814,142 drops25630,932 drops51293,105 dropssorted263,167 dropsdark: the chains' answers · middle: the record's · light: comparisons maderun1,024 keysshare of relearning drops
Fig. 4 On 1,024 keys, the drops caused by a pair relearned as it was, split by what answered the neighbouring question that rewrote it: the chains left by the previous scan, the record itself, or a comparison actually made. The sorted array: 260,610 by the chains, 2,557 by the record, none by a comparison.

The relearning is the previous scan’s answers written back: on 1,024 sorted keys 99% of the drops by a pair relearned as it was come from a neighbour’s question answered by the chains the previous scan left, 1% from the record’s own answers, and none from a comparison made. On a sorted array each scan’s largest-so-far moves one position at every step, since every key is larger than everything before it, and the question “is the key here larger than the largest so far?” is a question about two neighbours at every step. Two swaps a pass, and the stretches hold gave the sort chains of the previous scan’s minima and maxima, and they answer that question first, as a repeat. Their answer is about neighbours, so it is written into the record — at the value the record already held.

The writing is right. It is what keeps the record current when a pair has been forgotten and is learned again from a chain, and it costs nothing in comparisons. What was wrong was the register’s rule for when it is stale. The register watched for writes, and a write that changes nothing looks to it the same as one that breaks its run. On short runs the chains rarely answer neighbour questions — 155 of the relearning drops on runs of four come from them — and the rule cost little. On long runs nearly every step of every scan rewrites a pair inside the run a register holds, the register is dropped, and the next question from that extreme refills it by scanning the run to its end.

Linear in n

On sorted arrays the registers read 13.54, 53.54, 213.54 words a question at 256, 1,024, 4,096 keys — about n ÷ 19, between two and two and a half times the plain record — and refill at 100%, 100%, 100% of questions; survivors move none of those numbers by more than a quarter of a wordOn a sorted array of each size, a pass first: 256 keys: plain 6.122 words a question, registers 13.539, survivors 13.412; refills at 1.000 of 16,894 questions; pairs relearned as they were 16,639. 1,024 keys: plain 22.132 words a question, registers 53.541, survivors 53.415; refills at 1.000 of 264,190 questions; pairs relearned as they were 263,167. 4,096 keys: plain 86.135 words a question, registers 213.542, survivors 213.416; refills at 1.000 of 4,202,494 questions; pairs relearned as they were 4,198,399. Logarithmic scale from one word.256 keys6.12 plain13.54 registers13.41 survivors1,024 keys22.13 plain53.54 registers53.42 survivors4,096 keys86.13 plain213.54 registers213.42 survivorswords read a question, log scalesorted arrays, a pass firstlogarithmic scale
Fig. 5 On sorted arrays of 256, 1,024 and 4,096 keys, a pass first: words read a question by the plain record, the registers and the survivors, on a log scale. Registers 13.54, 53.54, 213.54; plain 6.12, 22.13, 86.14; survivors 13.41, 53.42, 213.42. Every question refills a register.

On sorted arrays the registers read 13.54, 53.54 and 213.54 words a question at 256, 1,024 and 4,096 keys — about n ÷ 19, between two and two and a half times the plain record — and refill a register at every question; survivors move none of those numbers by more than a quarter of a word. A refill scans the run from the extreme to its end. On a sorted array nothing is ever out of order, so that run is everything from the extreme to the last key, including the keys already placed at the right — about three quarters of the array on average over the scans, at sixteen pairs a word, which gives the n ÷ 19. The plain record reads only to the position the question asks about, well under half as far, and so on the same input reads less than the registers: it never scans past what it needs.

That is why a structure meant to save reading read more than the thing it replaced. A register is a promise to read a long stretch once and answer from it many times. If it is dropped after every answer, it reads the long stretch every time and answers once, and its scan is longer than the question’s. The register’s whole value depends on its lifetime, and its lifetime was being set by a rule that could not tell a change from a confirmation.

Why short runs never showed it

The same rule ran on runs of four, and there the registers were the success the earlier essay reported. Two things spared them. A short run holds few pairs, so a refill is one word: even dropped after every answer, a register on runs of four would read about as much as the plain record. And a short run is rarely rewritten by a chain, because on random runs the running maximum moves only when a new largest key appears, which in a run of four keys interleaved with others happens a few times a scan, not at every step. The runs too short to drop found that a record keeps even the runs of two keys, since they cost almost nothing; the same arithmetic makes a careless forgetting rule almost free on them.

So the defect was invisible on the inputs where the registers mattered most and enormous on the inputs where they were already losing, and those inputs failed for a reason that looked like the obvious one. The record that forgets on purpose and a record the size of a pass’s minima each found that what a record keeps is decided less by what it learns than by what makes it forget, and in both the forgetting was a rule someone chose. Here it was a rule nobody chose: a side effect of writing every answer about neighbours into the record, which is the right thing for the record and the wrong signal for anything that caches what the record says.

What the proposal’s account got wrong

The proposal’s account of the failure was plausible and was not checked: swaps break runs, long runs are broken, so long runs fail. Every step was true of some input. Swaps do break registers, about two a scan on every input that is not already sorted. Long runs were the inputs that failed. But the account did not hold on the input the prediction was made for, because a sorted array has no swaps at all, and a measurement that had counted drops by cause would have said so before the repair was designed. The price of remembering an answer made a related point about records in general: what a record remembers is cheap to state, and what it costs to keep is decided by when it forgets.

The rule that forgot was written as “drop when a pair in the run changes” and implemented as “drop when a pair in the run is written”. Those are the same rule wherever the record only learns new things, which is what it does in the pass between neighbours and in the scans of a random input. They diverge exactly where the chains of a record of stretches, not pairs answer neighbour questions the record already holds, which is on long runs. The registers’ own consistency check, run at every hit, could never catch it: it asks whether a register that answers holds the right run end, and a register dropped too early never answers.

What the counts assume

One sort. The drops are this sort’s: two extremes, chains consulted first, answers about neighbours written into the record. A sort that did not write chain answers back would not relearn, and would also not repair pairs a swap had forgotten.

Words as the cost. Reading is charged in 32-bit words of the record, as in the earlier essays; a refill and a question are charged the same way. A machine on which a long sequential scan is much cheaper per word than scattered reads would make the refills cheaper, and the conclusion about cause would not change.

Three sizes and one seed. The inputs are one shuffle per size, cut into sorted runs. The causes are measured, not modelled, and their proportions at each run length are close across the three sizes, but they are one sample of each.

Neither repair was the wrong idea in general. Survivors and answers from inside a run each answered something, a few hundred to a thousand questions. On a sort whose extremes do land inside kept runs — a sort that swaps more, on inputs that scatter its extremes — they might be worth their bookkeeping. On this sort and these inputs, a register’s far part is almost never where the next question starts.

Still open: a register that is not dropped by a confirmation

The repair the counts point at is smaller than either of the two measured. A comparison or a chain’s answer that writes a pair at the value the record already holds changes nothing a register depends on, and a register could be kept through it: drop a register only when a pair under it becomes unknown or changes direction, and treat a write of the same value as no write at all.

The measurement that follows gives the registers that rule, alone and with survivors, on the same inputs at all three sizes, and charges the same reads, and then asks what the cheapest record is at each run length. The prediction is that on the sorted array the reading falls from 53.5 words a question to well under a word, since its 263,167 relearning drops become none and its registers are then refilled only when a scan ends, and that the price of a saved comparison falls with run length instead of rising, which would leave the registers cheapest at every run length and the run list’s search with no input on which to win. It could fail on the swaps, which still drop about two registers a scan everywhere, and on the pairs learned for the first time, which on short runs are twice as common as the swaps. If those were what kept the registers expensive, the sorted array would improve and nothing else would. The question is whether a record’s cost on long runs was ever about what changed in it, or only about how it noticed.

What this makes readable

Essays that name this one as a prerequisite.

Named alongside this one

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

What links here

Every essay whose body links to this one.

The objects this essay names

Each one links to every other essay that touches it.

Bit vectorComparison countNatural runPredictionSelection sortSpace time trade