The other axis

What a second pass buys

Exact selection of a median from thirty-two thousand values needs the whole stream in one pass — a million bits — and eleven thousand in two. By nine passes it is three hundred and twenty. The state falls as n to the power one over p, which is a law with an exponent worth fitting, and on skewed data the deterministic rule misses it by three orders of magnitude.

The question is the median, exactly, and the algorithm may read the data pp times.

At p=1p = 1 there is nothing to be done: an exact one-pass selector has to keep the stream, which for thirty-two thousand thirty-two-bit values is 1,048,576 bits, and the floor under that is the subject of the next essay.

At p=2p = 2 it is 11,712 bits. At p=9p = 9 it is 320.

Peak state against passes, for two splitting rules on two distributionsExact selection of the 0.5 quantile of 32,768 values, in p passes, with the state measured at its peak during the run. Every point is an exact answer — a run that returned anything else stops the build — so the vertical axis is the price of exactness rather than a price paid for being approximately right. The line at the top is what one pass costs: 1,048,576 bits, because an exact one-pass selector has to keep the stream, and the floor under that is a counting argument this collection performs rather than quotes. The equal-width rule needs no knowledge of the data and gets 37 times smaller as passes are added — on data spread evenly. On a heavy tail it collapses, because an equal-width cut of a range containing almost no data narrows the range and not the count; the sampled rule, which spends half its passes finding out where the data is, is barely affected. Both axes are logarithmic.10³10⁴10⁵10⁶passes over the datapeak bits of stateone pass, exact: 1,048,576 bitsradix, uniformsample, uniformradix, paretosample, paretoevery point exact · 32,768 values320 bits at best
Fig. 1 Peak state against passes, for two splitting rules on two distributions. Every point is an exact answer — a run returning anything else stops the build — so the vertical axis is the price of exactness rather than a price paid for being approximately right.

The method is an interval that narrows

The whole procedure fits in three sentences.

Keep an interval that must contain the answer, and a count of how many values are already known to be below it. Each pass cuts the interval into ss pieces, counts how many values fall in each, and narrows to the piece the target rank lands in. The last pass keeps whatever is still inside the interval and sorts it, which is what makes the answer exact rather than approximate.

The state during a narrowing pass is ss counters and the cut points. The state during the last pass is however many values survived. Balance those and the whole thing is decided:

snsp1sn1/ps \approx \frac{n}{s^{\,p-1}} \quad\Longrightarrow\quad s \approx n^{1/p}

so both the counters and the survivors are about n1/pn^{1/p}, and that is the peak.

Equal-width narrowing on uniform data: 5 passes to an exact answerThe interval that still might contain the 0.5 quantile of 32,768 values drawn from [0, 1,048,576), pass by pass. Each bar is the surviving range as a fraction of the universe and the number after it is how many of the 32,768 values are still inside it. The cuts are equal-width and need no knowledge of the data at all, so every pass narrows the RANGE by 9 — and on data spread evenly that narrows the COUNT by 9 too. The last pass keeps whatever is left and sorts it — 3 values, 640 bits — and that is the peak state of the whole run.pass 1 — count3,685 insidepass 2 — count457 insidepass 3 — count40 insidepass 4 — count3 insidepass 5 — keep3 insidethe whole universe32,768 values in [0, 1,048,576) · radix rule · answer 526,0565 passes · splits 9 · exact answer required640 bits at peak
Fig. 2 One run, pass by pass. The bar is the surviving interval as a fraction of the universe and the number beside it is how many of the thirty-two thousand values are still inside. Four narrowings take it from everything to three, and the last pass keeps those three.
pass interval values inside
1 466,034 – 582,542 3,685
2 517,815 – 530,761 457
3 525,007 – 526,446 40
4 525,966 – 526,126 3
5 keep and sort 3

Nine splits a pass, and the count falls by roughly nine each time: 32,768 to 3,685 to 457 to 40 to 3. That is the arithmetic working, and it is working on equal-width cuts of the value range — the rule that needs no knowledge of the data at all.

The exponent, fitted

A claim of n1/pn^{1/p} is a claim this collection has machinery for. Taking logarithms, log2(peak)\log_2(\text{peak}) should be linear in 1/p1/p with slope log2n\log_2 n.

passes 2 3 4 5 6 7 9
peak bits 11,712 2,112 960 640 448 384 320

Fitted: slope 13.54, against a predicted log232,768=15\log_2 32{,}768 = 15. Worst departure from the fitted line, 12%.

The departure is at the ends and both ends are explained. At p=9p = 9 the ideal split count is 32,7681/9=3.1732{,}768^{1/9} = 3.17, which rounds to four — a 26% overshoot that propagates through nine passes — and the peak flattens because the counters cannot go below a handful. At p=2p = 2 the survivors dominate rather than the counters, and the survivor count is a random quantity rather than exactly n/sn/s.

So the honest statement is: the peak follows n1/pn^{1/p} to within twelve per cent over the measured range, and the departures are integer rounding of the split count rather than a different law. The fit is not offered as a demonstration that the exponent is exactly 1/p1/p — seven points over a range of thirty-six times cannot establish that — it is offered as a test the claim could have failed, and did not.

Peak state against passes, for two splitting rules on two distributionsExact selection of the 0.5 quantile of 32,768 values, in p passes, with the state measured at its peak during the run. Every point is an exact answer — a run that returned anything else stops the build — so the vertical axis is the price of exactness rather than a price paid for being approximately right. The line at the top is what one pass costs: 1,048,576 bits, because an exact one-pass selector has to keep the stream, and the floor under that is a counting argument this collection performs rather than quotes. The equal-width rule needs no knowledge of the data and gets 37 times smaller as passes are added — on data spread evenly. On a heavy tail it collapses, because an equal-width cut of a range containing almost no data narrows the range and not the count; the sampled rule, which spends half its passes finding out where the data is, is barely affected. Both axes are logarithmic.10³10⁴10⁵10⁶passes over the datapeak bits of stateone pass, exact: 1,048,576 bitsradix, uniformevery point exact · 32,768 values320 bits at best
Fig. 3 The same series alone, on logarithmic axes, where a power law would be a straight line and this is not one — because the relationship is a power law in n with the exponent depending on p, so it is straight against 1/p rather than against p. The curvature here is the shape of one over p.

Equal width is a bet on the data

Everything above is on values spread evenly over the range. Change that and the deterministic rule does not degrade — it collapses.

passes uniform data heavy-tailed data
2 11,712 1,040,608
3 2,112 982,752
5 640 337,504
7 384 287,200
9 320 52,864

At two passes on a heavy tail the peak is 1,040,608 bits, which is 99.2% of what keeping the entire stream costs. Nine passes gets it to 52,864 — still a hundred and sixty times worse than the same rule on uniform data at two passes.

The reason is exactly one sentence: an equal-width cut narrows the range and not the count. A Pareto distribution puts almost all of its mass in a tiny fraction of its range, so cutting the range into nine pieces puts nearly everything into the first piece, and the pass has narrowed the interval ninefold while eliminating almost nothing.

Equal-width narrowing on pareto data: 5 passes to an exact answerThe interval that still might contain the 0.5 quantile of 32,768 values drawn from [0, 1,048,576), pass by pass. Each bar is the surviving range as a fraction of the universe and the number after it is how many of the 32,768 values are still inside it. The cuts are equal-width and need no knowledge of the data at all, so every pass narrows the RANGE by 9 — and on data spread evenly that narrows the COUNT by 9 too. The last pass keeps whatever is left and sorts it — 10,547 values, 337,504 bits — and that is the peak state of the whole run.pass 1 — count32,763 insidepass 2 — count32,675 insidepass 3 — count31,364 insidepass 4 — count10,547 insidepass 5 — keep10,547 insidethe whole universe32,768 values in [0, 1,048,576) · radix rule · answer 1785 passes · splits 9 · exact answer required337,504 bits at peak
Fig. 4 The same rule on a heavy tail. The interval shrinks by nine every pass, exactly as before, and the count does not: 32,763, then 32,675, then 31,364. Three passes have removed 1,404 values out of thirty-two thousand.

Two things in that trace are worth noticing. The interval genuinely does shrink — the rule is not broken — and after four passes the count finally drops, from 31,364 to 10,547, because by then the interval has narrowed enough to be inside the bulk of the distribution. The whole cost is paid in the early passes, on a range that is mostly empty.

A rule that needs no data is a rule that has assumed something about it, and the assumption here is that the values are spread evenly enough for range and count to be proportional. That is stated nowhere in the method and it is the difference between three hundred bits and a million.

Adaptive splits, and what they cost

The repair is to cut at order statistics of the data rather than at equal widths — take a sample, sort it, use it to split. Then each piece holds about the same count by construction, and the distribution stops mattering.

It costs a pass. Nobody knows where the order statistics are until a pass has gone by, so the passes alternate: sample, count, sample, count. Nine passes give four narrowings rather than eight.

passes radix, heavy-tailed sampled, heavy-tailed
3 982,752 28,928
5 337,504 4,032
7 287,200 4,032
9 52,864 4,032

The sampled rule is between thirteen and eighty-three times better on this data, at every pass count, while doing half as many narrowings.

And on uniform data it is worse, at every pass count, for the same reason: half its passes buy nothing that equal-width cuts do not already give.

passes radix, uniform sampled, uniform
3 2,112 12,352
5 640 2,272
7 384 1,024
9 320 704

That reversal is asserted on every build, in both directions, because a comparison run only on skewed data would be measuring a rule’s advantage in the one place it has one and calling it a property of the rule.

Sampled narrowing on pareto data: 7 passes to an exact answerThe interval that still might contain the 0.5 quantile of 32,768 values drawn from [0, 1,048,576), pass by pass. Each bar is the surviving range as a fraction of the universe and the number after it is how many of the 32,768 values are still inside it. The cuts are order statistics of a sample, so a pass has to be spent finding them before a pass can be spent counting against them: 7 passes give 3 narrowings rather than 6. What that buys is a narrowing that follows the data. The last pass keeps whatever is left and sorts it — 126 values, 4,032 bits — and that is the peak state of the whole run.pass 1 — sample32,768 insidepass 2 — count4,539 insidepass 3 — sample4,539 insidepass 4 — count242 insidepass 5 — sample242 insidepass 6 — count126 insidepass 7 — keep126 insidethe whole universe32,768 values in [0, 1,048,576) · sample rule · answer 1787 passes · splits 14 · exact answer required4,032 bits at peak
Fig. 5 The sampled rule at work on the heavy tail. The odd passes take a reservoir from inside the current interval and produce nothing else; the even ones count against those cut points. Each narrowing removes most of what is left, and there are three of them in seven passes.

The floor when the values repeat

One row above is flat and it is not noise: the sampled rule reports 4,032 bits at five, seven and nine passes, and 126 survivors each time.

The values here are a heavy-tailed distribution rounded to integers, and 126 of them are equal to the answer. An interval cannot be narrowed below a single value, so once the interval has collapsed onto the answer’s value, the survivor count is its multiplicity and no further pass changes anything.

That is a real floor and it is worth stating in general: exact selection by interval narrowing cannot get below the multiplicity of the answer, whatever the pass count. On continuous data the multiplicity is one and it never binds. On integer or bucketed data — which is most real data — it binds at whatever the mode’s local density is, and it is the reason the sampled curves flatten while the deterministic ones are still falling.

The repair is to stop narrowing and start counting: once the interval holds one distinct value, the answer is that value and the survivors need not be kept. That is an implementation choice rather than a property of the method, it is not taken here, and the flat rows above are what it costs.

Peak state against passes, for two splitting rules on two distributionsExact selection of the 0.5 quantile of 32,768 values, in p passes, with the state measured at its peak during the run. Every point is an exact answer — a run that returned anything else stops the build — so the vertical axis is the price of exactness rather than a price paid for being approximately right. The line at the top is what one pass costs: 1,048,576 bits, because an exact one-pass selector has to keep the stream, and the floor under that is a counting argument this collection performs rather than quotes. The equal-width rule needs no knowledge of the data and gets 37 times smaller as passes are added — on data spread evenly. On a heavy tail it collapses, because an equal-width cut of a range containing almost no data narrows the range and not the count; the sampled rule, which spends half its passes finding out where the data is, is barely affected. Both axes are logarithmic.10³10⁴10⁵10⁶passes over the datapeak bits of stateone pass, exact: 1,048,576 bitsradix, uniformsample, uniformradix, lognormalsample, lognormalevery point exact · 32,768 values320 bits at best
Fig. 6 A third distribution — log-normal, which is skewed but far less extreme than a Pareto — where the deterministic rule is bad and not hopeless: a million bits at two passes falling to 28,480 at nine, against 320 for the same rule on uniform data. The degradation is continuous in how skewed the data is, rather than a property that switches on.

What crosses the boundary, and it is nearly nothing

The working state is what the plates above draw. The carry — what survives a pass boundary — is a different quantity and it is the one a bound in pp and ss is stated in.

What crosses a boundary, against what is held during a pass — radix selection on uniform dataExact selection of the 0.5 quantile of 32,768 values. The outer bar is the peak state during a pass and the inner one is what the algorithm declared and carried across the boundary after it. The carry is small and nearly flat — an interval, a running count, and for the sampled rule a set of split points — while the working state falls by a factor of 37 across the sweep. A bound stated in passes and space is a statement about the carry; a memory budget is a statement about the working peak; and the two are different by up to 122 times here. The carry is enforced rather than believed: between passes the algorithm's state is wiped and rebuilt from the carry alone, so a procedure keeping something it did not declare returns a wrong answer rather than a flattering number. The horizontal scale is logarithmic.2 passes11,712 held96 carried3 passes2,112 held96 carried4 passes960 held96 carried5 passes640 held96 carried6 passes448 held96 carried7 passes384 held96 carried9 passes320 held96 carriedheld during a passcarried across the boundaryevery run exact · the carry is enforced96 bits at least
Fig. 7 The two, side by side. The carry is an interval and a count: ninety-six bits, at every pass count and every problem size on the plate. The working state falls by a factor of thirty-six across the same sweep and is up to a hundred and twenty times larger.

Ninety-six bits. Two values and a running count, and nothing else survives a pass. The counters are recomputed from scratch every time, the survivors are recomputed from scratch every time, and the algorithm’s entire memory of everything before this pass is where to look.

The sampled rule’s carry is larger, because the split points have to survive: an interval, a count, and ss order statistics. That is the only carry in these essays that grows with the parameter, and it is what an adaptive rule costs at the boundary as well as in passes.

The carry is enforced rather than believed. Between passes the algorithm’s state is wiped and rebuilt from its declared carry alone, so a procedure keeping a hash map on the side returns a wrong answer rather than a flattering number.

The two passes at the ends are different from the others

The sweep hides a structural point that is worth drawing out, because it explains both ends of every curve above.

The last pass is not a narrowing pass. It keeps whatever is inside the interval and sorts it, and its state is the survivor count rather than the split count. So a pp-pass run has p1p-1 narrowings and one collection, and at small pp the collection dominates: at two passes the single narrowing leaves 214 survivors and 11,712 bits, of which the counters are a fifth.

And the first narrowing is the only one that sees the whole data. Every later pass counts only what is inside the current interval, so the later passes are cheaper in work even though they are the same length in reads. That asymmetry is invisible in a state measurement and is most of what a real implementation would care about.

Between them these explain why adding a pass helps enormously at the cheap end and barely at all at the expensive one. Going from two passes to three replaces one enormous collection with a narrowing and a smaller collection — a factor of five and a half. Going from seven to nine replaces two small narrowings with two smaller ones, and the split count is already down to four or five where integer rounding dominates.

There is a point past which more passes buy nothing, and it is where n1/pn^{1/p} reaches the smallest split count that makes sense. At s=2s = 2 each pass halves the interval and p=log2np = \log_2 n passes are needed — fifteen here — which is the binary search the whole method generalises. Below that split count there is nothing left to give up.

There is a third repair that costs neither a pass nor an assumption, and it is worth naming because it is what a production selector usually does: cut on the bits of the values rather than on their range. A radix split on the top log2s\log_2 s bits is an equal-width cut in disguise, so it inherits the collapse; a split on the exponent field of a floating-point value is an equal-width cut in the logarithm, so it inherits the repair. The representation the values already carry decides which of the two rules is being run, and neither the code nor the analysis mentions it, which makes this one of the quieter ways a method’s behaviour is settled by something nobody chose.

Where the passes actually come from

Nothing here charges for a pass, and it is worth saying where the charge would come from if it were made, because it is a field this collection already has.

In the external-memory model a pass is n/Bn/B block transfers, so a nine-pass algorithm holding 320 bits does nine times the I/O of a one-pass algorithm holding a million. Which of those is better depends on the ratio between memory and bandwidth, and that ratio is a property of a machine rather than of an algorithm.

So passes and space are being traded here and the exchange rate is deliberately left out. What the plates establish is which points are on the frontier; what a reader supplies is what a pass costs where their data lives. On a wire it is infinite — there is no second pass — and every point but the leftmost is unavailable.

Whether the sampled rule’s passes can be fused

The sampled rule spends half its passes producing no narrowing at all, which is the whole of why it loses on uniform data. The obvious repair is to fuse the two: gather the reservoir while counting, so that every pass both narrows the interval and collects the sample the next narrowing will cut on.

It is worth working out what that costs, because the arithmetic settles the question and the answer is not the one the idea promises.

A reservoir gathered during pass ii is a sample of the interval as it stood during pass ii. At the end of the pass the interval shrinks to one piece in ss, and only the sampled values that happen to fall inside that piece are usable as cut points for the next pass. In expectation that is one in ss of them. So a fused rule that wants ss usable order statistics at every pass must carry a reservoir of about s2s^2, and the state during a narrowing pass becomes s2s^2 counters-and-samples rather than ss counters.

Balance that against the survivors as before. The peak is now the larger of s2s^2 and n/sp1n/s^{\,p-1}, which is minimised at sn1/(p+1)s \approx n^{1/(p+1)}, giving a peak of about n2/(p+1)n^{2/(p+1)} against the unfused rule’s n1/p/2n^{1/\lceil p/2 \rceil}. Fusion wins for large pp and loses for small pp, and the crossover is around five passes — which is exactly where the sampled column above stops improving for a different reason.

Two honest caveats on that paragraph. The factor of ss in the surviving sample is an expectation and a run can be unlucky, so a fused implementation needs a fallback for the pass where too few samples survive, and a fallback that reverts to equal-width cuts inherits the collapse this essay is about. And none of it is measured here: the arithmetic above is a derivation from the same balance that produced n1/pn^{1/p}, offered as a reason not to expect much rather than as a result. A cheap derivation that says an idea is not worth implementing is worth more than an expensive implementation that says the same thing, provided it is labelled as what it is.

A transform is a cheaper repair than a pass

The sampled rule buys its robustness with passes. There is a repair that costs none, and putting it beside the other two makes the essay’s thesis sharper rather than softer.

Cut at equal widths in logv\log v rather than in vv. On a Pareto or a log-normal distribution the mass is spread evenly in the logarithm, so equal-width cuts in log space hold roughly equal counts, and the narrowing behaves the way it does on uniform data. The cut points are still computed from the range alone, no pass is spent learning anything, and the carry does not grow.

What has changed is not the amount of knowledge the rule uses but its honesty about it. Equal-width cuts on the raw values are a bet that the data is uniform; equal-width cuts on the logarithm are a bet that it is log-uniform. Neither rule reads the data and both are assumptions; the second is simply a better assumption about the kind of data that produced the disastrous column above, and it is wrong in its own way — on uniform data it puts most of the mass in the last piece and collapses exactly as the first rule does on a heavy tail.

That symmetry is the point. There is no distribution-free rule that reads no data, and the sampled rule’s extra pass is the price of not having to guess which family the data is in. A deployment that knows its latencies are log-normal should cut on the logarithm and keep its passes; one that does not know should spend the pass and stop guessing.

It also names precisely what the sampled rule is buying, which the tables above leave implicit. It is not accuracy — every point on every curve is an exact answer. It is not passes — it spends more of them. It is independence from a property of the data that nobody wrote down, and that is worth paying for in proportion to how surprising the data is allowed to be.

What is not measured here

Randomised selection in one pass, approximately. The whole apparatus above is about exactness. An approximate median is available in one pass and very little space, from the quantile summaries two essays back, and the comparison between “exact in nine passes” and “within one per cent in one” is a comparison of different products.

Work. Each pass here scans the whole data. A narrowing pass could skip values outside the interval if the data were indexed, and the count of operations would then fall with the interval rather than staying at nn every pass. Nothing here measures operations, only state.

The known bound. Munro and Paterson proved a Ω(n1/p)\Omega(n^{1/p}) lower bound for pp-pass selection in a comparison-based model in 1980, and the measurements above sit on that shape. The bound itself is not demonstrated here, and the next essay is precise about which parts of the floor this collection performs and which it quotes.

Peak state against passes, for two splitting rules on two distributionsExact selection of the 0.5 quantile of 32,768 values, in p passes, with the state measured at its peak during the run. Every point is an exact answer — a run that returned anything else stops the build — so the vertical axis is the price of exactness rather than a price paid for being approximately right. The line at the top is what one pass costs: 1,048,576 bits, because an exact one-pass selector has to keep the stream, and the floor under that is a counting argument this collection performs rather than quotes. The equal-width rule needs no knowledge of the data and gets 37 times smaller as passes are added — on data spread evenly. On a heavy tail it collapses, because an equal-width cut of a range containing almost no data narrows the range and not the count; the sampled rule, which spends half its passes finding out where the data is, is barely affected. Both axes are logarithmic.10³10⁴10⁵10⁶passes over the datapeak bits of stateone pass, exact: 1,048,576 bitsradix, uniformradix, paretoevery point exact · 32,768 values320 bits at best
Fig. 8 The deterministic rule alone on both distributions, which is the plate the equal-width section is about: two lines with the same method, the same pass counts and the same split counts, separated by three orders of magnitude by nothing but what the data looks like.

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.

Complexity classExternal-memoryFittingHeavy tailHonest limitMeasurementMulti-passSamplingSelectionState bitsStreaming modelTrade off