/** * Which MEMBER of a pool a reference hands each row. * * One place, because three engines and one repair all need the same answer. The * in-memory engine asks for every row up front, the streaming engines ask for * row 900,000 without the rows before it, and a config-level `` asks * "who did the sequence before me take" — those are the same question, and * before this file they were two copies of it that a change could separate. * * The pick is a pure function of (seed, reference name, row) plus, when a * `filter=` narrows the candidates, the values other columns hold on that row. * Purity is what lets the streaming engines seek and what lets the repair below * replay a row without materialising a column. */ import { type PoolTable, type PoolTables } from './pool.js'; import type { Sequence, SequenceSpec } from './types.js'; /** * A reference's pick, opened up. * * `candidates` is the set the row may draw from — every member, or the ones a * `filter=` leaves standing. `pick` is the one it actually takes. They are * separate because the repair needs the set: told that its member is taken, it * draws again from what remains rather than guessing and retrying. */ export interface MemberPicker { readonly table: PoolTable; /** The members row `i` may have, in ascending order. Throws when none pass. */ candidates: (i: number) => readonly number[]; /** The member row `i` takes, with no group repair applied. */ pick: (i: number) => number; /** * Whether row `i` gets a member at all. * * `parent=` narrows a reference to the rows its parent selected; the others * print nothing. A group must not count those rows, or an invisible column * takes a doctor away from the visible one beside it — measured on a pool of * two, where it pinned the second reference to the other member on every row * the first was absent from. */ active: (i: number) => boolean; } /** Draw one of `candidates` for row `i`, on the reference's own stream. */ export declare function drawFrom(seed: string, refName: string, candidates: readonly number[], i: number, attempt?: number): number; export declare function memberPicker(spec: SequenceSpec, poolName: string, table: PoolTable, registry: Record, seed: string, /** * How many rows the run has — only ever read to size a `parent=` mask. * * `undefined` from the streaming path, which has no row count to give and * needs none: it refuses a pool reference with `parent=` before it gets here, * so `active` is the constant true there. */ count?: number): MemberPicker; /** * `` around two or more references to the same pool. * * The group asks that no two of them hand ONE row the same member. A record has * no value of its own to compare — `${{Doctor}}` is not a string — so the * comparison is by identity: which member of the pool this row took. * * The repair happens at PICK time rather than on finished columns, and that is * what makes it work in all three engines from one place: the pick is a pure * function of the row, so the streaming engines replay a row's group without * materialising a column, exactly as they already replay a filter. * * A collision is not retried blindly. The candidate set is known, so the member * is drawn again from the candidates this row has NOT already given away — * uniform over what remains, deterministic, and it either succeeds or proves * there was nothing left to take. */ export declare function poolGroupPickers(groups: readonly (readonly string[])[], pickers: ReadonlyMap, seed: string): Map number>; /** * Every pool reference in `specs`, opened up so a group can have a say. * * Cheap: a picker is a closure over the pool table, not a column. Nothing is * drawn until a group asks, and a config with no group over references never * asks, so its run is what it was. */ export declare function poolPickers(specs: readonly SequenceSpec[], registry: Record, pools: PoolTables | undefined, seed: string, count: number): Map; /** * `` around two or more references to the same pool. * * The group asks that no two ROWS take the same combination of members. For * scalars that promise is kept by rearranging finished columns — every column * keeps its multiset, so nothing about the data changes except which row holds * what. Here the thing rearranged is the sequence of MEMBER PICKS, and the * fields follow for free: a field is a pure function of the member, so a row * that receives another row's pick receives that member whole and stays a * coherent record. * * Whole-column work by nature — an arrangement cannot be found a row at a time * — which is the same shape the scalar path already has on every engine. */ export declare function poolUniqPicks(groups: readonly (readonly string[])[] | undefined, pickers: ReadonlyMap, count: number): Map number>; /** * Both group kinds at once — the one entry point the engines call. * * `` is settled per row and `` across rows, so they cannot both * own the same reference; a sequence lives inside one wrapper element, and that * element decides which of the two it is. */ export declare function poolGroupPicks(groups: { readonly distinct?: readonly (readonly string[])[] | undefined; readonly uniq?: readonly (readonly string[])[] | undefined; }, specs: readonly SequenceSpec[], registry: Record, pools: PoolTables | undefined, seed: string, count: number): Map number>; //# sourceMappingURL=pool-member.d.ts.map