/** * A file read as a QUANTILE FUNCTION rather than as a bag of values. * * `` — the file is one * measurement per line, the engine sorts it once, and a row lands anywhere on * that sorted ruler, interpolating between two neighbours when it falls between * them. * * ### Why this exists beside `weight=` * * `weight=` reproduces declared shares EXACTLY (measured: 2.30/24.40/50.00 against * 2.3/24.4/50 requested), and for a countable quantity — a city, a status, a * number of orders — it is the final answer. But it can only ever emit values * that were written in the file. Ask for a million rows from a thousand-line * sample and you get a thousand distinct values with nothing between them: a * comb. For a MEASURED quantity — money, weight, a response time — that comb is * a structure the real data never had, and a model trained on it learns the * structure. * * Reading the same sample as a quantile function fixes it, and costs nothing * else: the values between observations appear on their own, the resolution * follows the mass rather than the range (a six-order-of-magnitude tail costs no * more points than a narrow hump), and a value repeated in the sample becomes a * flat shelf of exactly its own share — so atoms survive alongside the * continuum. * * ### Why it fits the engine * * One uniform per row, and the answer depends on that row alone. So it streams, * it parallelises, and it needs no totals up front — unlike `weight=`, which is * in-memory precisely because an exact quota has to see the whole file first. * * ### The precision question, decided by the source * * Interpolating between 31 and 40 gives 35.4, which is right for money and wrong * for a count of orders. Rather than guess, the answer is printed with the same * number of decimal places as the SOURCE: a whole-number sample gives whole * numbers, a sample written to the cent gives cents. `decimals=` overrides it. */ /** A source read as a quantile function: sorted values, and how they were written. */ export interface QuantileSource { /** The sample, ascending. Duplicates are kept — they are what makes an atom. */ readonly sorted: readonly number[]; /** The most decimal places any line used, so the answer is written like the source. */ readonly decimals: number; } export declare class QuantileError extends Error { readonly name = "QuantileError"; } /** * Parse and sort the file's values. * * A line that is not a number is refused rather than skipped: dropping it would * change the very shape the file was chosen for, and silently. The message names * the line, because in a file of ten thousand numbers "one of them is not a * number" is not an answer anyone can act on. */ export declare function quantileSource(values: readonly string[], src: string): QuantileSource; /** * The value at probability `u`, interpolating between neighbours. * * Each observation sits at `(i + 0.5) / n` — the MIDDLE of the slice of * probability it owns — rather than at `i / (n - 1)`, which is where the ends * of the sample would be. That is not a detail of taste; the end convention * gives the smallest and largest observations exactly HALF the weight they * should have, because there is nothing on the far side of them to ramp from. * Measured before this was fixed, on a file of a hundred distinct values that * each owe 1.000%: * * first 0.505% … middle 1.010% … last 0.505% * * The middle was over by 100/99 for the same reason the edges were short. * * It also decides what a REPEATED value is worth. An atom of multiplicity `k` * holds a plateau `(k-1)/n` wide, and the two ramps leaving it each round their * near half onto it — `1/n` more — so the atom gets exactly its `k/n`. Under the * end convention it got `(k-1)/(k)` of its share: a value written twice was * worth once, in a sample of any size. * * `u` below `0.5/n` and above `1 - 0.5/n` lands on the smallest and largest * observation, which is what returns their full weight — and it is the same * convention the ROW axis already uses, where row `i` reads `(slot + 0.5) / * count`. One rule on both axes, which is what it should have been. */ export declare function quantileAt(sorted: readonly number[], u: number): number; /** The finished cell: the interpolated value, written like the source unless told otherwise. */ export declare function renderQuantile(value: number, decimals: number): string; /** * The EXACT sweep: every row takes its own point on the ruler, no dice at all. * * Row `i` is sent to slot `permute(i, count, key)` and reads probability * `(slot + 0.5) / count`. Over the whole run the slots are the numbers `0 … * count-1` exactly once each, so the generated column reproduces the sample's * distribution with no sampling noise whatever — not "0.5% off", but the same * empirical distribution stretched to whatever number of rows was asked for. * * The permutation is what keeps it usable: without it the column would come out * sorted. It is the same seekable, seeded permutation `uniq` and the exact * `percent=` quota already use, so a row still costs nothing to compute on its * own and `--jobs` keeps working. * * Slot and row are separate arguments because the two engines number rows * differently under a `parent=` filter: the in-memory one by position in the * subset, the streaming one by population index. Both hand in the same number. */ export declare function exactQuantileAt(source: QuantileSource, decimals: number, count: number, key: number, position: number): string; //# sourceMappingURL=quantile.d.ts.map