/** * Statistical-distribution core — pure and engine-agnostic. * * A `number` generator can draw from a named distribution instead of a uniform * range (``), so a * column looks like real data (heights, salaries, inter-event times, wealth). * * Design: `docs/superpowers/specs/2026-07-15-statistical-distributions-design.md`. * * Two invariants make this work with the streaming/disk engines: * - **Fixed draws.** Each distribution consumes a FIXED number of uniform * draws (`spec.draws`), so a row's value is seekable — computable from its * index without generating the others. Only inverse-CDF / Box–Muller here; * no rejection sampling (which would consume a variable number of draws). * - **No dependency.** The math is hand-rolled and portable. `sampleDistribution` * is covered by golden vectors — the exact-number contract every language * port must reproduce from the same uniforms. * * `sampleDistribution` takes the uniforms as input; the ENGINE supplies them * (the render PRNG in memory, a seekable draw per row when streaming). Uniforms * MUST lie in the open interval (0, 1) — never exactly 0 or 1. */ interface Base { /** How many uniform draws in (0,1) `sampleDistribution` needs for this spec. */ readonly draws: number; /** Output precision — digits after the decimal point (0 ⇒ integer). */ readonly decimals: number; /** Optional inclusive clip of the sampled value. */ readonly min?: number; readonly max?: number; } export type DistributionSpec = Base & ({ readonly name: 'normal'; readonly mean: number; readonly sd: number; } | { readonly name: 'lognormal'; readonly meanlog: number; readonly sdlog: number; } | { readonly name: 'exponential'; readonly rate: number; } | { readonly name: 'pareto'; readonly alpha: number; readonly xmin: number; } | { readonly name: 'weibull'; readonly shape: number; readonly scale: number; } | { readonly name: 'poisson'; readonly lambda: number; readonly cdf: readonly number[]; } | { readonly name: 'zipf'; readonly n: number; readonly s: number; readonly cum: readonly number[]; } | { readonly name: 'gamma'; readonly shape: number; readonly scale: number; } | { readonly name: 'beta'; readonly alpha: number; readonly beta: number; }); export type DistributionName = DistributionSpec['name']; /** * Sample the distribution from `uniforms` (length ≥ `spec.draws`, each in * (0,1)). Returns the RAW value — clipping and rounding happen in * `formatSample`. */ export declare function sampleDistribution(spec: DistributionSpec, uniforms: readonly number[]): number; /** Clip the raw sample to `[min, max]` (if set), then round to `decimals`. */ export declare function formatSample(x: number, spec: DistributionSpec): string; /** * Parse and validate the distribution attributes of a `number` gen. Throws a * plain `Error` (callers add gen/source context). Only reads distribution * attributes — the incompatibility of `distribution` with range/percent/uniq is * enforced at the validation layer, which sees the whole gen. */ export declare function parseDistribution(attrs: Record): DistributionSpec; /** * Every attribute a distribution reads as a NUMBER — the ones that may instead * be an expression over the row's other columns. * * Kept as one list so "which parameters can follow a column" has a single * answer, rather than each caller remembering a different subset. */ export declare const DISTRIBUTION_PARAMS: readonly string[]; /** * The parameters this generator wrote as an EXPRESSION rather than a number. * * A bare number stays the degenerate case, so a config that never wanted this * pays nothing: the spec is parsed once, exactly as before, and only a config * that actually names a column takes the per-row path. * * This does NOT change how many uniforms a row consumes — `draws` depends only * on WHICH distribution, never on its parameters — so the property every engine * is built on (a row computable without its predecessors) is untouched. That is * the difference from `repeat=`, where a per-row count would have changed the * draw budget and was therefore refused; see `sequence/repeat.ts`. */ /** * How many uniforms a row of this distribution consumes, known from the NAME * alone — no parameters needed. * * Wanted by a row that cannot be drawn at all (a parameter read an empty cell), * which must still spend what a drawn row would spend. Otherwise blanking one * cell would slide every value after it, and a `parent=` filter would quietly * rewrite the rest of the column. */ export declare function distributionDraws(attrs: Record): number; export declare function expressionParams(attrs: Record): readonly string[]; export {}; //# sourceMappingURL=distribution.d.ts.map