@mark1russell7/rigor-bench 0.2.15 → 0.2.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -1
- package/build/fresh.js +1 -1
- package/build/index.d.ts +103 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +204 -13
- package/build/index.js.map +1 -1
- package/build/paired.d.ts +11 -1
- package/build/paired.d.ts.map +1 -1
- package/build/paired.js +17 -1
- package/build/paired.js.map +1 -1
- package/package.json +1 -1
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["round","round"],"sources":["../src/budget.ts","../src/gate.ts","../src/control.ts","../src/ladder.ts","../src/verdict.ts","../src/limit.ts","../src/merge.ts","../src/measures.ts","../src/power.ts","../src/rounds.ts"],"sourcesContent":["/**\n * The budget verdict of one build: is the median of a measure of each case at most an absolute limit? An example is the\n * claim \"the median blocking time of this page is at most 450 ms\". The time verdict and the limit verdict judge a ratio\n * of two arms, so they cannot use a value of 0. Their A/A band is also a ratio.\n */\nimport { median, medianInterval } from \"@mark1russell7/rigor-statistics\";\n\n/** One value of one build on one case. The value is finite and 0 or more. */\nexport interface BudgetRound {\n /** The name of the case: one input of the bench. */\n readonly case: string;\n /** The number of the round, a whole number of 0 or more. */\n readonly round: number;\n readonly value: number;\n}\n\n/** The three outcomes of a budget verdict. */\nexport type BudgetOutcome = \"within\" | \"beyond\" | \"cannot decide\";\n\n/** The options of a budget verdict. */\nexport interface BudgetOptions {\n /** The largest median that the claim permits, in the unit of the values. */\n readonly limit: number;\n /** The largest difference between the medians of the two arms of the same build. A larger difference makes the run too noisy. */\n readonly maxDifference: number;\n /** The level of the interval of each median. The default is 0.95, which needs 6 rounds or more in each arm. */\n readonly caseLevel?: number;\n}\n\n/** The verdict of one case against the budget. */\nexport interface CaseBudget {\n readonly case: string;\n /** The number of rounds of the case. */\n readonly rounds: number;\n /** The number of rounds of the case in the A/A arm. */\n readonly aaRounds: number;\n readonly median: number;\n /** The median of the A/A arm, or undefined when the A/A arm does not have the case. */\n readonly aaMedian: number | undefined;\n /** The size of the difference between the two medians, or undefined when the A/A arm does not have the case. */\n readonly difference: number | undefined;\n /** The ends of the distribution-free interval of the median. */\n readonly low: number;\n readonly high: number;\n /** The coverage of the interval. Below the level, the case has too few rounds. */\n readonly coverage: number;\n readonly outcome: BudgetOutcome;\n /** The reason of the outcome, in one sentence, with the limit, the medians, the difference and the rounds. */\n readonly reason: string;\n}\n\n/** A budget verdict, with the facts that it uses. */\nexport interface BudgetVerdict {\n readonly outcome: BudgetOutcome;\n /** The reason of the outcome, in one sentence. */\n readonly reason: string;\n readonly limit: number;\n readonly maxDifference: number;\n readonly level: number;\n readonly cases: readonly CaseBudget[];\n}\n\n/** This function gives the values of each case, and it refuses a value out of range or a round that comes twice. */\nfunction valuesOfCases(name: string, rounds: readonly BudgetRound[]): Map<string, number[]> {\n const seen = new Set<string>();\n const out = new Map<string, number[]>();\n for (const r of rounds) {\n if (!(Number.isFinite(r.value) && r.value >= 0)) throw new RangeError(`budgetVerdict: the value of ${JSON.stringify(r.case)} in ${name} is finite and 0 or more, not ${r.value}.`);\n const key = JSON.stringify([r.case, r.round]);\n if (seen.has(key)) throw new RangeError(`budgetVerdict: the round ${r.round} of ${JSON.stringify(r.case)} comes twice in ${name}.`);\n seen.add(key);\n out.set(r.case, [...(out.get(r.case) ?? []), r.value]);\n }\n return out;\n}\n\n/** This function gives the verdict of one case. */\nfunction caseBudget(name: string, values: readonly number[], aaValues: readonly number[], options: BudgetOptions, level: number): CaseBudget {\n const { limit, maxDifference } = options;\n const interval = medianInterval(values, level);\n const middle = median(values);\n const aaMedian = aaValues.length > 0 ? median(aaValues) : undefined;\n const difference = aaMedian === undefined ? undefined : Math.abs(middle - aaMedian);\n const aaCoverage = aaValues.length > 0 ? medianInterval(aaValues, level).coverage : 0;\n const facts = `median ${round(middle)} of ${values.length} rounds, interval ${round(interval.low)} to ${round(interval.high)}, limit ${limit}, A/A median ${aaMedian === undefined ? \"none\" : round(aaMedian)} of ${aaValues.length} rounds, difference ${difference === undefined ? \"none\" : round(difference)}`;\n const decide = (outcome: BudgetOutcome, why: string): CaseBudget => ({\n case: name,\n rounds: values.length,\n aaRounds: aaValues.length,\n median: middle,\n aaMedian,\n difference,\n low: interval.low,\n high: interval.high,\n coverage: interval.coverage,\n outcome,\n reason: `The case ${JSON.stringify(name)} has the outcome \"${outcome}\": ${why} (${facts}).`,\n });\n if (difference === undefined) return decide(\"cannot decide\", \"the A/A arm does not have the case\");\n if (interval.coverage < level || aaCoverage < level) return decide(\"cannot decide\", `an arm has too few rounds for the level ${level}`);\n if (difference > maxDifference) return decide(\"cannot decide\", `the A/A difference is above ${maxDifference}`);\n if (interval.high <= limit) return decide(\"within\", \"the interval is at or below the limit\");\n if (interval.low > limit) return decide(\"beyond\", \"the interval is above the limit\");\n return decide(\"cannot decide\", \"the interval holds the limit\");\n}\n\n/**\n * This function gives the verdict of the claim \"the median of each case is at most `limit`\". The arm `aa` is a second\n * arm of the same build, and it shows the noise of the run as a difference. Values of 0 are valid.\n * - A case is `cannot decide` when the A/A arm does not have it, or when an arm has too few rounds for the level.\n * - A case is also `cannot decide` when the medians of the two arms differ by more than `maxDifference`.\n * - Other cases are `within` when the high end of the interval is at most the limit.\n * - They are `beyond` when the low end of the interval is above the limit.\n * - The verdict is `beyond` when a case is `beyond`, and `within` when each case is `within`.\n * - Each other verdict is `cannot decide`, and so is a verdict with no cases.\n */\nexport function budgetVerdict(rounds: readonly BudgetRound[], aa: readonly BudgetRound[], options: BudgetOptions): BudgetVerdict {\n const { limit, maxDifference } = options;\n const level = options.caseLevel ?? 0.95;\n if (!(limit >= 0 && Number.isFinite(limit))) throw new RangeError(`budgetVerdict: the limit is finite and 0 or more, not ${limit}.`);\n if (!(maxDifference >= 0 && Number.isFinite(maxDifference))) throw new RangeError(`budgetVerdict: the largest difference is finite and 0 or more, not ${maxDifference}.`);\n const values = valuesOfCases(\"the rounds\", rounds);\n const aaValues = valuesOfCases(\"the A/A arm\", aa);\n const cases = [...values.keys()].sort().map((name) => caseBudget(name, values.get(name) ?? [], aaValues.get(name) ?? [], options, level));\n return verdictOf(cases, { limit, maxDifference, level });\n}\n\n/** This function gives the verdict of a list of case verdicts. */\nfunction verdictOf(cases: readonly CaseBudget[], claim: Pick<BudgetVerdict, \"limit\" | \"maxDifference\" | \"level\">): BudgetVerdict {\n const facts = { ...claim, cases };\n if (cases.length === 0) return { outcome: \"cannot decide\", reason: \"The verdict has no cases.\", ...facts };\n const first = cases.find((c) => c.outcome === \"beyond\") ?? cases.find((c) => c.outcome === \"cannot decide\");\n if (first === undefined) {\n const top = cases.reduce((a, b) => (b.high > a.high ? b : a));\n return { outcome: \"within\", reason: `Each of the ${cases.length} cases is within. The largest is this one: ${top.reason}`, ...facts };\n }\n const count = cases.filter((c) => c.outcome === first.outcome).length;\n return { outcome: first.outcome, reason: `${count} of ${cases.length} cases have this outcome. The first is this one: ${first.reason}`, ...facts };\n}\n\n/** One look of a budget with looks: the rounds of each arm, and the level of the interval at those rounds. */\nexport interface BudgetLook {\n readonly rounds: number;\n readonly level: number;\n}\n\n/**\n * These looks start with 6 rounds, as `budgetVerdict` does, and they stop at 24. The three looks spend 0.0442 of the\n * overall 0.05. On the blocking times of a noisy web page, 97% of the runs with a median 16% under the limit stop by 24.\n */\nexport const BUDGET_LOOKS: readonly BudgetLook[] = [\n { rounds: 6, level: 0.95 },\n { rounds: 12, level: 0.99 },\n { rounds: 24, level: 0.99 },\n];\n\n/** The options of a budget verdict with looks. */\nexport interface BudgetLooksOptions {\n /** The largest median that the claim permits, in the unit of the values. */\n readonly limit: number;\n /** The largest difference between the medians of the two arms of the same build. */\n readonly maxDifference: number;\n /** The looks, with the rounds in rising order. The default is `BUDGET_LOOKS`. */\n readonly looks?: readonly BudgetLook[];\n /** The level over all looks of one case. The default is 0.95. */\n readonly level?: number;\n}\n\n/** The next look of one case: the rounds that each arm of the case needs. */\nexport interface BudgetMore {\n readonly case: string;\n readonly rounds: number;\n}\n\n/** A budget verdict with looks. The field `level` is the level over all looks. */\nexport interface BudgetLooksVerdict extends BudgetVerdict {\n /** The chance of error that the looks spend: the sum of 1 - coverage over the looks. */\n readonly spent: number;\n /** The cases with no outcome that can have another look. The list is empty when the verdict is final. */\n readonly more: readonly BudgetMore[];\n /** True only when the interval of a case is above the limit. A case with no outcome at the last look does not fail. */\n readonly fails: boolean;\n}\n\n/**\n * This function gives the chance of error that a list of looks spends: the sum of 1 - coverage of each look. This sum is\n * the Bonferroni bound over the looks. A look that has too few rounds for its level gives a `RangeError`.\n */\nexport function budgetLookSpend(looks: readonly BudgetLook[]): number {\n if (looks.length === 0) throw new RangeError(\"budgetLookSpend: the list of looks is empty.\");\n let spent = 0;\n let last = 0;\n for (const { rounds, level } of looks) {\n if (!(Number.isInteger(rounds) && rounds > last)) throw new RangeError(`budgetLookSpend: the rounds of the looks are whole numbers in rising order, not ${rounds} after ${last}.`);\n const { coverage } = medianInterval(\n Array.from({ length: rounds }, (_, i) => i),\n level,\n );\n if (coverage < level) throw new RangeError(`budgetLookSpend: ${rounds} rounds are too few for the level ${level}.`);\n spent += 1 - coverage;\n last = rounds;\n }\n return spent;\n}\n\n/** This function gives the outcome of one case: the first look with an outcome, or the last look that the rounds reach. */\nfunction caseAtLooks(name: string, values: readonly number[], aaValues: readonly number[], options: BudgetOptions, looks: readonly BudgetLook[]): { verdict: CaseBudget; next: number | undefined } {\n let verdict: CaseBudget | undefined;\n for (const { rounds, level } of looks) {\n if (values.length < rounds || aaValues.length < rounds) {\n return { verdict: verdict ?? caseBudget(name, values, aaValues, options, level), next: rounds };\n }\n verdict = caseBudget(name, values.slice(0, rounds), aaValues.slice(0, rounds), options, level);\n if (verdict.outcome !== \"cannot decide\") return { verdict, next: undefined };\n }\n return { verdict: verdict as CaseBudget, next: undefined };\n}\n\n/**\n * This function gives the budget verdict of a run that adds rounds. A caller gives all rounds so far, and it gets a\n * verdict and the field `more`. It adds the rounds of `more` to both arms, and it calls the function again.\n *\n * The chance of error of one look is 1 - coverage. The coverage is 1 - 2 P(X <= k - 1), for X ~ Binomial(n, 1/2) and\n * the rank k of the interval. The nominal level does not give this chance. The default looks have these figures:\n *\n * | Rounds n | Level | Rank k | Coverage | Chance of error |\n * | ---: | ---: | ---: | ---: | ---: |\n * | 6 | 0.95 | 1 | 0.96875 | 0.03125 |\n * | 12 | 0.99 | 2 | 0.99365 | 0.00635 |\n * | 24 | 0.99 | 6 | 0.99339 | 0.00661 |\n * | Sum | | | | 0.04421 |\n *\n * The sum is the Bonferroni bound over the looks. Each coverage needs independent rounds. Rounds with a shared cause, for\n * example a slow computer for one run, do not have that coverage.\n *\n * - The first look of a case with an outcome decides the case. Later rounds do not change it.\n * - Each look reads the rounds of that look in the order of their numbers. Thus a verdict comes again from its records.\n * - A sum of `budgetLookSpend` above 1 - `level` gives a `RangeError`, because many looks at one level spend too much.\n * - The field `fails` is true only for the outcome `beyond`. Tell a final `cannot decide` to the reader of the run.\n */\nexport function budgetLooksVerdict(rounds: readonly BudgetRound[], aa: readonly BudgetRound[], options: BudgetLooksOptions): BudgetLooksVerdict {\n const { limit, maxDifference } = options;\n const looks = options.looks ?? BUDGET_LOOKS;\n const level = options.level ?? 0.95;\n const spent = budgetLookSpend(looks);\n if (spent > 1 - level) throw new RangeError(`budgetLooksVerdict: the looks spend ${round(spent)}, over the ${round(1 - level)} of the level ${level}.`);\n if (!(limit >= 0 && Number.isFinite(limit))) throw new RangeError(`budgetLooksVerdict: the limit is finite and 0 or more, not ${limit}.`);\n if (!(maxDifference >= 0 && Number.isFinite(maxDifference))) throw new RangeError(`budgetLooksVerdict: the largest difference is finite and 0 or more, not ${maxDifference}.`);\n const byRound = (list: readonly BudgetRound[]): BudgetRound[] => [...list].sort((a, b) => a.round - b.round);\n const values = valuesOfCases(\"the rounds\", byRound(rounds));\n const aaValues = valuesOfCases(\"the A/A arm\", byRound(aa));\n const results = [...values.keys()].sort().map((name) => ({ name, ...caseAtLooks(name, values.get(name) ?? [], aaValues.get(name) ?? [], { limit, maxDifference }, looks) }));\n const verdict = verdictOf(\n results.map((r) => r.verdict),\n { limit, maxDifference, level },\n );\n const more = results.flatMap((r) => (r.next === undefined ? [] : [{ case: r.name, rounds: r.next }]));\n return { ...verdict, spent, more, fails: verdict.cases.some((c) => c.outcome === \"beyond\") };\n}\n\nfunction round(x: number): number {\n return Math.round(x * 10_000) / 10_000;\n}\n","/**\n * The gate of a bench: the result that a check of a merge reads. A verdict gives one of the words of `LimitOutcome` for each\n * case, and the gate gives \"pass\", \"block\" or \"no read\". A case with no outcome does not pass.\n */\nimport { holm, median, partialConjunction, signTest } from \"@mark1russell7/rigor-statistics\";\nimport type { BudgetMore } from \"./budget.ts\";\nimport type { LimitOutcome } from \"./limit.ts\";\nimport type { JobRecords } from \"./merge.ts\";\nimport { type Arm, type PairedTime, checkPairedTime } from \"./paired.ts\";\n\n/** The three results of a gate. */\nexport type GateOutcome = \"pass\" | \"block\" | \"no read\";\n\n/** The fields of a case that a gate reads. The cases of `limitVerdict`, `budgetVerdict` and the verdict of this file have them. */\nexport interface GateCaseOutcome {\n readonly case: string;\n readonly outcome: LimitOutcome;\n}\n\n/** The result of a gate, with the cases that make it. */\nexport interface Gate {\n readonly outcome: GateOutcome;\n /** The reason of the result, in one sentence. */\n readonly reason: string;\n /** The cases with the outcome `beyond`. */\n readonly blocks: readonly string[];\n /** The cases with the outcome `cannot decide`. */\n readonly noRead: readonly string[];\n}\n\n/**\n * This function gives the gate of a list of case outcomes.\n * - The result is \"block\" when a case is `beyond`.\n * - The result is \"pass\" when each case is `within`.\n * - Each other result is \"no read\", and so is a list with no cases. A caller does not count \"no read\" as a pass.\n */\nexport function gateOf(cases: readonly GateCaseOutcome[]): Gate {\n const names = (outcome: LimitOutcome): string[] => cases.filter((c) => c.outcome === outcome).map((c) => c.case);\n const blocks = names(\"beyond\");\n const noRead = names(\"cannot decide\");\n if (cases.length === 0) return { outcome: \"no read\", reason: \"The gate has no cases.\", blocks, noRead };\n if (blocks.length > 0) return { outcome: \"block\", reason: `${blocks.length} of ${cases.length} cases are beyond the claim. The first is ${JSON.stringify(blocks[0])}.`, blocks, noRead };\n if (noRead.length > 0) return { outcome: \"no read\", reason: `${noRead.length} of ${cases.length} cases have no outcome. The first is ${JSON.stringify(noRead[0])}.`, blocks, noRead };\n return { outcome: \"pass\", reason: `Each of the ${cases.length} cases is within the claim.`, blocks, noRead };\n}\n\n/** The word of a case for the claim \"not slower by more than the margin\". The word \"not slower\" is apart from `same` of `timeVerdict`. */\nexport type NotSlowerRead = \"not slower\" | \"slower\" | \"no read\";\n\nconst READ_OF: Record<LimitOutcome, NotSlowerRead> = { within: \"not slower\", beyond: \"slower\", \"cannot decide\": \"no read\" };\n\n/** The looks of `notSlowerVerdict`: the rounds in each job. The level of the family has an equal share at each look. */\nexport const GATE_LOOKS: readonly number[] = [12, 24, 48];\n\n/** The options of `notSlowerVerdict`. */\nexport interface NotSlowerOptions {\n /** The margin of each case on a log scale: a number, or a function of the name of the case. */\n readonly margin: number | ((name: string) => number);\n /** The chance of a false \"not slower\", and apart from it the chance of a false \"slower\", over the family and all looks. The default is 0.05. */\n readonly level?: number;\n /** The looks: even whole numbers in rising order. The default is `GATE_LOOKS`. */\n readonly looks?: readonly number[];\n /** The count of jobs that each need the bound. The default is 2, because more rounds do not remove a difference between jobs. */\n readonly jobs?: number;\n}\n\n/** The read of one case in one job, at one look. */\nexport interface GateJobRead {\n readonly job: string;\n /** The pairs of rounds that the look uses. Below the rounds of the look, the job has not reached the look. */\n readonly rounds: number;\n /** The count of pairs with a difference below the margin. */\n readonly below: number;\n /** The count of pairs with a difference above the margin. */\n readonly above: number;\n /** The one-sided p of the sign test of the claim \"the median difference is below the margin\". */\n readonly notSlower: number;\n /** The one-sided p of the sign test of the claim \"the median difference is above the margin\". */\n readonly slower: number;\n /** The median of the differences, or undefined when the job has not reached the look. */\n readonly centre: number | undefined;\n}\n\n/** The verdict of one case. */\nexport interface CaseGate extends GateCaseOutcome {\n readonly read: NotSlowerRead;\n readonly margin: number;\n /** The rounds of the look that decides the case, or undefined when the case has no outcome. */\n readonly look: number | undefined;\n /** The reads of each job, at the look that decides the case, or else at the last look that a job reached. */\n readonly jobs: readonly GateJobRead[];\n /** The reason of the outcome, in one sentence. */\n readonly reason: string;\n}\n\n/** The gate of the claim \"not slower by more than the margin\", with the facts that it uses. */\nexport interface NotSlowerVerdict extends Gate {\n readonly level: number;\n readonly looks: readonly number[];\n /** The count of jobs that each need the bound. */\n readonly need: number;\n readonly cases: readonly CaseGate[];\n /** The cases with no outcome that can have another look. The list is empty when the verdict is final. */\n readonly more: readonly BudgetMore[];\n}\n\n/** This function examines the options. */\nfunction checkOptions(level: number, looks: readonly number[], need: number): void {\n if (!(level > 0 && level < 1)) throw new RangeError(`notSlowerVerdict: the level is above 0 and below 1, not ${level}.`);\n if (looks.length === 0) throw new RangeError(\"notSlowerVerdict: the list of looks is empty.\");\n let last = 0;\n for (const rounds of looks) {\n if (!(Number.isInteger(rounds) && rounds > last && rounds % 2 === 0)) throw new RangeError(`notSlowerVerdict: the looks are even whole numbers in rising order, not ${rounds} after ${last}.`);\n last = rounds;\n }\n if (!(Number.isInteger(need) && need >= 1)) throw new RangeError(`notSlowerVerdict: the count of jobs is a whole number of 1 or more, not ${need}.`);\n}\n\n/** This function gives the records of one case of one job in the order of the rounds. It refuses a round that comes twice. */\nfunction casesOf(records: readonly PairedTime[]): Map<string, PairedTime[]> {\n const out = new Map<string, PairedTime[]>();\n for (const record of records) {\n checkPairedTime(record);\n const list = out.get(record.case) ?? [];\n if (list.some((r) => r.round === record.round)) throw new RangeError(`notSlowerVerdict: the round ${record.round} of ${JSON.stringify(record.case)} comes twice.`);\n list.push(record);\n out.set(record.case, list);\n }\n for (const list of out.values()) list.sort((a, b) => a.round - b.round);\n return out;\n}\n\n/**\n * This function gives the differences of the first `rounds` rounds: log(b / a) of the candidate minus log(b / a) of the A/A arm.\n * A pair has two records with the same first arm, because a difference of two orders holds the effect of the order.\n */\nfunction differences(candidate: readonly PairedTime[], aa: readonly PairedTime[], rounds: number): number[] {\n const out: number[] = [];\n const ofOrder = (list: readonly PairedTime[], first: Arm): PairedTime[] => list.slice(0, rounds).filter((r) => r.first === first);\n for (const first of [\"a\", \"b\"] as const) {\n const left = ofOrder(candidate, first);\n const right = ofOrder(aa, first);\n for (let i = 0; i < Math.min(left.length, right.length); i++) {\n const c = left[i] as PairedTime;\n const a = right[i] as PairedTime;\n out.push(Math.log(c.b / c.a) - Math.log(a.b / a.a));\n }\n }\n return out;\n}\n\n/** This function gives the read of one job. A job that has not reached the look gives a p of 1 in both directions. */\nfunction jobRead(job: string, diffs: readonly number[], margin: number, rounds: number): GateJobRead {\n if (diffs.length < rounds) return { job, rounds: diffs.length, below: 0, above: 0, notSlower: 1, slower: 1, centre: undefined };\n const below = diffs.filter((d) => d < margin).length;\n const above = diffs.filter((d) => d > margin).length;\n // A difference equal to the margin counts against each claim.\n return { job, rounds: diffs.length, below, above, notSlower: signTest(below, diffs.length - below), slower: signTest(above, diffs.length - above), centre: median(diffs) };\n}\n\n/** This function gives the words of the facts of one job, for a reason. */\nfunction jobFacts(read: GateJobRead): string {\n if (read.centre === undefined) return `job ${read.job} has ${read.rounds} pairs`;\n return `job ${read.job} has ${read.below} of ${read.rounds} pairs below the margin, centre ${Math.round(read.centre * 100_000) / 1000} %`;\n}\n\n/**\n * This function gives the gate of the claim \"the candidate is not slower than the A/A arm by more than the margin\" for each\n * case. A one-sided bound answers the claim. Thus a case with its whole interval under the margin reads \"not slower\", also\n * when its interval holds 1.\n *\n * - In each job, the sign test compares the median of the differences with the margin. It uses no random numbers.\n * - A case reads in `jobs` jobs or more: `partialConjunction` joins the p of each job, with no condition on how they depend.\n * - The level is for the family. Each look has `level / looks` of it, and `holm` corrects each look over all cases.\n * - The first look with an outcome decides a case. Later rounds do not change it. Each look uses the first rounds of a job.\n * - The result is \"block\" when a case reads \"slower\", and \"pass\" when each case reads \"not slower\".\n * - Each other result is \"no read\". The field `more` gives the next look of each case. After the last look, the caller adds jobs.\n *\n * The level needs independent rounds. Rounds with a shared cause, for example a slow computer for one job, do not have it.\n * A job that a caller adds after the last look is one more look, and the level does not count it.\n */\nexport function notSlowerVerdict(jobs: readonly JobRecords[], options: NotSlowerOptions): NotSlowerVerdict {\n const level = options.level ?? 0.05;\n const looks = options.looks ?? GATE_LOOKS;\n const need = options.jobs ?? 2;\n checkOptions(level, looks, need);\n const marginOf = (name: string): number => {\n const margin = typeof options.margin === \"number\" ? options.margin : options.margin(name);\n if (!(margin >= 0 && Number.isFinite(margin))) throw new RangeError(`notSlowerVerdict: the margin of ${JSON.stringify(name)} is finite and 0 or more, not ${margin}.`);\n return margin;\n };\n const records = jobs.map((job) => ({ job: job.job, candidate: casesOf(job.candidate), aa: casesOf(job.aa) }));\n const names = [...new Set(records.flatMap((job) => [...job.candidate.keys()]))].sort();\n const margins = names.map(marginOf);\n const decided = new Map<string, { outcome: LimitOutcome; look: number; reads: readonly GateJobRead[] }>();\n const reached = new Map<string, readonly GateJobRead[]>();\n const each = level / looks.length;\n for (const rounds of looks) {\n const reads = names.map((name, i) => records.map((job) => jobRead(job.job, differences(job.candidate.get(name) ?? [], job.aa.get(name) ?? [], rounds), margins[i] as number, rounds)));\n const joined = (pick: (read: GateJobRead) => number): number[] => reads.map((list) => (list.length < need ? 1 : partialConjunction(list.map(pick), need)));\n const within = holm(joined((read) => read.notSlower), each);\n const beyond = holm(joined((read) => read.slower), each);\n names.forEach((name, i) => {\n const list = reads[i] as GateJobRead[];\n if (!reached.has(name) || list.some((read) => read.rounds >= rounds)) reached.set(name, list);\n if (decided.has(name)) return;\n if (within[i]?.reject === true) decided.set(name, { outcome: \"within\", look: rounds, reads: list });\n else if (beyond[i]?.reject === true) decided.set(name, { outcome: \"beyond\", look: rounds, reads: list });\n });\n }\n const cases = names.map((name, i): CaseGate => {\n const decision = decided.get(name);\n const outcome = decision?.outcome ?? \"cannot decide\";\n const reads = decision?.reads ?? reached.get(name) ?? [];\n const facts = reads.map(jobFacts).join(\", \");\n const where = decision === undefined ? `no look of ${looks.join(\", \")} rounds decides it` : `the look of ${decision.look} rounds decides it`;\n return { case: name, outcome, read: READ_OF[outcome], margin: margins[i] as number, look: decision?.look, jobs: reads, reason: `The case ${JSON.stringify(name)} reads \"${READ_OF[outcome]}\": ${where} (${facts}).` };\n });\n const more = cases.flatMap((c): BudgetMore[] => {\n if (c.outcome !== \"cannot decide\") return [];\n const next = looks.find((rounds) => records.some((job) => differences(job.candidate.get(c.case) ?? [], job.aa.get(c.case) ?? [], rounds).length < rounds));\n return next === undefined ? [] : [{ case: c.case, rounds: next }];\n });\n return { ...gateOf(cases), level, looks, need, cases, more };\n}\n","/**\n * The load factor of a run, read from a control. Runs on shared machines differ by load. A change does not touch a control.\n * So the change of its time between two groups measures the machine and not the code.\n * The groups can be two runs, or the shards of one run.\n */\nimport { median, quantile } from \"@mark1russell7/rigor-statistics\";\n\n/** One time of the control in one group. */\nexport interface ControlRow {\n /** The name of the group: a run, or a shard of one run. */\n readonly group: string;\n /** The name of a class of work. The same key in two groups names equal work, so a ratio of the two measures the load. */\n readonly key: string;\n /** The time. It is finite and more than 0. */\n readonly value: number;\n /** This field is true when the run stopped the case at `value`. Thus the real time is at least `value`. */\n readonly censored?: boolean;\n}\n\n/** The options of `controlFactor`. */\nexport interface ControlOptions {\n /** The group that the factors compare with. Without it, the base of each key is the median of that key over the groups. */\n readonly base?: string;\n /** The least number of keys in a factor. A group with fewer keys has no factor. The default is 5. */\n readonly minPairs?: number;\n}\n\n/** The counts of one group, with or without a factor. */\nexport interface GroupCounts {\n readonly group: string;\n /** The number of keys that the factor reads. */\n readonly pairs: number;\n /** The number of keys that this function left out because a time of the key was censored. The factor reads low when this count is not 0. */\n readonly censored: number;\n /** The number of keys of this group that have no time to compare with, so no ratio reads them. */\n readonly unshared: number;\n}\n\n/** The factor of one group. */\nexport interface MeasuredFactor extends GroupCounts {\n /** The median ratio of the times of this group over the base. A factor of 1.6 means that this group took 1.6 times as long. */\n readonly factor: number;\n /** The quartiles of the ratios. A wide spread means that one factor does not explain the load. */\n readonly low: number;\n readonly high: number;\n}\n\n/** A group with too few usable keys. It has no factor, and the other groups keep theirs. */\nexport interface NoFactor extends GroupCounts {\n readonly factor: undefined;\n /** The reason that this group has no factor. */\n readonly reason: string;\n}\n\n/** The result of one group. Read `factor` first: a group with too few usable keys has no factor. */\nexport type GroupFactor = MeasuredFactor | NoFactor;\n\n/** The factors of a run, with the base that they use. */\nexport interface ControlFactors {\n /** The base group, or undefined when the base of each key is its median over the groups. */\n readonly base: string | undefined;\n readonly factors: readonly GroupFactor[];\n}\n\nconst DEFAULT_MIN_PAIRS = 5;\n\nfunction checkedRows(rows: readonly ControlRow[]): Map<string, Map<string, ControlRow>> {\n const groups = new Map<string, Map<string, ControlRow>>();\n for (const r of rows) {\n if (!(Number.isFinite(r.value) && r.value > 0)) throw new RangeError(`controlFactor: the value of ${JSON.stringify(r.key)} in ${JSON.stringify(r.group)} is finite and more than 0, not ${r.value}.`);\n const group = groups.get(r.group) ?? new Map<string, ControlRow>();\n if (group.has(r.key)) throw new RangeError(`controlFactor: the key ${JSON.stringify(r.key)} comes twice in ${JSON.stringify(r.group)}.`);\n group.set(r.key, r);\n groups.set(r.group, group);\n }\n return groups;\n}\n\nfunction factorOf(group: string, ratios: readonly number[], censored: number, unshared: number, minPairs: number): GroupFactor {\n const counts = { group, pairs: ratios.length, censored, unshared };\n if (ratios.length < minPairs) return { ...counts, factor: undefined, reason: `the group ${JSON.stringify(group)} has ${ratios.length} usable keys, and the least is ${minPairs}.` };\n return { ...counts, factor: median(ratios), low: quantile(ratios, 0.25), high: quantile(ratios, 0.75) };\n}\n\n/** This function refuses a result with no factor at all, because such a result measures nothing. */\nfunction withFactors(base: string | undefined, factors: readonly GroupFactor[]): ControlFactors {\n if (factors.every((f) => f.factor === undefined)) {\n const thin = factors.find((f): f is NoFactor => f.factor === undefined);\n throw new RangeError(`controlFactor: no group has a factor: ${thin?.reason ?? \"the rows hold no group to compare.\"}`);\n }\n return { base, factors };\n}\n\n/** This function gives the factors over one base group. Each factor reads the keys that the two groups share. */\nfunction againstGroup(groups: Map<string, Map<string, ControlRow>>, base: string, minPairs: number): ControlFactors {\n const baseRows = groups.get(base);\n if (baseRows === undefined) throw new RangeError(`controlFactor: the base ${JSON.stringify(base)} is not a group of the rows.`);\n const factors: GroupFactor[] = [];\n for (const [group, rows] of groups) {\n if (group === base) continue;\n const ratios: number[] = [];\n let censored = 0;\n let unshared = 0;\n for (const [key, r] of rows) {\n const b = baseRows.get(key);\n if (b === undefined) unshared += 1;\n else if (r.censored === true || b.censored === true) censored += 1;\n else ratios.push(r.value / b.value);\n }\n factors.push(factorOf(group, ratios, censored, unshared, minPairs));\n }\n return withFactors(base, factors);\n}\n\n/**\n * This function gives the factors over the median of each key, as one run grouped by shard needs.\n * Each group holds a different mix of work, so a time compares only with the times of the same key. A key in one group has nothing to compare with.\n */\nfunction againstKeys(groups: Map<string, Map<string, ControlRow>>, minPairs: number): ControlFactors {\n const clean = new Map<string, number[]>();\n for (const rows of groups.values()) {\n for (const [key, r] of rows) if (r.censored !== true) clean.set(key, [...(clean.get(key) ?? []), r.value]);\n }\n const factors = [...groups].map(([group, rows]) => {\n const ratios: number[] = [];\n let censored = 0;\n let unshared = 0;\n for (const [key, r] of rows) {\n const times = clean.get(key) ?? [];\n if (r.censored === true) censored += 1;\n else if (times.length >= 2) ratios.push(r.value / median(times));\n else unshared += 1;\n }\n return factorOf(group, ratios, censored, unshared, minPairs);\n });\n return withFactors(undefined, factors);\n}\n\n/**\n * This function gives the load factor of each group from the times of a control.\n *\n * With `base`, a factor compares the keys that a group shares with that group. Without it, a factor compares each time with the median of its key over the groups.\n * A key names a class of work, so equal keys in two groups mean equal work. Each group has at most one row for a key.\n *\n * A censored time is only a lower limit, so no ratio reads it, and the result counts those keys. A run stops its slowest cases, so a factor reads low when `censored` is not 0.\n *\n * A group with too few usable keys gets an entry with no factor and its reason, so the other groups keep their factors. This function refuses a result where no group has a factor.\n */\nexport function controlFactor(rows: readonly ControlRow[], options: ControlOptions = {}): ControlFactors {\n const minPairs = options.minPairs ?? DEFAULT_MIN_PAIRS;\n if (!(Number.isInteger(minPairs) && minPairs >= 1)) throw new RangeError(`controlFactor: minPairs is a whole number of 1 or more, not ${minPairs}.`);\n const groups = checkedRows(rows);\n return options.base === undefined ? againstKeys(groups, minPairs) : againstGroup(groups, options.base, minPairs);\n}\n","/**\n * The scale ladder of a product, as data. A ladder has rungs at sizes that grow, for example 1, 10 and 100 tenants. Each\n * rung has budgets, and it names the test that holds it. A rung is held only when a record of that test shows each budget\n * `within`. A number in a document is not a rung.\n */\nimport { quantile, quantileInterval, quantileSamples, wilson } from \"@mark1russell7/rigor-statistics\";\nimport { type BudgetOutcome, type BudgetRound, budgetVerdict } from \"./budget.ts\";\n\n/** The format name of a ladder. It changes when a reader of an older form cannot read the data. */\nexport const LADDER_FORMAT = \"rigor-ladder/1\";\n\n/** One dimension of a ladder, for example tenants or nodes. */\nexport interface LadderDimension {\n readonly name: string;\n /** What one unit of the dimension is, in plain words. */\n readonly describe: string;\n}\n\n/** A budget on the median of each case, for example the time of a read. A record gives rounds and an A/A arm. */\nexport interface MedianBudget {\n readonly kind: \"median\";\n readonly measure: string;\n /** The unit of the limit and of the values. */\n readonly unit: string;\n /** The largest median that the budget permits. */\n readonly limit: number;\n /** The largest difference between the medians of the two arms. A larger difference makes the run too noisy. */\n readonly maxDifference: number;\n /** The level of the interval of each median. The default is 0.95. */\n readonly caseLevel?: number;\n}\n\n/** A budget on the share of failed trials, for example failed requests. A record gives failures and trials. */\nexport interface RateBudget {\n readonly kind: \"rate\";\n readonly measure: string;\n /** The largest share of failures that the budget permits, from 0 to 1. */\n readonly limit: number;\n}\n\n/** A budget on the largest value of a set of drills, for example the writes that a restore lost. One bad drill is `beyond`. */\nexport interface WorstBudget {\n readonly kind: \"worst\";\n readonly measure: string;\n readonly unit: string;\n /** The largest value that the budget permits in any drill. */\n readonly limit: number;\n /** The number of drills that a verdict needs, 1 or more. With fewer, the budget is `cannot decide`. */\n readonly minDrills: number;\n}\n\n/**\n * A budget on a high quantile, for example the p99 of a read. A record gives the values. The verdict is the distribution-free\n * interval of the quantile against the limit. A p99 needs 368 independent values at the level 0.95: refer to `quantileSamples`.\n * Successive times of one run can follow each other. Space them apart, or give one value for each run.\n *\n * The evidence can also hold `censored`: a lower bound for each arrival with no reply, and for each arrival that was not\n * sent. The bound is the time that the arrival waited. The true value is that bound or more, with no upper limit. Thus the\n * low end of the interval reads the bounds, and the high end reads each censored value as `Infinity`. A `beyond` stays\n * provable from the bounds alone. A `within` needs real replies up to the upper rank of the interval.\n */\nexport interface QuantileBudget {\n readonly kind: \"quantile\";\n readonly measure: string;\n /** The unit of the limit and of the values. */\n readonly unit: string;\n /** The quantile, more than 0 and less than 1, for example 0.99. */\n readonly quantile: number;\n /** The largest quantile that the budget permits. */\n readonly limit: number;\n /** The level of the interval. The default is 0.95. */\n readonly level?: number;\n}\n\n/** One budget of a rung. */\nexport type RungBudget = MedianBudget | QuantileBudget | RateBudget | WorstBudget;\n\n/** One rung of a ladder. */\nexport interface Rung {\n /** The name of the rung, unique in the ladder. */\n readonly name: string;\n /** The size of the rung in each dimension that it names. */\n readonly at: Readonly<Record<string, number>>;\n readonly budgets: readonly RungBudget[];\n /** The name of the automatic test that holds the rung. */\n readonly test: string;\n /** True when a gate holds the rung: the verdict fails when the rung is not `within`. */\n readonly locked?: boolean;\n}\n\n/** The ladder of one subject. The rungs go from the smallest to the largest. */\nexport interface Ladder {\n readonly format: typeof LADDER_FORMAT;\n /** The product or the service that the ladder is for. */\n readonly subject: string;\n readonly dimensions: readonly LadderDimension[];\n readonly rungs: readonly Rung[];\n}\n\n/** The measured evidence for one budget. Its `kind` is the kind of the budget. */\nexport type RungEvidence =\n | { readonly kind: \"median\"; readonly measure: string; readonly rounds: readonly BudgetRound[]; readonly aa: readonly BudgetRound[] }\n | { readonly kind: \"quantile\"; readonly measure: string; readonly values: readonly number[]; readonly censored?: readonly number[] }\n | { readonly kind: \"rate\"; readonly measure: string; readonly failures: number; readonly trials: number }\n | { readonly kind: \"worst\"; readonly measure: string; readonly values: readonly number[] };\n\n/** One run of the test of a rung. */\nexport interface RungRecord {\n /** The name of the rung. */\n readonly rung: string;\n /** The commit that the run measured. */\n readonly commit: string;\n /** The time of the run, as an ISO 8601 string. */\n readonly at: string;\n /** What the run did for real, for example \"2 processes\" or \"a restore from a real backup\". */\n readonly real: readonly string[];\n /** What the run made up, for example \"90 % of the tenants as data at rest\". An empty list states that nothing was synthetic. */\n readonly synthetic: readonly string[];\n readonly evidence: readonly RungEvidence[];\n}\n\n/** The verdict of one budget of a rung. */\nexport interface BudgetResult {\n readonly measure: string;\n readonly outcome: BudgetOutcome;\n /** The reason of the outcome, in one sentence, with the numbers. */\n readonly reason: string;\n}\n\n/** The verdict of one rung. */\nexport interface RungVerdict {\n readonly rung: string;\n readonly test: string;\n readonly locked: boolean;\n readonly outcome: BudgetOutcome;\n /** The reason of the outcome, in one sentence. */\n readonly reason: string;\n readonly budgets: readonly BudgetResult[];\n /** The commit of the record, or undefined when the rung has no record. */\n readonly commit: string | undefined;\n readonly real: readonly string[];\n readonly synthetic: readonly string[];\n}\n\n/** The verdict of a ladder. */\nexport interface LadderVerdict {\n readonly subject: string;\n /** The highest rung with each rung up to it `within`, or undefined when the first rung is not `within`. */\n readonly held: string | undefined;\n /** The first rung that is not `within`, or undefined when each rung is `within`. */\n readonly next: string | undefined;\n /** True when a locked rung is not `within`. A rung with no result is not held, so `cannot decide` fails too. */\n readonly failed: boolean;\n /** The reason of `failed`, in one sentence. */\n readonly reason: string;\n readonly rungs: readonly RungVerdict[];\n}\n\n/** The options of a ladder verdict. */\nexport interface LadderOptions {\n /** The time of the verdict, as an ISO 8601 string. It is an input, so that a verdict is the same at each read. */\n readonly now: string;\n /** The largest age of a record, in days. An older record gives `cannot decide`. The default accepts any age. */\n readonly maxAgeDays?: number;\n}\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\n/** This function gives the problems of one budget. */\nfunction budgetProblems(where: string, budget: RungBudget): string[] {\n const out: string[] = [];\n const name = `${where}, budget ${JSON.stringify(budget.measure)}`;\n if (budget.measure.trim() === \"\") out.push(`${where}: a budget has no measure.`);\n if (!(Number.isFinite(budget.limit) && budget.limit >= 0)) out.push(`${name}: the limit is finite and 0 or more, not ${budget.limit}.`);\n if (budget.kind === \"rate\" && budget.limit > 1) out.push(`${name}: a rate limit is at most 1, not ${budget.limit}.`);\n if (budget.kind === \"median\" && !(Number.isFinite(budget.maxDifference) && budget.maxDifference >= 0)) {\n out.push(`${name}: the largest difference is finite and 0 or more, not ${budget.maxDifference}.`);\n }\n if (budget.kind === \"worst\" && !(Number.isInteger(budget.minDrills) && budget.minDrills >= 1)) {\n out.push(`${name}: the number of drills is a whole number of 1 or more, not ${budget.minDrills}.`);\n }\n if (budget.kind === \"quantile\" && !(budget.quantile > 0 && budget.quantile < 1)) out.push(`${name}: a quantile is more than 0 and less than 1, not ${budget.quantile}.`);\n if (budget.kind === \"quantile\" && budget.level !== undefined && !(budget.level > 0 && budget.level < 1)) out.push(`${name}: a level is more than 0 and less than 1, not ${budget.level}.`);\n return out;\n}\n\n/** This function gives the problems of one rung, in the order of its fields. */\nfunction rungProblems(rung: Rung, dimensions: ReadonlySet<string>): string[] {\n const where = `The rung ${JSON.stringify(rung.name)}`;\n const out: string[] = [];\n const names = Object.keys(rung.at);\n if (names.length === 0) out.push(`${where} names no dimension.`);\n for (const name of names) {\n if (!dimensions.has(name)) out.push(`${where} names the unknown dimension ${JSON.stringify(name)}.`);\n const size = rung.at[name];\n if (!(typeof size === \"number\" && Number.isFinite(size) && size > 0)) out.push(`${where}: the size of ${JSON.stringify(name)} is finite and above 0, not ${size}.`);\n }\n if (rung.test.trim() === \"\") out.push(`${where} names no test.`);\n if (rung.budgets.length === 0) out.push(`${where} has no budgets.`);\n const measures = new Set<string>();\n for (const budget of rung.budgets) {\n if (measures.has(budget.measure)) out.push(`${where} has two budgets of ${JSON.stringify(budget.measure)}.`);\n measures.add(budget.measure);\n out.push(...budgetProblems(where, budget));\n }\n return out;\n}\n\n/**\n * This function gives each problem of a ladder as data, or an empty list. A ladder needs a subject, one dimension or more,\n * and one rung or more. Names are unique. Each rung names a test and has budgets. From one rung to the next, each dimension\n * that the two rungs name grows.\n */\nexport function checkLadder(ladder: Ladder): readonly string[] {\n const out: string[] = [];\n if (ladder.format !== LADDER_FORMAT) out.push(`The format is ${JSON.stringify(LADDER_FORMAT)}, not ${JSON.stringify(ladder.format)}.`);\n if (ladder.subject.trim() === \"\") out.push(\"The ladder has no subject.\");\n if (ladder.dimensions.length === 0) out.push(\"The ladder has no dimensions.\");\n if (ladder.rungs.length === 0) out.push(\"The ladder has no rungs.\");\n const dimensions = new Set(ladder.dimensions.map((d) => d.name));\n if (dimensions.size !== ladder.dimensions.length) out.push(\"Two dimensions have the same name.\");\n if (new Set(ladder.rungs.map((r) => r.name)).size !== ladder.rungs.length) out.push(\"Two rungs have the same name.\");\n ladder.rungs.forEach((rung, index) => {\n out.push(...rungProblems(rung, dimensions));\n const before = ladder.rungs[index - 1];\n if (before === undefined) return;\n for (const [name, size] of Object.entries(rung.at)) {\n const low = before.at[name];\n if (low !== undefined && !(size > low)) out.push(`The rung ${JSON.stringify(rung.name)}: ${JSON.stringify(name)} does not grow from ${low} to ${size}.`);\n }\n });\n return out;\n}\n\n/** This function gives the verdict of a rate: the Wilson interval at 95 % against the limit. */\nfunction rateResult(budget: RateBudget, failures: number, trials: number): BudgetResult {\n const interval = wilson(failures, trials);\n const facts = `${failures} failures of ${trials} trials, interval ${interval.low} to ${interval.high}, limit ${budget.limit}`;\n const outcome: BudgetOutcome = trials === 0 ? \"cannot decide\" : interval.high <= budget.limit ? \"within\" : interval.low > budget.limit ? \"beyond\" : \"cannot decide\";\n return { measure: budget.measure, outcome, reason: `The measure ${JSON.stringify(budget.measure)} is \"${outcome}\" (${facts}).` };\n}\n\n/** This function gives the verdict of a set of drills: the largest value against the limit. */\nfunction worstResult(budget: WorstBudget, values: readonly number[]): BudgetResult {\n const largest = values.length === 0 ? undefined : Math.max(...values);\n const facts = `${values.length} drills, the largest ${largest ?? \"none\"} ${budget.unit}, limit ${budget.limit}`;\n const outcome: BudgetOutcome = largest !== undefined && largest > budget.limit ? \"beyond\" : values.length < budget.minDrills ? \"cannot decide\" : \"within\";\n return { measure: budget.measure, outcome, reason: `The measure ${JSON.stringify(budget.measure)} is \"${outcome}\" (${facts}, ${budget.minDrills} drills needed).` };\n}\n\n/**\n * This function gives the verdict of a quantile: its distribution-free interval against the limit. With censored values, the\n * low end reads their bounds and the high end reads them as `Infinity`. Each true sample has its interval inside that one.\n */\nfunction quantileResult(budget: QuantileBudget, values: readonly number[], censored: readonly number[]): BudgetResult {\n const level = budget.level ?? 0.95;\n const needed = quantileSamples(budget.quantile, level);\n const say = (outcome: BudgetOutcome, facts: string): BudgetResult => ({ measure: budget.measure, outcome, reason: `The measure ${JSON.stringify(budget.measure)} is \"${outcome}\" (${facts}, ${needed} values needed).` });\n const open = censored.length > 0;\n const bounds = [...values, ...censored];\n if (bounds.length === 0) return say(\"cannot decide\", `0 values, limit ${budget.limit} ${budget.unit}`);\n if (values.some((value) => Number.isNaN(value))) return say(\"cannot decide\", \"the values have a NaN\");\n if (!censored.every((value) => Number.isFinite(value))) return say(\"cannot decide\", \"a censored value is not a finite number\");\n const lowest = quantileInterval(bounds, budget.quantile, level);\n const highest = open ? quantileInterval([...values, ...censored.map(() => Infinity)], budget.quantile, level) : lowest;\n const [count, point] = open ? [`${values.length} values and ${censored.length} censored`, \"at least\"] : [`${values.length} values`, \"at\"];\n const facts = `${count}, quantile ${budget.quantile} ${point} ${quantile(bounds, budget.quantile, \"nearest-rank\")} ${budget.unit}, interval ${lowest.low} to ${highest.high}, limit ${budget.limit}`;\n return say(highest.high <= budget.limit ? \"within\" : lowest.low > budget.limit ? \"beyond\" : \"cannot decide\", facts);\n}\n\n/** This function gives the verdict of one budget from the evidence of a record. */\nfunction budgetResult(budget: RungBudget, evidence: readonly RungEvidence[]): BudgetResult {\n const found = evidence.find((e) => e.measure === budget.measure);\n const none = (why: string): BudgetResult => ({ measure: budget.measure, outcome: \"cannot decide\", reason: `The measure ${JSON.stringify(budget.measure)} is \"cannot decide\": ${why}.` });\n if (found === undefined) return none(\"the record has no evidence for it\");\n if (budget.kind === \"median\" && found.kind === \"median\") {\n const v = budgetVerdict(found.rounds, found.aa, { limit: budget.limit, maxDifference: budget.maxDifference, ...(budget.caseLevel === undefined ? {} : { caseLevel: budget.caseLevel }) });\n return { measure: budget.measure, outcome: v.outcome, reason: v.reason };\n }\n if (budget.kind === \"quantile\" && found.kind === \"quantile\") return quantileResult(budget, found.values, found.censored ?? []);\n if (budget.kind === \"rate\" && found.kind === \"rate\") return rateResult(budget, found.failures, found.trials);\n if (budget.kind === \"worst\" && found.kind === \"worst\") return worstResult(budget, found.values);\n return none(`the budget is ${budget.kind}, and the evidence is ${found.kind}`);\n}\n\n/** This function gives the reason that a record cannot decide a rung, or undefined when the record can. */\nfunction recordProblem(record: RungRecord, options: LadderOptions): string | undefined {\n if (record.real.length === 0) return \"the record does not state what was real\";\n const { maxAgeDays } = options;\n if (maxAgeDays === undefined) return undefined;\n const age = (Date.parse(options.now) - Date.parse(record.at)) / DAY_MS;\n if (!Number.isFinite(age)) return `a time does not parse: now ${options.now}, record ${record.at}`;\n return age > maxAgeDays ? `the record of ${record.at} is older than ${maxAgeDays} days` : undefined;\n}\n\n/** This function gives the outcome of a set of budgets: `beyond` first, then `cannot decide`, and `within` only when each budget is. */\nfunction worstOutcome(results: readonly BudgetResult[]): BudgetOutcome {\n if (results.some((r) => r.outcome === \"beyond\")) return \"beyond\";\n return results.length > 0 && results.every((r) => r.outcome === \"within\") ? \"within\" : \"cannot decide\";\n}\n\n/** This function gives the verdict of one rung from its record. With no record, the rung is `cannot decide`. */\nexport function rungVerdict(rung: Rung, record: RungRecord | undefined, options: LadderOptions): RungVerdict {\n const base = { rung: rung.name, test: rung.test, locked: rung.locked === true };\n if (record === undefined) {\n return { ...base, outcome: \"cannot decide\", reason: `The rung ${JSON.stringify(rung.name)} has no record of the test ${JSON.stringify(rung.test)}.`, budgets: [], commit: undefined, real: [], synthetic: [] };\n }\n const facts = { commit: record.commit, real: record.real, synthetic: record.synthetic };\n const problem = recordProblem(record, options);\n if (problem !== undefined) return { ...base, ...facts, outcome: \"cannot decide\", reason: `The rung ${JSON.stringify(rung.name)} is \"cannot decide\": ${problem}.`, budgets: [] };\n const budgets = rung.budgets.map((b) => budgetResult(b, record.evidence));\n const outcome = worstOutcome(budgets);\n const first = budgets.find((b) => b.outcome === outcome);\n return { ...base, ...facts, outcome, reason: outcome === \"within\" ? `The ${budgets.length} budgets of the rung ${JSON.stringify(rung.name)} are within.` : `The rung ${JSON.stringify(rung.name)} is \"${outcome}\". ${first?.reason ?? \"\"}`, budgets };\n}\n\n/** This function gives the newest record of each rung. It keeps the first of two records with the same time. */\nfunction newestRecords(records: readonly RungRecord[]): Map<string, RungRecord> {\n const out = new Map<string, RungRecord>();\n for (const record of records) {\n const old = out.get(record.rung);\n if (old === undefined || Date.parse(record.at) > Date.parse(old.at)) out.set(record.rung, record);\n }\n return out;\n}\n\n/**\n * This function gives the verdict of a ladder from the records of its rungs. It uses the newest record of each rung, so an\n * older pass does not hide a newer failure. A rung high up does not count when a rung below it is not `within`. It throws\n * a `RangeError` for a ladder with problems, because a verdict on a bad ladder has no meaning. See `checkLadder`.\n */\nexport function ladderVerdict(ladder: Ladder, records: readonly RungRecord[], options: LadderOptions): LadderVerdict {\n const problems = checkLadder(ladder);\n if (problems.length > 0) throw new RangeError(`ladderVerdict: ${problems.join(\" \")}`);\n const newest = newestRecords(records);\n const rungs = ladder.rungs.map((r) => rungVerdict(r, newest.get(r.name), options));\n const firstOpen = rungs.findIndex((r) => r.outcome !== \"within\");\n const heldCount = firstOpen === -1 ? rungs.length : firstOpen;\n const lost = rungs.filter((r) => r.locked && r.outcome !== \"within\");\n const reason = lost.length === 0 ? `Each of the ${rungs.filter((r) => r.locked).length} locked rungs is within.` : `${lost.length} locked rungs are not within. ${lost[0]?.reason ?? \"\"}`;\n return { subject: ladder.subject, held: rungs[heldCount - 1]?.rung, next: rungs[heldCount]?.rung, failed: lost.length > 0, reason, rungs };\n}\n","/**\n * The time verdict of a candidate against a baseline, with the noise of an A/A arm. An A/A pair runs the same code in\n * its two arms. Its ratios show how far apart two equal arms come on this machine. A candidate is faster or slower only\n * when its interval is out of that band.\n */\nimport { type BootstrapOptions, type Comparison, type Interval, bootstrapMedian, bootstrapTwo, compareRatios, median, quantile } from \"@mark1russell7/rigor-statistics\";\nimport { type CaseRatio, type PairedTime, caseRatios } from \"./paired.ts\";\n\n/**\n * The two kinds of an A/A band.\n * - The band `case` holds the ratio of one A/A case. It is wide, so it finds only a large change.\n * - The band `median` holds the median ratio of the A/A cases. It has the scale of the median of the candidate.\n */\nexport type BandKind = \"case\" | \"median\";\n\n/** The options of the A/A band. */\nexport interface BandOptions {\n /** The kind of the band. The default is `median`, from the power test of `verdictPower`. */\n readonly kind?: BandKind;\n /** The quantile of the band `case`, or the level of the bootstrap of the band `median`. The default is 0.95. */\n readonly level?: number;\n /** The fewest A/A cases that give a band. The default is 5, the 5-seed rule. */\n readonly minimum?: number;\n /** The bootstrap of the band `median`. The level of the band replaces its level. */\n readonly bootstrap?: BootstrapOptions;\n}\n\n/** The band of the A/A arm: two equal arms come out in this band of ratios. */\nexport interface Band {\n /** The count of the A/A cases. */\n readonly cases: number;\n readonly kind: BandKind;\n /**\n * The half width of the band on a log scale.\n * For the band `case`, it is the `level` quantile of `abs(log(ratio))` over the A/A cases.\n * For the band `median`, it is the larger distance of an end of the bootstrap interval of the A/A median from 0.\n */\n readonly noise: number;\n /** The ends of the band: `exp(-noise)` and `exp(noise)`. */\n readonly low: number;\n readonly high: number;\n /** The median ratio of the A/A cases. A value far from 1 shows a bias of the order or of the arm slots. */\n readonly median: number;\n}\n\n/** This function gives the band of the A/A arm. The band is symmetric on a log scale. It refuses fewer cases than `minimum`. */\nexport function aaBand(aa: readonly PairedTime[], options: BandOptions = {}): Band {\n const ratios = caseRatios(aa);\n const minimum = options.minimum ?? 5;\n if (ratios.length < minimum) throw new RangeError(`aaBand: the A/A arm has ${ratios.length} cases, and a band needs ${minimum} or more.`);\n const logs = ratios.map((r) => Math.log(r.ratio));\n const kind = options.kind ?? \"median\";\n const level = options.level ?? 0.95;\n let noise: number;\n if (kind === \"case\") noise = quantile(logs.map(Math.abs), level);\n else {\n const interval = bootstrapMedian(logs, { ...options.bootstrap, level });\n noise = Math.max(Math.abs(interval.low), Math.abs(interval.high));\n }\n return { cases: ratios.length, kind, noise, low: Math.exp(-noise), high: Math.exp(noise), median: Math.exp(quantile(logs, 0.5)) };\n}\n\n/**\n * This function gives the A/A spread: the `level` quantile of `abs(log(ratio))` over the A/A cases. The default level is 0.9.\n * It refuses an A/A arm with no cases.\n */\nexport function aaSpread(aa: readonly PairedTime[], level = 0.9): number {\n const ratios = caseRatios(aa);\n if (ratios.length === 0) throw new RangeError(\"aaSpread: the A/A arm has no cases.\");\n return spreadOf(ratios, level);\n}\n\nfunction spreadOf(ratios: readonly CaseRatio[], level: number): number {\n return quantile(ratios.map((r) => Math.abs(Math.log(r.ratio))), level);\n}\n\n/** The options of a pooled band: the A/A records of earlier quiet runs, and a floor. The caller keeps the pool. */\nexport interface PoolOptions {\n /** The A/A records of the earlier runs. Give each run its own case names, for example with the run id as a prefix. */\n readonly records: readonly PairedTime[];\n /** The smallest noise of the band, on a log scale. The default is 0. A floor of `Math.log(1.05)` gives at least the band `[1 / 1.05, 1.05]`. */\n readonly floor?: number;\n /** The fewest pooled cases that give a spread. With fewer cases, the noise of the band is the floor. The default is 5. */\n readonly minimum?: number;\n /**\n * The run of a record, for example the id of its CI run. The verdict counts the runs of the pool with it.\n * The cases of one run share one runner, so they are not independent. Many cases from few runs show the noise of few runners.\n */\n readonly run?: (record: PairedTime) => string;\n}\n\n/** The facts of the pooled band of a verdict. */\nexport interface PoolFacts {\n /** The count of the pooled A/A cases. */\n readonly cases: number;\n /** The count of the runs of the pool, from the option `run`. It is undefined without that option. */\n readonly runs: number | undefined;\n /** The A/A spread of the pooled cases, or undefined when the pool has fewer cases than `minimum`. */\n readonly spread: number | undefined;\n readonly floor: number;\n /** This value is `true` when the spread of the pool is larger than the floor, so the spread gives the noise of the band. */\n readonly pooled: boolean;\n}\n\n/**\n * This function gives the pooled band of the kind `case`. Its noise is the larger of the floor and the A/A spread of the pooled records.\n * The spread is the `level` quantile of `abs(log(ratio))`, with the default level 0.9.\n *\n * A band with fewer pooled cases than `minimum` uses the floor alone. A band with no pooled cases has the median 1.\n */\nexport function pooledBand(pool: PoolOptions, level = 0.9): Band {\n return poolOf(pool, level).band;\n}\n\nfunction poolOf(pool: PoolOptions, level: number): { band: Band; facts: PoolFacts } {\n const floor = pool.floor ?? 0;\n const minimum = pool.minimum ?? 5;\n if (!(floor >= 0 && Number.isFinite(floor))) throw new RangeError(`pooledBand: the floor is a finite number of 0 or more, not ${floor}.`);\n if (!Number.isSafeInteger(minimum) || minimum < 1) throw new RangeError(`pooledBand: the minimum is a whole number of 1 or more, not ${minimum}.`);\n const ratios = caseRatios(pool.records);\n const spread = ratios.length >= minimum ? spreadOf(ratios, level) : undefined;\n const noise = Math.max(floor, spread ?? 0);\n const median = ratios.length === 0 ? 1 : Math.exp(quantile(ratios.map((r) => Math.log(r.ratio)), 0.5));\n const band: Band = { cases: ratios.length, kind: \"case\", noise, low: Math.exp(-noise), high: Math.exp(noise), median };\n const runs = pool.run === undefined ? undefined : new Set(pool.records.map(pool.run)).size;\n return { band, facts: { cases: ratios.length, runs, spread, floor, pooled: spread !== undefined && spread > floor } };\n}\n\n/** The four outcomes of a time verdict. The candidate is the arm `b`, so `faster` is a ratio below 1. */\nexport type TimeOutcome = \"faster\" | \"slower\" | \"same\" | \"cannot decide\";\n\n/** The options of a time verdict. The bootstrap gives the interval of the median ratio of the candidate, and the band `median`. */\n/**\n * The two rules of a time verdict.\n * - The rule `band` compares the interval of the median ratio of the candidate with the A/A band.\n * - The rule `difference` compares the interval of the candidate median over the A/A median with 1 and with `margin`.\n */\nexport type VerdictRule = \"band\" | \"difference\";\n\n/** The options of a time verdict. The bootstrap gives each interval of the verdict. */\nexport interface VerdictOptions extends BandOptions {\n /** The rule of the verdict. The default is `difference`, from the power test of `verdictPower`. */\n readonly rule?: VerdictRule;\n /**\n * The half width on a log scale of the ratios that the rule `difference` calls `same`. The default is 0.05.\n * An interval in the margin is `same`, also when it is wholly below 1.\n */\n readonly margin?: number;\n /**\n * The noise cap on the A/A spread of the run, on a log scale. Above the cap, the outcome is `cannot decide`.\n * The cap also limits the bias of the A/A arm: an A/A median ratio out of `[exp(-noiseCap), exp(noiseCap)]` gives `cannot decide`.\n * The default is no cap.\n */\n readonly noiseCap?: number;\n /** The quantile of the A/A spread of the noise cap and of the pooled band. The default is 0.9. */\n readonly spreadLevel?: number;\n /**\n * The pooled band. It replaces the band of the A/A arm of the run in the rule `band` and in `comparison`.\n * The rule `difference` uses the larger of `margin` and the noise of the pooled band as its margin. The default is no pool.\n */\n readonly pool?: PoolOptions;\n}\n\n/** The noise cap of a verdict: the A/A spread of the run, the A/A median ratio of the run and the cap. */\nexport interface NoiseCheck {\n /** The A/A spread of the run, or undefined when the A/A arm has no cases. */\n readonly spread: number | undefined;\n readonly cap: number;\n /** This value is `true` when the spread is above the cap, or when the A/A arm has no cases. */\n readonly noisy: boolean;\n /** The median ratio of the A/A cases of the run, or undefined when the A/A arm has no cases. A value far from 1 shows a bias of the order or of the arm slots. */\n readonly aaMedian: number | undefined;\n /**\n * This value is `true` when the A/A median ratio of the run is out of `[exp(-cap), exp(cap)]`.\n * With a spread level of 0.5 or more, a biased run is also noisy. The check decides alone only below that level.\n */\n readonly biased: boolean;\n}\n\n/** A time verdict, with the facts that it uses. */\nexport interface TimeVerdict {\n readonly outcome: TimeOutcome;\n /** The reason of the outcome, in one sentence. */\n readonly reason: string;\n readonly cases: readonly CaseRatio[];\n readonly rule: VerdictRule;\n /**\n * The interval that the rule compares, or undefined when there are no candidate cases.\n * With too few A/A cases, it is the interval of the median ratio of the candidate.\n * For the rule `band`, it is the bootstrap interval of the median ratio of the candidate.\n * For the rule `difference`, it is the interval of the candidate median ratio over the A/A median ratio.\n */\n readonly interval: Interval | undefined;\n /** The band of the A/A arm, or undefined when the A/A arm has too few cases. */\n readonly band: Band | undefined;\n /**\n * The counts of the cases out of the band, or undefined without a band.\n * The comparison uses the value `1 + log(ratio)` of each case and the noise of the band, so its two sides are the ends of the band.\n */\n readonly comparison: Comparison | undefined;\n /** The facts of the pooled band. The verdict has this field only with the option `pool`. */\n readonly pool?: PoolFacts;\n /** The noise cap. The verdict has this field only with the option `noiseCap`. */\n readonly noise?: NoiseCheck;\n}\n\n/**\n * This function gives the time verdict of the candidate arm `b` against the baseline arm `a`.\n * - The rule `difference` gives `same` when the interval is in `[exp(-margin), exp(margin)]`. This test comes first, so\n * an interval in the margin and below 1 is `same`, not `faster`.\n * - Out of the margin, the rule `difference` gives `faster` when the whole interval is below 1, and `slower` when it is above 1.\n * With the margin 0, each outcome stays the same as in 0.1.2.\n * - The rule `band` gives `faster` below the band, `slower` above the band, and `same` in the band.\n * - Each other case is `cannot decide`, and so is an A/A arm with too few cases.\n * - With `noiseCap`, an A/A spread of the run above the cap gives `cannot decide`.\n * - With `noiseCap`, an A/A median ratio of the run out of `[exp(-noiseCap), exp(noiseCap)]` also gives `cannot decide`.\n * - With `pool`, the pooled band replaces the band of the A/A arm of the run. The run still needs `minimum` A/A cases.\n */\nexport function timeVerdict(candidate: readonly PairedTime[], aa: readonly PairedTime[], options: VerdictOptions = {}): TimeVerdict {\n const level = options.spreadLevel ?? 0.9;\n if (options.noiseCap !== undefined && !(options.noiseCap >= 0 && Number.isFinite(options.noiseCap))) {\n throw new RangeError(`timeVerdict: the noise cap is a finite number of 0 or more, not ${options.noiseCap}.`);\n }\n const pool = poolFor(options);\n let verdict = ruleVerdict(candidate, aa, options, pool?.band);\n if (pool !== undefined) verdict = { ...verdict, pool: pool.facts };\n if (options.noiseCap !== undefined) {\n const cap = options.noiseCap;\n const aaRatios = caseRatios(aa);\n const spread = aaRatios.length === 0 ? undefined : spreadOf(aaRatios, level);\n const aaMedian = aaRatios.length === 0 ? undefined : Math.exp(quantile(aaRatios.map((r) => Math.log(r.ratio)), 0.5));\n const biased = aaMedian !== undefined && Math.abs(Math.log(aaMedian)) > cap;\n const noise: NoiseCheck = { spread, cap, noisy: spread === undefined || spread > cap, aaMedian, biased };\n verdict = { ...verdict, noise };\n // The early outcomes (no candidate cases, too few A/A cases) keep their reason. Each other outcome gives way to the cap.\n if (noise.noisy && verdict.band !== undefined) {\n const why = spread === undefined ? \"The A/A arm of the run has no cases, so the noise cap has no spread.\" : `The A/A spread of the run is ${round(spread)}, above the noise cap ${cap}.`;\n const reason = `${why} Without the cap, the outcome is \"${verdict.outcome}\".`;\n verdict = { ...verdict, outcome: \"cannot decide\", reason };\n } else if (noise.biased && verdict.band !== undefined) {\n const reason = `The A/A median ratio of the run is ${round(aaMedian!)}, out of [${round(Math.exp(-cap))}, ${round(Math.exp(cap))}] of the noise cap ${cap}. Without the cap, the outcome is \"${verdict.outcome}\".`;\n verdict = { ...verdict, outcome: \"cannot decide\", reason };\n }\n }\n return verdict;\n}\n\n/** This function gives the pooled band and its facts of the options, or undefined without the option `pool`. */\nfunction poolFor(options: VerdictOptions): { band: Band; facts: PoolFacts } | undefined {\n return options.pool === undefined ? undefined : poolOf(options.pool, options.spreadLevel ?? 0.9);\n}\n\n/** This function gives the margin of the rule `difference`: the larger of `margin` and the noise of the pooled band. It refuses a margin below 0. */\nfunction marginOf(options: VerdictOptions, pooled: Band | undefined): number {\n const given = options.margin ?? 0.05;\n if (!(given >= 0)) throw new RangeError(`timeVerdict: the margin is 0 or more, not ${given}.`);\n return pooled === undefined ? given : Math.max(given, pooled.noise);\n}\n\n/**\n * This function gives the margin that the rule `difference` of `timeVerdict` uses with these options, on a log scale.\n * The margin is the larger of the option `margin` (default 0.05) and the noise of the pooled band. It uses the same code as the verdict.\n * The pooled band comes from the records of the option `pool`, not from the records of the run.\n * An interval in `[exp(-margin), exp(margin)]` has the outcome `same`. A page can draw that zone with this function.\n */\nexport function verdictMargin(options: VerdictOptions = {}): number {\n return marginOf(options, poolFor(options)?.band);\n}\n\n/** This function gives the outcome of the rule. A pooled band replaces the band of the A/A arm, and it widens the margin of the rule `difference`. */\nfunction ruleVerdict(candidate: readonly PairedTime[], aa: readonly PairedTime[], options: VerdictOptions, pooled: Band | undefined): TimeVerdict {\n const rule = options.rule ?? \"difference\";\n const cases = caseRatios(candidate);\n const aaRatios = caseRatios(aa);\n const minimum = options.minimum ?? 5;\n const none = { cases, rule, interval: undefined, band: undefined, comparison: undefined };\n if (cases.length === 0) return { ...none, outcome: \"cannot decide\", reason: \"The candidate has no cases.\" };\n if (aaRatios.length < minimum) {\n const interval = bootstrapMedian(cases.map((c) => c.ratio), options.bootstrap);\n return { ...none, interval, outcome: \"cannot decide\", reason: `The A/A arm has ${aaRatios.length} cases, and a band needs ${minimum} or more.` };\n }\n const band = pooled ?? aaBand(aa, options);\n const comparison = compareRatios(cases.map((c) => 1 + Math.log(c.ratio)), { better: \"lower\", noise: band.noise });\n const facts = { cases, rule, band, comparison };\n if (rule === \"difference\") {\n const margin = marginOf(options, pooled);\n const shown = pooled === undefined ? margin : round(margin);\n const logs = cases.map((c) => Math.log(c.ratio));\n const aaLogs = aaRatios.map((c) => Math.log(c.ratio));\n const d = bootstrapTwo(logs, aaLogs, (x, y) => median(x) - median(y), options.bootstrap);\n const interval: Interval = { ...d, estimate: Math.exp(d.estimate), low: Math.exp(d.low), high: Math.exp(d.high) };\n const span = `The interval of the candidate median over the A/A median is [${round(interval.low)}, ${round(interval.high)}].`;\n // The margin comes first: an interval in the margin is `same`, also when it is wholly below or above 1.\n if (d.low >= -margin && d.high <= margin) return { ...facts, interval, outcome: \"same\", reason: `${span} The interval is in the margin of ${shown}.` };\n if (interval.high < 1) return { ...facts, interval, outcome: \"faster\", reason: `${span} The interval is below 1.` };\n if (interval.low > 1) return { ...facts, interval, outcome: \"slower\", reason: `${span} The interval is above 1.` };\n return { ...facts, interval, outcome: \"cannot decide\", reason: `${span} The interval holds 1 and crosses the margin of ${shown}.` };\n }\n const interval = bootstrapMedian(cases.map((c) => c.ratio), options.bootstrap);\n const span = `The interval of the median ratio is [${round(interval.low)}, ${round(interval.high)}], and the A/A band is [${round(band.low)}, ${round(band.high)}].`;\n if (interval.high < band.low) return { ...facts, interval, outcome: \"faster\", reason: `${span} The interval is below the band.` };\n if (interval.low > band.high) return { ...facts, interval, outcome: \"slower\", reason: `${span} The interval is above the band.` };\n if (interval.low >= band.low && interval.high <= band.high) return { ...facts, interval, outcome: \"same\", reason: `${span} The interval is in the band.` };\n return { ...facts, interval, outcome: \"cannot decide\", reason: `${span} The interval crosses an end of the band.` };\n}\n\nfunction round(x: number): number {\n return Math.round(x * 10_000) / 10_000;\n}\n","/**\n * The limit verdict of a bench: is the ratio of each case at most a limit? For example, the claim \"the new code takes at most\n * 2 times the time of the old code\" needs it. The time verdict compares only with 1.\n */\nimport { medianInterval } from \"@mark1russell7/rigor-statistics\";\nimport { type CaseRatio, type PairedTime, caseRatios } from \"./paired.ts\";\nimport { type Band, type BandOptions, aaBand } from \"./verdict.ts\";\n\n/** The ratio of one case with the interval of its median over the rounds. */\nexport interface CaseInterval extends CaseRatio {\n /** The ends of the interval: `exp` of `medianInterval` over the values `log(b / a)` of the rounds. */\n readonly low: number;\n readonly high: number;\n /** The coverage of the interval. It is at least the level. */\n readonly coverage: number;\n}\n\n/**\n * This function gives the ratio of each case with a distribution-free interval of its median, in the order of\n * `caseRatios`. It needs enough rounds for the level: 6 rounds or more for the level 0.95.\n */\nexport function caseIntervals(records: readonly PairedTime[], level = 0.95): CaseInterval[] {\n const logs = new Map<string, number[]>();\n for (const r of records) {\n const list = logs.get(r.case) ?? [];\n list.push(Math.log(r.b / r.a));\n logs.set(r.case, list);\n }\n return caseRatios(records).map((c) => {\n const interval = medianInterval(logs.get(c.case)!, level);\n return { ...c, low: Math.exp(interval.low), high: Math.exp(interval.high), coverage: interval.coverage };\n });\n}\n\n/** The three outcomes of a limit verdict. */\nexport type LimitOutcome = \"within\" | \"beyond\" | \"cannot decide\";\n\n/** The options of a limit verdict. */\nexport interface LimitOptions extends BandOptions {\n /** The largest ratio `b / a` that the claim permits, for example 2. */\n readonly limit: number;\n /** The level of the interval of each case. The default is 0.95. */\n readonly caseLevel?: number;\n /**\n * The share of the cases that the claim needs `within`, above 0 and at most 1. The default 1 needs each case. With 0.95\n * and 20 cases, 1 case can be `beyond` or `cannot decide`. The option `timeTailQ` of a promotion record is this share.\n */\n readonly share?: number;\n}\n\n/** The verdict of one case against the limit. */\nexport interface CaseLimit extends CaseInterval {\n /** The high end of the interval of the case, times the high end of the A/A band. */\n readonly bound: number;\n /** The low end of the interval of the case, times the low end of the A/A band. */\n readonly floor: number;\n readonly outcome: LimitOutcome;\n}\n\n/** A limit verdict, with the facts that it uses. */\nexport interface LimitVerdict {\n readonly outcome: LimitOutcome;\n /** The reason of the outcome, in one sentence. */\n readonly reason: string;\n readonly limit: number;\n readonly cases: readonly CaseLimit[];\n /** The band of the A/A arm, or undefined when the A/A arm has too few cases. */\n readonly band: Band | undefined;\n /** The share of the option `share`. */\n readonly share: number;\n /** The number of cases that can be other than `within`: the floor of the number of cases times `1 - share`. */\n readonly allowed: number;\n}\n\n/**\n * This function gives the verdict of the claim \"the ratio `b / a` of each case is at most `limit`\". The A/A band widens\n * the interval of each case: the bound is the high end times the high end of the band.\n * - A case is `within` when its bound is at most the limit, and `beyond` when its floor is above the limit.\n * - The verdict is `within` when `allowed` cases or fewer are other than `within`. With the default share 1, `allowed` is 0.\n * - The verdict is `beyond` when more than `allowed` cases are `beyond`.\n * - Each other verdict is `cannot decide`, and so is an A/A arm with too few cases or a candidate with no cases.\n */\nexport function limitVerdict(candidate: readonly PairedTime[], aa: readonly PairedTime[], options: LimitOptions): LimitVerdict {\n const { limit } = options;\n if (!(limit > 0 && Number.isFinite(limit))) throw new RangeError(`limitVerdict: the limit is a finite number above 0, not ${limit}.`);\n const share = options.share ?? 1;\n if (!(share > 0 && share <= 1)) throw new RangeError(`limitVerdict: the share is above 0 and at most 1, not ${share}.`);\n const intervals = caseIntervals(candidate, options.caseLevel);\n const minimum = options.minimum ?? 5;\n // The small term keeps a product such as 10 * (1 - 0.9) = 0.9999999999999998 from a floor of 0.\n const allowed = Math.floor(intervals.length * (1 - share) + 1e-9);\n if (intervals.length === 0) return { outcome: \"cannot decide\", reason: \"The candidate has no cases.\", limit, cases: [], band: undefined, share, allowed };\n const aaCount = caseRatios(aa).length;\n if (aaCount < minimum) {\n const cases = intervals.map((c) => ({ ...c, bound: c.high, floor: c.low, outcome: \"cannot decide\" as const }));\n return { outcome: \"cannot decide\", reason: `The A/A arm has ${aaCount} cases, and a band needs ${minimum} or more.`, limit, cases, band: undefined, share, allowed };\n }\n const band = aaBand(aa, options);\n const cases = intervals.map((c): CaseLimit => {\n const bound = c.high * band.high;\n const floor = c.low * band.low;\n const outcome: LimitOutcome = bound <= limit ? \"within\" : floor > limit ? \"beyond\" : \"cannot decide\";\n return { ...c, bound, floor, outcome };\n });\n const facts = { limit, cases, band, share, allowed };\n const beyond = cases.filter((c) => c.outcome === \"beyond\");\n const others = cases.filter((c) => c.outcome !== \"within\");\n const permit = allowed === 0 ? \"\" : `, and the share ${share} permits ${allowed}`;\n if (beyond.length > allowed) {\n return { outcome: \"beyond\", reason: `${beyond.length} of ${cases.length} cases are above the limit ${limit}${permit}. The first is ${JSON.stringify(beyond[0]!.case)}.`, ...facts };\n }\n if (others.length <= allowed) {\n const inside = cases.filter((c) => c.outcome === \"within\");\n const top = (inside.length > 0 ? inside : cases).reduce((a, b) => (b.bound > a.bound ? b : a));\n const rest = others.length === 0 ? \"\" : ` ${others.length} of ${cases.length} cases are not within${permit}.`;\n return { outcome: \"within\", reason: `The largest bound of a case within is ${round(top.bound)} in the case ${JSON.stringify(top.case)}, and it is at most the limit ${limit}.${rest}`, ...facts };\n }\n const top = cases.reduce((a, b) => (b.bound > a.bound ? b : a));\n return { outcome: \"cannot decide\", reason: `${others.length} of ${cases.length} cases are not within${permit}. The bound of the case ${JSON.stringify(top.case)} is ${round(top.bound)}, above the limit ${limit}, and too few floors are above it.`, ...facts };\n}\n\nfunction round(x: number): number {\n return Math.round(x * 10_000) / 10_000;\n}\n","/**\n * The merge of the records of many jobs, and the pooled verdicts over them. Each job of a bench gives its own records.\n * A pooled verdict uses all jobs together, and the verdict of each job alone guards it.\n */\nimport { type LimitOptions, type LimitOutcome, type LimitVerdict, limitVerdict } from \"./limit.ts\";\nimport { type Arm, type PairedTime } from \"./paired.ts\";\nimport { type TimeOutcome, type TimeVerdict, type VerdictOptions, timeVerdict } from \"./verdict.ts\";\n\n/** The records of each case with a turned order, and the count of the records that the balance removed. */\nexport interface Balanced<T extends PairedTime> {\n readonly records: T[];\n /** The count of the removed records. It is 0 when each case has a turned order. */\n readonly trimmed: number;\n}\n\n/**\n * This function removes records until the two orders of each case differ in count by 1 or less.\n * It removes the records of the larger order with the highest rounds first. The other records keep their order.\n * A job that stopped early, or a missing job, can leave a case with 2 more rounds of one order. `caseRatios` refuses such a case.\n */\nexport function balanceOrders<T extends PairedTime>(records: readonly T[]): Balanced<T> {\n const byCase = new Map<string, Record<Arm, number[]>>();\n records.forEach((record, index) => {\n const orders = byCase.get(record.case) ?? { a: [], b: [] };\n orders[record.first === \"b\" ? \"b\" : \"a\"].push(index);\n byCase.set(record.case, orders);\n });\n const drop = new Set<number>();\n const highFirst = (x: number, y: number): number => records[y]!.round - records[x]!.round;\n for (const { a, b } of byCase.values()) {\n const [more, fewer] = a.length > b.length ? [a, b] : [b, a];\n const extra = more.length - fewer.length - 1;\n if (extra > 0) for (const index of more.toSorted(highFirst).slice(0, extra)) drop.add(index);\n }\n return { records: records.filter((_, index) => !drop.has(index)), trimmed: drop.size };\n}\n\n/** The records of one job: the candidate pair and the A/A pair. */\nexport interface JobRecords {\n /** The label of the job, for example the index of its CI job. A record with a field `job` has this label, or `poolRecords` refuses it. */\n readonly job: string;\n readonly candidate: readonly PairedTime[];\n readonly aa: readonly PairedTime[];\n /** The cases that the job skipped, as `freshRun` gives them. `poolRecords` removes each of these cases from all jobs. */\n readonly skipped?: readonly { readonly case: string }[];\n}\n\n/** The records of one job in a pool: the cases that no job skipped, balanced with `balanceOrders`. */\nexport interface PooledJob {\n readonly job: string;\n readonly candidate: PairedTime[];\n readonly aa: PairedTime[];\n}\n\n/** The pool of the jobs: the merged records of all jobs, and the records of each job alone. */\nexport interface PooledRecords {\n /** The merged candidate records of all jobs, balanced with `balanceOrders`. */\n readonly candidate: PairedTime[];\n /** The merged A/A records of all jobs, balanced with `balanceOrders`. */\n readonly aa: PairedTime[];\n /** The records of each job alone, in the order of the jobs. */\n readonly jobs: readonly PooledJob[];\n /** The count of the records that `balanceOrders` removed from the merged candidate and A/A records. */\n readonly trimmed: number;\n /** The cases that a job skipped, in sorted order. The pool has no record of these cases. */\n readonly dropped: string[];\n}\n\n/**\n * This function gives the pool of the jobs. `pooledVerdict` and `pooledLimitVerdict` use it.\n * - It refuses two jobs with one label, and a record with a different job label. It also refuses two jobs with a record of one case and one round.\n * - It removes each case that a job skipped from all jobs, so all jobs have the same cases.\n * - It merges the records of the jobs, and it balances the merged records and the records of each job with `balanceOrders`.\n */\nexport function poolRecords(jobs: readonly JobRecords[]): PooledRecords {\n return pool(jobs, \"poolRecords\");\n}\n\n/** The pool of `poolRecords`. Each error starts with the name `caller`. */\nfunction pool(jobs: readonly JobRecords[], caller: string): PooledRecords {\n const labels = new Set<string>();\n for (const { job } of jobs) {\n if (labels.has(job)) throw new RangeError(`${caller}: two jobs have the label ${JSON.stringify(job)}.`);\n labels.add(job);\n }\n for (const { job, candidate: c, aa: a } of jobs) {\n for (const r of [...c, ...a] as readonly (PairedTime & { readonly job?: unknown })[]) {\n if (r.job !== undefined && r.job !== job) throw new RangeError(`${caller}: a record of the job ${JSON.stringify(job)} has the job ${JSON.stringify(r.job)}.`);\n }\n }\n const dropped = [...new Set(jobs.flatMap((j) => (j.skipped ?? []).map((s) => s.case)))].sort();\n const gone = new Set(dropped);\n const keep = (records: readonly PairedTime[]): PairedTime[] => records.filter((r) => !gone.has(r.case));\n const kept = jobs.map((j) => ({ job: j.job, candidate: keep(j.candidate), aa: keep(j.aa) }));\n uniqueRounds(kept, \"candidate\", caller);\n uniqueRounds(kept, \"aa\", caller);\n const candidate = balanceOrders(kept.flatMap((j) => j.candidate));\n const aa = balanceOrders(kept.flatMap((j) => j.aa));\n const each = kept.map(({ job, candidate: c, aa: a }): PooledJob => ({ job, candidate: balanceOrders(c).records, aa: balanceOrders(a).records }));\n return { candidate: candidate.records, aa: aa.records, jobs: each, trimmed: candidate.trimmed + aa.trimmed, dropped };\n}\n\n/** This function refuses two jobs with a record of one case and one round in one pair. */\nfunction uniqueRounds(jobs: readonly PooledJob[], pair: \"candidate\" | \"aa\", caller: string): void {\n const seen = new Map<string, string>();\n for (const { job, [pair]: records } of jobs) {\n for (const r of records) {\n const key = `${r.case}\\u0000${r.round}`;\n const other = seen.get(key);\n if (other !== undefined && other !== job) {\n throw new RangeError(\n `${caller}: the jobs ${JSON.stringify(other)} and ${JSON.stringify(job)} both have the round ${r.round} of the case ${JSON.stringify(r.case)} in the ${pair} pair. Set roundOffset of each job to job * rounds.`,\n );\n }\n seen.set(key, job);\n }\n }\n}\n\n/** The guard of a pooled verdict: the outcome, the opposed jobs and the reason. */\ninterface Guarded<O extends string> {\n readonly outcome: O | \"cannot decide\";\n readonly opposed: string[];\n readonly reason: string;\n}\n\n/**\n * This function applies the guard of the jobs to a pooled verdict. A job whose outcome is `opposite` of the pooled outcome\n * makes the outcome `cannot decide`. Each other job does not change the outcome.\n */\nfunction guard<O extends string>(\n pooled: { readonly outcome: O; readonly reason: string },\n jobs: readonly { readonly job: string; readonly verdict: { readonly outcome: O } }[],\n opposite: Partial<Record<O, O>>,\n): Guarded<O> {\n const against = opposite[pooled.outcome];\n const opposed = against === undefined ? [] : jobs.filter((j) => j.verdict.outcome === against).map((j) => j.job);\n if (opposed.length === 0) return { outcome: pooled.outcome, opposed, reason: pooled.reason };\n const names = opposed.map((j) => JSON.stringify(j)).join(\", \");\n const reason = `${pooled.reason} The pooled outcome is \"${pooled.outcome}\", but the jobs ${names} give \"${against}\". Thus the outcome is \"cannot decide\".`;\n return { outcome: \"cannot decide\", opposed, reason };\n}\n\n/** The verdict of one job alone. */\nexport interface JobVerdict {\n readonly job: string;\n readonly verdict: TimeVerdict;\n}\n\n/** The pooled verdict over the jobs, with the verdict of each job alone. */\nexport interface PooledVerdict {\n /** The outcome of the pooled verdict, or `cannot decide` when a job decides the opposite direction. */\n readonly outcome: TimeOutcome;\n /** The verdict of the merged and balanced records of all jobs. */\n readonly pooled: TimeVerdict;\n /** The verdict of each job alone, with the options of the pooled verdict. */\n readonly jobs: readonly JobVerdict[];\n /** The jobs whose own outcome is the opposite direction of the pooled outcome. */\n readonly opposed: string[];\n /** The count of the records that `balanceOrders` removed from the merged candidate and A/A records. */\n readonly trimmed: number;\n /** The cases that a job skipped, in sorted order. The verdicts use no record of these cases. */\n readonly dropped: string[];\n /** The reason of the pooled verdict, and the opposed jobs. */\n readonly reason: string;\n}\n\nconst opposite: Partial<Record<TimeOutcome, TimeOutcome>> = { faster: \"slower\", slower: \"faster\" };\n\n/**\n * This function gives the time verdict over the records of all jobs.\n * - It makes the pool of the jobs with `poolRecords`, and it gives the time verdict of the merged records.\n * - The verdict of each job alone uses the same options. A job with `cannot decide` or `same` does not change the outcome.\n * - A job that decides the opposite direction of the pooled outcome makes the outcome `cannot decide`.\n */\nexport function pooledVerdict(jobs: readonly JobRecords[], options: VerdictOptions = {}): PooledVerdict {\n const { candidate, aa, jobs: each, trimmed, dropped } = pool(jobs, \"pooledVerdict\");\n const pooled = timeVerdict(candidate, aa, options);\n const verdicts = each.map(({ job, candidate: c, aa: a }): JobVerdict => ({ job, verdict: timeVerdict(c, a, options) }));\n const { outcome, opposed, reason } = guard(pooled, verdicts, opposite);\n return { outcome, pooled, jobs: verdicts, opposed, trimmed, dropped, reason };\n}\n\n/** The limit verdict of one job alone. */\nexport interface JobLimitVerdict {\n readonly job: string;\n readonly verdict: LimitVerdict;\n}\n\n/** The pooled limit verdict over the jobs, with the limit verdict of each job alone. */\nexport interface PooledLimitVerdict {\n /** The outcome of the pooled limit verdict, or `cannot decide` when a job gives the opposite outcome. */\n readonly outcome: LimitOutcome;\n /** The limit verdict of the merged and balanced records of all jobs. */\n readonly pooled: LimitVerdict;\n /** The limit verdict of each job alone, with the options of the pooled verdict. */\n readonly jobs: readonly JobLimitVerdict[];\n /** The jobs whose own outcome is the opposite of the pooled outcome: `beyond` against `within`, or the reverse. */\n readonly opposed: string[];\n /** The count of the records that `balanceOrders` removed from the merged candidate and A/A records. */\n readonly trimmed: number;\n /** The cases that a job skipped, in sorted order. The verdicts use no record of these cases. */\n readonly dropped: string[];\n /** The reason of the pooled limit verdict, and the opposed jobs. */\n readonly reason: string;\n}\n\nconst limitOpposite: Partial<Record<LimitOutcome, LimitOutcome>> = { within: \"beyond\", beyond: \"within\" };\n\n/**\n * This function gives the limit verdict over the records of all jobs, for example for a speed gate on limits over a CI matrix.\n * - It makes the pool of the jobs with `poolRecords`, and it gives the limit verdict of the merged records.\n * - The verdict of each job alone uses the same options. A job with `cannot decide` does not change the outcome.\n * - A job with `beyond` against a pooled `within`, or the reverse, makes the outcome `cannot decide`.\n */\nexport function pooledLimitVerdict(jobs: readonly JobRecords[], options: LimitOptions): PooledLimitVerdict {\n const { candidate, aa, jobs: each, trimmed, dropped } = pool(jobs, \"pooledLimitVerdict\");\n const pooled = limitVerdict(candidate, aa, options);\n const verdicts = each.map(({ job, candidate: c, aa: a }): JobLimitVerdict => ({ job, verdict: limitVerdict(c, a, options) }));\n const { outcome, opposed, reason } = guard(pooled, verdicts, limitOpposite);\n return { outcome, pooled, jobs: verdicts, opposed, trimmed, dropped, reason };\n}\n\n/** The pairs of a run: the records of each pair, by the id of the pair. */\nexport interface RunPairs {\n readonly pairs: Readonly<Record<string, readonly PairedTime[]>>;\n}\n\n/**\n * This function gives the verdict of each candidate pair of a run against its A/A pair `aaPair`.\n * It balances the records of each pair with `balanceOrders` first. It refuses an `aaPair` that the run does not have.\n */\nexport function armVerdicts(run: RunPairs, aaPair: string, options: VerdictOptions = {}): Record<string, TimeVerdict> {\n const aaRecords = run.pairs[aaPair];\n if (aaRecords === undefined) throw new RangeError(`armVerdicts: the run has no pair ${JSON.stringify(aaPair)}.`);\n const aa = balanceOrders(aaRecords).records;\n const out: Record<string, TimeVerdict> = {};\n for (const [pair, records] of Object.entries(run.pairs)) {\n if (pair !== aaPair) out[pair] = timeVerdict(balanceOrders(records).records, aa, options);\n }\n return out;\n}\n","/**\n * The check that a trick does not buy a measure. A control is a strategy made to win one measure and nothing else.\n * A real entry that wins that measure can do the same trick, so the win alone tells little. This check reads the controls of a\n * bench, and it tells which wins need a partner measure beside them. It also tells which measures separate nothing.\n *\n * A test compares paired values with the sign test of `rigor-statistics` and with the Holm correction. The keys of one stratum come\n * from one family of inputs, so they are not independent draws. The p of a test holds only under the sign test's own null: each\n * untied key is a fair coin. A result is about these keys, and this check claims nothing about other inputs.\n */\nimport { holm, median, signTest, signTestPower } from \"@mark1russell7/rigor-statistics\";\n\n/** One value of one measure, for one entry and one input. */\nexport interface MeasureRow {\n /** The name of the measure. */\n readonly measure: string;\n /** The name of the entry: a real strategy or a control. */\n readonly group: string;\n /** The name of the input. Equal keys in two groups name equal work, so the two values make a pair. */\n readonly key: string;\n /** The value. It is finite. No test reads the value of a censored row. */\n readonly value: number;\n /** This field is true when the entry did not finish this input, for example over its budget. */\n readonly censored?: boolean;\n /** The way that the value was made, for example a sample or a full count. Two ways in one measure do not compare. */\n readonly method?: string;\n /** The family of the input. A key has one stratum in all its rows. Rows without a stratum make one group. */\n readonly stratum?: string;\n}\n\n/** A measure with no control yet: the reason and the date of the control. */\nexport interface NoControl {\n /** The reason that the measure has no control at this time. */\n readonly because: string;\n /** The date of the control, as `YYYY-MM-DD`. A date before `asOf` gives the finding `control-late`. */\n readonly until: string;\n}\n\n/** The rule of one measure. */\nexport interface MeasureRule {\n readonly measure: string;\n /** The direction of a better value. */\n readonly sense: \"higher\" | \"lower\";\n /** The controls made to win this measure. Each one is in `controls` of the options. */\n readonly controls: readonly string[];\n /** The measures that a control of this measure is to lose. Each one has its own rule. */\n readonly partners: readonly string[];\n /** The smallest median paired difference that counts. Without it, only the test decides, and the output says so. It has no default. */\n readonly resolution?: number;\n /** The reason and the date, for a rule with no controls. */\n readonly noControl?: NoControl;\n}\n\n/** The options of `checkMeasures`. */\nexport interface MeasureCheckOptions {\n readonly rules: readonly MeasureRule[];\n /** Each group that is a control. Each other group is a real entry. */\n readonly controls: readonly string[];\n /** The date of the check, as `YYYY-MM-DD`. The caller gives it, so the function stays pure. */\n readonly asOf: string;\n /** The level of each family of tests. The default is 0.05. */\n readonly alpha?: number;\n}\n\n/** One test: `better` beats `other` on the keys that the two finished. */\nexport interface Comparison {\n readonly better: string;\n readonly other: string;\n readonly stratum: string | undefined;\n /** The keys that both finished. */\n readonly shared: number;\n /** The shared keys with different values. The test reads only these. */\n readonly n: number;\n readonly ties: number;\n /** The keys where `better` has the better value. */\n readonly wins: number;\n /** The keys where `other` has the better value. */\n readonly losses: number;\n /** The median paired difference over the shared keys, with ties. A positive value favours `better`. */\n readonly medianDifference: number;\n /** The p of the sign test. */\n readonly p: number;\n /** The p after the Holm correction. */\n readonly adjusted: number;\n /** The size of the Holm family. */\n readonly family: number;\n /** The least count of untied keys with the power to pass in this family. */\n readonly needs: number;\n /** This field is true when `n` is under `needs`. Such a test beats nothing. */\n readonly tooFew: boolean;\n /** This field is true when the shared keys reach `needs` and ties took them under it. So the two read as equal, not as unread. */\n readonly tied: boolean;\n /** The test passes, and the median difference is over the resolution when the measure has one. */\n readonly beats: boolean;\n}\n\n/** The read of one control on one measure and one stratum. */\nexport interface ControlRead {\n readonly measure: string;\n readonly control: string;\n readonly stratum: string | undefined;\n /**\n * The state of the read. `wins`: no real entry with enough pairs beats the control. `beaten`: a real entry beats it.\n * `too-few`: no real entry has enough shared keys. `no-rows`: no real entry shares a finished key with it.\n */\n readonly status: \"wins\" | \"beaten\" | \"too-few\" | \"no-rows\";\n /** The real entries with fewer winning keys than the control. It is a plain count with no test. */\n readonly aheadOf: number;\n /** One test for each real entry: `better` is the real entry, and `other` is the control. */\n readonly comparisons: readonly Comparison[];\n /** The real entries that the control beats by test on this stratum. */\n readonly beatsEntries: number;\n /** The tests of the control against the real entries that have power on this stratum. */\n readonly of: number;\n /** One test for each real entry: `better` is the control, and `other` is the real entry. This family is apart from `comparisons`. */\n readonly against: readonly Comparison[];\n}\n\n/** The counts of one entry on one measure and one stratum. */\nexport interface EntryCount {\n readonly group: string;\n readonly stratum: string | undefined;\n readonly finished: number;\n readonly censored: number;\n}\n\n/** The read of the spread of one measure on one stratum, over the pairs of real entries. */\nexport interface SpreadRead {\n readonly stratum: string | undefined;\n /** The pairs of real entries that share a finished key. */\n readonly pairs: number;\n /** The pairs with a test that passes in one direction. */\n readonly separated: number;\n /** The pairs with too few shared keys for the test. A pair that ties on enough keys does not count here. */\n readonly tooFew: number;\n /** The largest absolute median paired difference of a pair. */\n readonly widest: number | undefined;\n}\n\n/** The result of one control and one partner on one stratum. */\nexport interface PartnerRead {\n readonly partner: string;\n /**\n * `lost`: a real entry beats the control at the level divided by the count of partners. Each partner is one more chance to clear the control.\n * `not-lost`: no real entry does. `too-few`: no test has the power at that level. `no-rows`: nothing to read.\n */\n readonly status: \"lost\" | \"not-lost\" | \"too-few\" | \"no-rows\";\n}\n\n/** The result of one control on its measure and one stratum, with its partners. */\nexport interface GuardRead {\n readonly control: string;\n readonly stratum: string | undefined;\n readonly status: ControlRead[\"status\"];\n readonly partners: readonly PartnerRead[];\n}\n\n/** The read of one measure. */\nexport interface MeasureCheck {\n readonly measure: string;\n readonly sense: \"higher\" | \"lower\";\n /** `test only`: a measure with no resolution. `test and resolution`: a measure with one. */\n readonly basis: \"test only\" | \"test and resolution\";\n /** The only method of the rows. It is undefined when the rows give none. */\n readonly method: string | undefined;\n /** This field is true when the rows mix methods. The check then has no read of the measure. */\n readonly mixed: boolean;\n readonly guards: readonly GuardRead[];\n readonly spread: readonly SpreadRead[];\n readonly entries: readonly EntryCount[];\n /** The partners that the rule names. */\n readonly partners: readonly string[];\n /** The reason and the date, for a measure with no control. */\n readonly open: NoControl | undefined;\n}\n\n/** The kind of a finding. Each finding fails a gate. */\nexport type MeasureFindingKind = \"uncaught\" | \"weak-control\" | \"censored-win\" | \"no-spread\" | \"too-few\" | \"mixed-method\" | \"no-rule\" | \"no-rows\" | \"no-control\" | \"control-late\";\n\n/** One finding of the check, with the numbers behind it. */\nexport interface MeasureFinding {\n readonly kind: MeasureFindingKind;\n readonly measure: string;\n readonly stratum?: string | undefined;\n readonly control?: string;\n /** The count of the partners of the rule, for a finding about the partners of a control. */\n readonly partners?: number;\n /** The finding in plain words, with its numbers. */\n readonly text: string;\n /** The tests behind the finding. */\n readonly comparisons: readonly Comparison[];\n}\n\n/** The result of `checkMeasures`. */\nexport interface MeasureChecks {\n /** The level of each family of tests. */\n readonly alpha: number;\n readonly measures: readonly MeasureCheck[];\n /** Each read of a control, on its own measures and on their partners. */\n readonly reads: readonly ControlRead[];\n readonly findings: readonly MeasureFinding[];\n}\n\n/** What a page says about the win of one entry on one measure. */\nexport interface WinClaim {\n /** This field is true only when a control was read on this measure and this entry beats each control on it. A win by another entry does not count. */\n readonly alone: boolean;\n /** The partners that a winning control loses. When this entry does not beat a control that does not win, or with no read of a control, all partners of the rule. */\n readonly show: readonly string[];\n /** This field is true when this entry does not beat a control on this measure and beats it on no partner. The win then reads the same as the trick. The status of the control does not change this. */\n readonly likeControl: boolean;\n /** The censored keys of this entry and of each control that it does not beat. A page shows them beside the win. */\n readonly censored: { readonly entry: number; readonly controls: readonly { readonly control: string; readonly censored: number }[] };\n /** The reason and the date, for a measure with no control. */\n readonly open: NoControl | undefined;\n}\n\nconst DEFAULT_ALPHA = 0.05;\nconst DATE = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n/** The rows of one measure: for each stratum, for each group, the rows by key. */\ntype StratumRows = Map<string | undefined, Map<string, Map<string, MeasureRow>>>;\n\nfunction checkedDate(name: string, date: string): string {\n const time = Date.parse(`${date}T00:00:00Z`);\n if (!DATE.test(date) || !Number.isFinite(time) || new Date(time).toISOString().slice(0, 10) !== date) throw new RangeError(`checkMeasures: ${name} is a date as YYYY-MM-DD, not ${JSON.stringify(date)}.`);\n return date;\n}\n\n/** This function refuses the rules that contradict each other, because a wrong rule reads as a passed check. */\nfunction checkedRules(options: MeasureCheckOptions): Map<string, MeasureRule> {\n const controls = new Set(options.controls);\n const rules = new Map<string, MeasureRule>();\n for (const rule of options.rules) {\n if (rules.has(rule.measure)) throw new RangeError(`checkMeasures: the measure ${JSON.stringify(rule.measure)} has two rules.`);\n rules.set(rule.measure, rule);\n }\n for (const rule of options.rules) {\n const name = JSON.stringify(rule.measure);\n for (const control of rule.controls) if (!controls.has(control)) throw new RangeError(`checkMeasures: the control ${JSON.stringify(control)} of ${name} is not in the controls of the options.`);\n for (const partner of rule.partners) {\n if (partner === rule.measure) throw new RangeError(`checkMeasures: ${name} names itself as a partner.`);\n if (!rules.has(partner)) throw new RangeError(`checkMeasures: the partner ${JSON.stringify(partner)} of ${name} has no rule.`);\n }\n if (rule.resolution !== undefined && !(Number.isFinite(rule.resolution) && rule.resolution >= 0)) throw new RangeError(`checkMeasures: the resolution of ${name} is finite and 0 or more, not ${rule.resolution}.`);\n if (rule.noControl !== undefined) {\n if (rule.controls.length > 0) throw new RangeError(`checkMeasures: ${name} has controls and also noControl.`);\n checkedDate(`the date of ${name}`, rule.noControl.until);\n }\n }\n return rules;\n}\n\n/** This function groups the rows. It refuses a value that is not finite, a repeat, and a key in two strata. */\nfunction groupedRows(rows: readonly MeasureRow[]): Map<string, StratumRows> {\n const strata = new Map<string, string | undefined>();\n const measures = new Map<string, StratumRows>();\n for (const row of rows) {\n const where = `${JSON.stringify(row.key)} of ${JSON.stringify(row.group)} on ${JSON.stringify(row.measure)}`;\n if (!Number.isFinite(row.value)) throw new RangeError(`checkMeasures: the value of ${where} is not finite: ${row.value}.`);\n if (strata.has(row.key) && strata.get(row.key) !== row.stratum) throw new RangeError(`checkMeasures: the key ${JSON.stringify(row.key)} has two strata.`);\n strata.set(row.key, row.stratum);\n const measure = measures.get(row.measure) ?? (new Map() as StratumRows);\n measures.set(row.measure, measure);\n const groups = measure.get(row.stratum) ?? new Map<string, Map<string, MeasureRow>>();\n measure.set(row.stratum, groups);\n const keys = groups.get(row.group) ?? new Map<string, MeasureRow>();\n groups.set(row.group, keys);\n if (keys.has(row.key)) throw new RangeError(`checkMeasures: the row ${where} comes twice. State how the repeats reduce to one row.`);\n keys.set(row.key, row);\n }\n return measures;\n}\n\n/** This function gives the least count of untied keys with the power to pass at `level`. */\nfunction pairsNeeded(level: number, sides: 1 | 2): number {\n let n = 1;\n while (signTestPower(n, level, sides) === undefined) n += 1;\n return n;\n}\n\n/** The numbers of one pair before the correction. */\ninterface RawTest {\n readonly better: string;\n readonly other: string;\n readonly stratum: string | undefined;\n readonly shared: number;\n readonly wins: number;\n readonly losses: number;\n readonly medianDifference: number;\n}\n\n/** This function compares two groups on the keys that both finished. A positive difference favours `better`. */\nfunction rawTest(better: string, other: string, stratum: string | undefined, groups: Map<string, Map<string, MeasureRow>>, sense: MeasureRule[\"sense\"]): RawTest | undefined {\n const a = groups.get(better);\n const b = groups.get(other);\n if (a === undefined || b === undefined) return undefined;\n const differences: number[] = [];\n for (const [key, row] of a) {\n const pair = b.get(key);\n if (pair === undefined || row.censored === true || pair.censored === true) continue;\n differences.push(sense === \"higher\" ? row.value - pair.value : pair.value - row.value);\n }\n if (differences.length === 0) return undefined;\n const wins = differences.filter((d) => d > 0).length;\n const losses = differences.filter((d) => d < 0).length;\n return { better, other, stratum, shared: differences.length, wins, losses, medianDifference: median(differences) };\n}\n\n/** This function corrects one family of tests, over all strata. A test with too few keys beats nothing, even when a step of Holm passes it. */\nfunction corrected(tests: readonly RawTest[], sides: 1 | 2, alpha: number, resolution: number | undefined): Comparison[] {\n if (tests.length === 0) return [];\n const family = tests.length;\n const needs = pairsNeeded(alpha / family, sides);\n const ps = tests.map((t) => signTest(t.wins, t.losses, sides));\n const steps = holm(ps, alpha);\n return tests.map((t, i) => {\n const n = t.wins + t.losses;\n const tooFew = n < needs;\n const size = sides === 1 ? t.medianDifference : Math.abs(t.medianDifference);\n const clears = resolution === undefined || size > resolution;\n return { ...t, n, ties: t.shared - n, p: ps[i] as number, adjusted: steps[i]?.adjusted as number, family, needs, tooFew, tied: tooFew && t.shared >= needs, beats: !tooFew && steps[i]?.reject === true && clears };\n });\n}\n\nconst stratumText = (stratum: string | undefined): string => (stratum === undefined ? \"\" : ` in the stratum ${JSON.stringify(stratum)}`);\n\n/** This function tells that a test has too few keys to read, so a tie on enough keys is a read. */\nconst unread = (c: Comparison): boolean => c.tooFew && !c.tied;\n\n/** The reads of one control on one measure: one for each stratum of the measure. */\nfunction controlReads(measure: string, control: string, data: StratumRows | undefined, rule: MeasureRule, real: readonly string[], alpha: number): ControlRead[] {\n if (data === undefined) return [];\n const tests = [...data].flatMap(([stratum, groups]) => real.flatMap((entry) => rawTest(entry, control, stratum, groups, rule.sense) ?? []));\n const comparisons = corrected(tests, 1, alpha, rule.resolution);\n const attacks = corrected(\n [...data].flatMap(([stratum, groups]) => real.flatMap((entry) => rawTest(control, entry, stratum, groups, rule.sense) ?? [])),\n 1,\n alpha,\n rule.resolution,\n );\n return [...data.keys()].map((stratum) => {\n const here = comparisons.filter((c) => c.stratum === stratum);\n const against = attacks.filter((c) => c.stratum === stratum);\n const status: ControlRead[\"status\"] = here.length === 0 ? \"no-rows\" : here.some((c) => c.beats) ? \"beaten\" : here.every(unread) ? \"too-few\" : \"wins\";\n return { measure, control, stratum, status, aheadOf: here.filter((c) => c.losses > c.wins).length, comparisons: here, beatsEntries: against.filter((c) => c.beats).length, of: against.filter((c) => !unread(c)).length, against };\n });\n}\n\n/** The read of the spread of one measure: one family over all pairs of real entries and all strata. */\nfunction spreadReads(data: StratumRows, rule: MeasureRule, real: readonly string[], alpha: number): { reads: SpreadRead[]; comparisons: Comparison[] } {\n const tests = [...data].flatMap(([stratum, groups]) => real.flatMap((entry, i) => real.slice(i + 1).flatMap((other) => rawTest(entry, other, stratum, groups, rule.sense) ?? [])));\n const comparisons = corrected(tests, 2, alpha, rule.resolution);\n const reads = [...data.keys()].map((stratum) => {\n const here = comparisons.filter((c) => c.stratum === stratum);\n const widest = here.length === 0 ? undefined : Math.max(...here.map((c) => Math.abs(c.medianDifference)));\n return { stratum, pairs: here.length, separated: here.filter((c) => c.beats).length, tooFew: here.filter(unread).length, widest };\n });\n return { reads, comparisons };\n}\n\nfunction countsOf(data: StratumRows | undefined): EntryCount[] {\n const counts: EntryCount[] = [];\n for (const [stratum, groups] of data ?? []) {\n for (const [group, keys] of groups) {\n const censored = [...keys.values()].filter((row) => row.censored === true).length;\n counts.push({ group, stratum, finished: keys.size - censored, censored });\n }\n }\n return counts;\n}\n\n/** This function gives the methods of a measure. A row with no method counts as one more method beside a named one. */\nfunction methodsOf(data: StratumRows | undefined): readonly (string | undefined)[] {\n const methods = new Set<string | undefined>();\n for (const groups of data?.values() ?? []) for (const keys of groups.values()) for (const row of keys.values()) methods.add(row.method);\n return [...methods];\n}\n\n/** This function tells that a test clears a control on one of `partners` partners. One passed partner is enough, so the level divides by their count. */\nconst clearsPartner = (c: Comparison, partners: number, alpha: number): boolean => c.beats && c.adjusted * partners <= alpha;\n\n/** This function reads a control on one of `partners` partners. A test with too few shared keys for the divided level has no power, so a miss there is not a read. */\nconst partnerStatus = (read: ControlRead | undefined, partners: number, alpha: number): PartnerRead[\"status\"] => {\n if (read === undefined || read.status === \"no-rows\") return \"no-rows\";\n if (read.comparisons.some((c) => clearsPartner(c, partners, alpha))) return \"lost\";\n const needs = pairsNeeded(alpha / ((read.comparisons[0]?.family ?? 1) * partners), 1);\n return read.comparisons.every((c) => c.shared < needs) ? \"too-few\" : \"not-lost\";\n};\n\n/** The inputs of the reads, with the reads that the check already made. */\ninterface Reading {\n readonly rules: Map<string, MeasureRule>;\n readonly data: Map<string, StratumRows>;\n readonly real: readonly string[];\n readonly alpha: number;\n readonly mixed: ReadonlySet<string>;\n readonly memo: Map<string, ControlRead[]>;\n}\n\nfunction readsOf(reading: Reading, measure: string, control: string): ControlRead[] {\n const memoKey = JSON.stringify([measure, control]);\n const known = reading.memo.get(memoKey);\n if (known !== undefined) return known;\n const rule = reading.rules.get(measure) as MeasureRule;\n const reads = reading.mixed.has(measure) ? [] : controlReads(measure, control, reading.data.get(measure), rule, reading.real, reading.alpha);\n reading.memo.set(memoKey, reads);\n return reads;\n}\n\n/** The findings of the rows and the controls of one rule that have nothing to read. */\nfunction missingFindings(rule: MeasureRule, reading: Reading): MeasureFinding[] {\n const findings: MeasureFinding[] = [];\n const hasRows = (measure: string, group: string): boolean => [...(reading.data.get(measure)?.values() ?? [])].some((groups) => groups.has(group));\n const missing = (text: string, control?: string): void => {\n findings.push({ kind: \"no-rows\", measure: rule.measure, ...(control === undefined ? {} : { control }), text, comparisons: [] });\n };\n if (!reading.data.has(rule.measure)) missing(`The measure ${rule.measure} has a rule and no rows.`);\n for (const control of rule.controls) {\n if (reading.data.has(rule.measure) && !hasRows(rule.measure, control)) missing(`The control ${control} has no rows on ${rule.measure}, so it reads as nothing and not as \"not beaten\".`, control);\n for (const partner of rule.partners) {\n if (!hasRows(partner, control)) missing(`The control ${control} has no rows on the partner ${partner} of ${rule.measure}, so it reads as nothing and not as \"not beaten\".`, control);\n }\n }\n return findings;\n}\n\n/** The findings of the win of a control on one stratum: the partners and the censored keys. */\nfunction winFindings(rule: MeasureRule, read: ControlRead, guard: GuardRead, counts: readonly EntryCount[], partnerReads: readonly ControlRead[]): MeasureFinding[] {\n const findings: MeasureFinding[] = [];\n const where = stratumText(read.stratum);\n const count = guard.partners.length;\n const thin = guard.partners.filter((p) => p.status === \"too-few\").map((p) => p.partner);\n const noRows = guard.partners.some((p) => p.status === \"no-rows\");\n const behind = partnerReads.flatMap((r) => r.comparisons);\n if (!guard.partners.some((p) => p.status === \"lost\")) {\n if (thin.length > 0) {\n findings.push({ kind: \"too-few\", measure: rule.measure, stratum: read.stratum, control: read.control, partners: count, text: `The control ${read.control} wins ${rule.measure}${where} and loses no partner. Of its ${count} partners, ${thin.join(\", \")} have too few keys for a read.`, comparisons: behind });\n } else if (!noRows) {\n const list = count === 0 ? \"It has no partner.\" : `It loses none of its ${count} partners, ${guard.partners.map((p) => p.partner).join(\", \")}.`;\n findings.push({ kind: \"uncaught\", measure: rule.measure, stratum: read.stratum, control: read.control, partners: count, text: `The control ${read.control} wins ${rule.measure}${where}. ${list}`, comparisons: [...read.comparisons, ...behind] });\n }\n }\n const own = counts.find((c) => c.group === read.control && c.stratum === read.stratum)?.censored ?? 0;\n const fewer = counts.filter((c) => c.group !== read.control && c.stratum === read.stratum && read.comparisons.some((t) => t.better === c.group) && c.censored < own);\n if (fewer.length > 0) {\n const list = fewer.map((c) => `${c.group} ${c.censored}`).join(\", \");\n findings.push({ kind: \"censored-win\", measure: rule.measure, stratum: read.stratum, control: read.control, text: `The control ${read.control} wins ${rule.measure}${where} with ${own} censored keys, more than ${list}. Its win can come from the easy keys.`, comparisons: read.comparisons.filter((t) => fewer.some((c) => c.group === t.better)) });\n }\n return findings;\n}\n\n/** The read of one rule, with its findings. */\nfunction checkRule(rule: MeasureRule, reading: Reading, asOf: string): { check: MeasureCheck; findings: MeasureFinding[]; reads: ControlRead[] } {\n const data = reading.data.get(rule.measure);\n const methods = methodsOf(data);\n const mixed = reading.mixed.has(rule.measure);\n const counts = countsOf(data);\n const findings = missingFindings(rule, reading);\n const reads: ControlRead[] = [];\n const guards: GuardRead[] = [];\n\n if (mixed) {\n findings.push({ kind: \"mixed-method\", measure: rule.measure, text: `The measure ${rule.measure} mixes the methods ${methods.map((m) => m ?? \"(none)\").join(\", \")}. The check has no read of it until the rows are split or marked.`, comparisons: [] });\n }\n if (rule.controls.length === 0) {\n if (rule.noControl === undefined) findings.push({ kind: \"no-control\", measure: rule.measure, text: `The measure ${rule.measure} has no control and no noControl with a date.`, comparisons: [] });\n else if (rule.noControl.until < asOf) findings.push({ kind: \"control-late\", measure: rule.measure, text: `The control of ${rule.measure} was due on ${rule.noControl.until}, and the date of the check is ${asOf}.`, comparisons: [] });\n }\n\n for (const control of rule.controls) {\n for (const read of readsOf(reading, rule.measure, control)) {\n const partnerReads = rule.partners.map((partner) => readsOf(reading, partner, control).find((r) => r.stratum === read.stratum));\n const partners = rule.partners.map((partner, i) => ({ partner, status: partnerStatus(partnerReads[i], rule.partners.length, reading.alpha) }));\n const guard = { control, stratum: read.stratum, status: read.status, partners };\n guards.push(guard);\n reads.push(read, ...partnerReads.filter((r) => r !== undefined));\n if (read.status === \"wins\") findings.push(...winFindings(rule, read, guard, counts, partnerReads.filter((r) => r !== undefined)));\n }\n }\n const controlComparisons = guards.length === 0 ? [] : reads.filter((r) => r.measure === rule.measure).flatMap((r) => r.comparisons);\n if (rule.controls.length > 0 && guards.length > 0 && !mixed) {\n if (guards.every((g) => g.status === \"too-few\" || g.status === \"no-rows\")) {\n const needs = Math.max(0, ...controlComparisons.map((c) => c.needs));\n findings.push({ kind: \"too-few\", measure: rule.measure, text: `No control of ${rule.measure} has enough pairs for a read. A test needs ${needs} untied pairs.`, comparisons: controlComparisons });\n } else {\n for (const control of rule.controls) {\n const own = reads.filter((r) => r.measure === rule.measure && r.control === control);\n const of = own.reduce((sum, r) => sum + r.of, 0);\n if (of > 0 && own.every((r) => r.beatsEntries === 0)) {\n findings.push({ kind: \"weak-control\", measure: rule.measure, control, text: `The control ${control} beats 0 of ${of} real entries on ${rule.measure} by test, in all strata. The trick buys nothing.`, comparisons: own.flatMap((r) => r.against) });\n }\n }\n }\n }\n\n let spread: SpreadRead[] = [];\n if (data !== undefined && !mixed) {\n const { reads: spreadRows, comparisons } = spreadReads(data, rule, reading.real, reading.alpha);\n spread = spreadRows;\n const testable = comparisons.filter((c) => !unread(c));\n if (comparisons.length > 0 && testable.length === 0) {\n findings.push({ kind: \"too-few\", measure: rule.measure, text: `No pair of real entries has enough keys for a read of the spread of ${rule.measure}. A test needs ${comparisons[0]?.needs} untied pairs.`, comparisons: [] });\n } else if (testable.length > 0 && !comparisons.some((c) => c.beats)) {\n const widest = Math.max(...comparisons.map((c) => Math.abs(c.medianDifference)));\n const basis = rule.resolution === undefined ? \"by the test only\" : `by the test and the resolution ${rule.resolution}`;\n findings.push({ kind: \"no-spread\", measure: rule.measure, text: `No pair of the ${comparisons.length} pairs of real entries separates on ${rule.measure}, ${basis}. The widest median difference is ${widest}.`, comparisons: [...comparisons].sort((a, b) => a.adjusted - b.adjusted).slice(0, 1) });\n }\n }\n\n const check: MeasureCheck = {\n measure: rule.measure,\n sense: rule.sense,\n basis: rule.resolution === undefined ? \"test only\" : \"test and resolution\",\n method: mixed ? undefined : methods[0],\n mixed,\n guards,\n spread,\n entries: counts,\n partners: rule.partners,\n open: rule.noControl,\n };\n return { check, findings, reads };\n}\n\n/**\n * This function reads the controls and the spread of each measure of a bench.\n *\n * - A control wins a measure when no real entry beats it on the keys that both finished. A tie counts for the control.\n * - A real entry beats a control when the Holm-corrected sign test passes and the median paired difference is over the resolution.\n * - One Holm family holds the tests of one control on one measure over all real entries and all strata.\n * - One more Holm family holds the tests of one control against the real entries, with the same need and resolution. A control that beats none of them is weak.\n * - One Holm family holds the tests of the spread of one measure over all pairs of real entries and all strata.\n * - A test with fewer untied keys than `signTestPower` needs for that family reads `tooFew` and beats nothing.\n * - A test with enough shared keys and too few untied keys is `tied`. The two entries read as equal, so a constant measure is `no-spread` and not `too-few`.\n * - A control loses a partner only at the level divided by the count of its partners. One passed partner clears `uncaught`, so each partner is one more chance.\n *\n * The function throws a `RangeError` for a value that is not finite, a repeat of measure, group and key, or a key in two strata.\n * It also throws one for rules that contradict each other.\n * The rules, the controls and the date are stated, so the result depends only on the arguments.\n */\nexport function checkMeasures(rows: readonly MeasureRow[], options: MeasureCheckOptions): MeasureChecks {\n const alpha = options.alpha ?? DEFAULT_ALPHA;\n if (!(alpha > 0 && alpha < 1)) throw new RangeError(`checkMeasures: alpha is over 0 and under 1, not ${alpha}.`);\n const asOf = checkedDate(\"asOf\", options.asOf);\n const rules = checkedRules(options);\n const data = groupedRows(rows);\n const controls = new Set(options.controls);\n const real = [...new Set(rows.map((row) => row.group))].filter((group) => !controls.has(group));\n const mixed = new Set([...data.keys()].filter((measure) => methodsOf(data.get(measure)).length > 1));\n const reading: Reading = { rules, data, real, alpha, mixed, memo: new Map() };\n\n const findings: MeasureFinding[] = [];\n for (const measure of data.keys()) {\n if (!rules.has(measure)) findings.push({ kind: \"no-rule\", measure, text: `The measure ${measure} has rows and no rule.`, comparisons: [] });\n }\n const measures: MeasureCheck[] = [];\n const reads = new Map<string, ControlRead>();\n for (const rule of options.rules) {\n const result = checkRule(rule, reading, asOf);\n measures.push(result.check);\n findings.push(...result.findings);\n for (const read of result.reads) reads.set(JSON.stringify([read.measure, read.control, read.stratum ?? null]), read);\n }\n return { alpha, measures, reads: [...reads.values()], findings };\n}\n\n/**\n * This function tells what a page says about the win of one real entry on one measure.\n * The claim is about this entry: only this entry beating the control, on this measure or on a partner, clears the entry. A win by another entry clears nothing.\n * With a stratum, the function reads that stratum. Without one, it reads the rows with no stratum.\n * The function throws a `RangeError` for a measure with no read and for an entry that the rows do not hold.\n */\nexport function winClaim(check: MeasureChecks, measure: string, entry: string, stratum?: string): WinClaim {\n const read = check.measures.find((m) => m.measure === measure);\n if (read === undefined) throw new RangeError(`winClaim: the measure ${JSON.stringify(measure)} has no rule.`);\n const count = read.entries.find((c) => c.group === entry && c.stratum === stratum);\n if (count === undefined) throw new RangeError(`winClaim: the entry ${JSON.stringify(entry)} has no rows on ${JSON.stringify(measure)}${stratumText(stratum)}.`);\n const guards = read.guards.filter((g) => g.stratum === stratum);\n const winning = guards.filter((g) => g.status === \"wins\");\n const lostByControl = (guard: GuardRead): readonly string[] => guard.partners.filter((p) => p.status === \"lost\").map((p) => p.partner);\n const testsOf = (of: string, control: string): readonly Comparison[] => check.reads.find((r) => r.measure === of && r.control === control && r.stratum === stratum)?.comparisons ?? [];\n const notBeaten = guards.filter((g) => !testsOf(measure, g.control).some((c) => c.better === entry && c.beats));\n const clearsOnPartner = (guard: GuardRead): boolean => guard.partners.some((p) => testsOf(p.partner, guard.control).some((c) => c.better === entry && clearsPartner(c, guard.partners.length, check.alpha)));\n const countOf = (control: string): number => read.entries.find((c) => c.group === control && c.stratum === stratum)?.censored ?? 0;\n const alone = guards.length > 0 && notBeaten.length === 0;\n const onlyWinners = notBeaten.length > 0 && notBeaten.every((g) => g.status === \"wins\");\n const show = onlyWinners ? [...new Set(winning.flatMap(lostByControl))] : alone ? [] : read.partners;\n return {\n alone,\n show,\n likeControl: notBeaten.some((guard) => !clearsOnPartner(guard)),\n censored: { entry: count.censored, controls: notBeaten.map((g) => ({ control: g.control, censored: countOf(g.control) })) },\n open: read.open,\n };\n}\n","/**\n * The power test of a time verdict. It draws seeded benches with a known speedup and counts the verdicts that find it.\n * It also draws benches with equal arms and counts the false verdicts.\n */\nimport { random } from \"@mark1russell7/rigor-generators\";\nimport { firstArm, type PairedTime } from \"./paired.ts\";\nimport { type TimeOutcome, type VerdictOptions, timeVerdict, verdictMargin } from \"./verdict.ts\";\n\n/** The options of a power test. */\nexport interface PowerOptions {\n /** The count of the cases of the candidate and of the A/A arm. */\n readonly cases: number;\n /** The count of the rounds of each case. The default is 5. */\n readonly rounds?: number;\n /** The true ratio of the candidate time to the baseline time, for example 0.93 for a speedup of 7%. */\n readonly ratio: number;\n /** The standard deviation of the log time of one arm in one round. The default is 0.1. */\n readonly sigma?: number;\n /** The count of the seeded benches. The default is 200. */\n readonly trials?: number;\n /** The seed of the draws. The default is 1. */\n readonly seed?: number | string;\n /** The options of the verdict of each bench. */\n readonly verdict?: VerdictOptions;\n}\n\n/** The result of a power test: the share of each outcome over the trials. */\nexport interface Power {\n readonly trials: number;\n readonly outcomes: Readonly<Record<TimeOutcome, number>>;\n /**\n * The share of the trials whose outcome is the true one. For the rule `difference`, a ratio in the margin of the verdict has the true outcome `same`.\n * That margin is the larger of `margin` and the noise of the pooled band. The pool is the same in each trial, so each trial has the same margin.\n * Out of that margin, and for the rule `band`, the true outcome is `faster` below 1, `slower` above 1 and `same` at 1.\n */\n readonly power: number;\n}\n\n/**\n * This function draws `trials` benches and gives the share of each verdict. Each case has its own log scale.\n * Each arm of each round adds a normal noise of `sigma` to the log time.\n */\nexport function verdictPower(options: PowerOptions): Power {\n const rounds = options.rounds ?? 5;\n const sigma = options.sigma ?? 0.1;\n const trials = options.trials ?? 200;\n if (!Number.isSafeInteger(options.cases) || options.cases < 1) throw new RangeError(`verdictPower: cases is a whole number of 1 or more, not ${options.cases}.`);\n if (!(options.ratio > 0 && Number.isFinite(options.ratio))) throw new RangeError(`verdictPower: the ratio is a finite number above 0, not ${options.ratio}.`);\n const r = random(options.seed ?? 1);\n const bench = (ratio: number, prefix: string): PairedTime[] => {\n const out: PairedTime[] = [];\n for (let c = 0; c < options.cases; c++) {\n const scale = 10 * Math.exp(r.normal());\n for (let round = 0; round < rounds; round++) {\n const a = scale * Math.exp(r.normal(0, sigma));\n const b = scale * ratio * Math.exp(r.normal(0, sigma));\n out.push({ case: `${prefix}${c}`, round, first: firstArm(round, c), a, b });\n }\n }\n return out;\n };\n const truth = trueOutcome(options.ratio, options.verdict);\n const counts: Record<TimeOutcome, number> = { faster: 0, slower: 0, same: 0, \"cannot decide\": 0 };\n for (let t = 0; t < trials; t++) {\n const aa = bench(1, \"aa\");\n const candidate = bench(options.ratio, \"c\");\n counts[timeVerdict(candidate, aa, options.verdict).outcome]++;\n }\n const outcomes = Object.fromEntries(Object.entries(counts).map(([k, n]) => [k, n / trials])) as Record<TimeOutcome, number>;\n return { trials, outcomes, power: outcomes[truth] };\n}\n\n/** This function gives the true outcome of a ratio. The margin of the rule `difference` comes first, as in `timeVerdict`. */\nfunction trueOutcome(ratio: number, verdict: VerdictOptions = {}): TimeOutcome {\n if ((verdict.rule ?? \"difference\") === \"difference\" && Math.abs(Math.log(ratio)) <= verdictMargin(verdict)) return \"same\";\n return ratio < 1 ? \"faster\" : ratio > 1 ? \"slower\" : \"same\";\n}\n","/**\n * The timed rounds of one case in one process. The two arms first run for a warm-up time. Then the count of calls of\n * one batch grows until a batch of arm `a` takes the target time. Each round times one batch of each arm, in the order\n * of `firstArm`. Start this function in a fresh process for each case.\n */\nimport { type Arm, type PairedTime, firstArm } from \"./paired.ts\";\n\n/** The options of the timed rounds of one case. */\nexport interface RoundsOptions {\n /** The name of the case. */\n readonly case: string;\n /** The count of the rounds. */\n readonly rounds: number;\n /** The offset of `firstArm`: give the index of the case, so half of the cases start with each arm. The default is 0. */\n readonly offset?: number;\n /** The least time in milliseconds of one batch of arm `a`. The default is 10. */\n readonly targetMs?: number;\n /** The time in milliseconds of the warm-up of the two arms. The default is 1000. */\n readonly warmMs?: number;\n /** The clock in milliseconds. The default is `performance.now` of the global `performance` of Node and of each browser. */\n readonly now?: () => number;\n}\n\n/** The result of the timed rounds of one case. */\nexport interface Rounds {\n readonly records: PairedTime[];\n /** The count of calls of each arm in one batch. */\n readonly count: number;\n /** The sum of the numbers that the arms gave. The engine cannot remove the work of a call, because this sum uses it. */\n readonly sink: number;\n}\n\n/**\n * This function times the arms `a` and `b` of one case, and gives one `PairedTime` record for each round. The time of\n * a record is the time of one batch, in milliseconds. Each call of an arm gives a number, and the sum of these numbers\n * keeps the work.\n */\nexport function timeRounds(arms: Readonly<Record<Arm, () => number>>, options: RoundsOptions): Rounds {\n const { rounds } = options;\n const offset = options.offset ?? 0;\n const targetMs = options.targetMs ?? 10;\n const warmMs = options.warmMs ?? 1000;\n const now = options.now ?? (() => performance.now());\n if (!Number.isSafeInteger(rounds) || rounds < 1) throw new RangeError(`timeRounds: the rounds are a whole number of 1 or more, not ${rounds}.`);\n if (!Number.isSafeInteger(offset)) throw new RangeError(`timeRounds: the offset is a whole number, not ${offset}.`);\n if (!(targetMs > 0) || !(warmMs >= 0)) throw new RangeError(\"timeRounds: the target time is above 0, and the warm-up time is 0 or more.\");\n let sink = 0;\n const batch = (arm: Arm, count: number): number => {\n const run = arms[arm];\n const start = now();\n for (let i = 0; i < count; i++) sink += run();\n return now() - start;\n };\n let count = 1;\n const warmUntil = now() + warmMs;\n while (now() < warmUntil) {\n if (batch(\"a\", count) < targetMs / 4) count *= 2;\n batch(\"b\", count);\n }\n while (batch(\"a\", count) < targetMs) count *= 2;\n const records: PairedTime[] = [];\n for (let round = 0; round < rounds; round++) {\n const first = firstArm(round, offset);\n const second: Arm = first === \"a\" ? \"b\" : \"a\";\n const times = { [first]: batch(first, count), [second]: batch(second, count) } as Record<Arm, number>;\n records.push({ case: options.case, round, first, a: times.a, b: times.b });\n }\n return { records, count, sink };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["round","round","round"],"sources":["../src/budget.ts","../src/gate.ts","../src/control.ts","../src/ladder.ts","../src/verdict.ts","../src/limit.ts","../src/tail.ts","../src/merge.ts","../src/measures.ts","../src/power.ts","../src/rounds.ts"],"sourcesContent":["/**\n * The budget verdict of one build: is the median of a measure of each case at most an absolute limit? An example is the\n * claim \"the median blocking time of this page is at most 450 ms\". The time verdict and the limit verdict judge a ratio\n * of two arms, so they cannot use a value of 0. Their A/A band is also a ratio.\n */\nimport { median, medianInterval } from \"@mark1russell7/rigor-statistics\";\n\n/** One value of one build on one case. The value is finite and 0 or more. */\nexport interface BudgetRound {\n /** The name of the case: one input of the bench. */\n readonly case: string;\n /** The number of the round, a whole number of 0 or more. */\n readonly round: number;\n readonly value: number;\n}\n\n/** The three outcomes of a budget verdict. */\nexport type BudgetOutcome = \"within\" | \"beyond\" | \"cannot decide\";\n\n/** The options of a budget verdict. */\nexport interface BudgetOptions {\n /** The largest median that the claim permits, in the unit of the values. */\n readonly limit: number;\n /** The largest difference between the medians of the two arms of the same build. A larger difference makes the run too noisy. */\n readonly maxDifference: number;\n /** The level of the interval of each median. The default is 0.95, which needs 6 rounds or more in each arm. */\n readonly caseLevel?: number;\n}\n\n/** The verdict of one case against the budget. */\nexport interface CaseBudget {\n readonly case: string;\n /** The number of rounds of the case. */\n readonly rounds: number;\n /** The number of rounds of the case in the A/A arm. */\n readonly aaRounds: number;\n readonly median: number;\n /** The median of the A/A arm, or undefined when the A/A arm does not have the case. */\n readonly aaMedian: number | undefined;\n /** The size of the difference between the two medians, or undefined when the A/A arm does not have the case. */\n readonly difference: number | undefined;\n /** The ends of the distribution-free interval of the median. */\n readonly low: number;\n readonly high: number;\n /** The coverage of the interval. Below the level, the case has too few rounds. */\n readonly coverage: number;\n readonly outcome: BudgetOutcome;\n /** The reason of the outcome, in one sentence, with the limit, the medians, the difference and the rounds. */\n readonly reason: string;\n}\n\n/** A budget verdict, with the facts that it uses. */\nexport interface BudgetVerdict {\n readonly outcome: BudgetOutcome;\n /** The reason of the outcome, in one sentence. */\n readonly reason: string;\n readonly limit: number;\n readonly maxDifference: number;\n readonly level: number;\n readonly cases: readonly CaseBudget[];\n}\n\n/** This function gives the values of each case, and it refuses a value out of range or a round that comes twice. */\nfunction valuesOfCases(name: string, rounds: readonly BudgetRound[]): Map<string, number[]> {\n const seen = new Set<string>();\n const out = new Map<string, number[]>();\n for (const r of rounds) {\n if (!(Number.isFinite(r.value) && r.value >= 0)) throw new RangeError(`budgetVerdict: the value of ${JSON.stringify(r.case)} in ${name} is finite and 0 or more, not ${r.value}.`);\n const key = JSON.stringify([r.case, r.round]);\n if (seen.has(key)) throw new RangeError(`budgetVerdict: the round ${r.round} of ${JSON.stringify(r.case)} comes twice in ${name}.`);\n seen.add(key);\n out.set(r.case, [...(out.get(r.case) ?? []), r.value]);\n }\n return out;\n}\n\n/** This function gives the verdict of one case. */\nfunction caseBudget(name: string, values: readonly number[], aaValues: readonly number[], options: BudgetOptions, level: number): CaseBudget {\n const { limit, maxDifference } = options;\n const interval = medianInterval(values, level);\n const middle = median(values);\n const aaMedian = aaValues.length > 0 ? median(aaValues) : undefined;\n const difference = aaMedian === undefined ? undefined : Math.abs(middle - aaMedian);\n const aaCoverage = aaValues.length > 0 ? medianInterval(aaValues, level).coverage : 0;\n const facts = `median ${round(middle)} of ${values.length} rounds, interval ${round(interval.low)} to ${round(interval.high)}, limit ${limit}, A/A median ${aaMedian === undefined ? \"none\" : round(aaMedian)} of ${aaValues.length} rounds, difference ${difference === undefined ? \"none\" : round(difference)}`;\n const decide = (outcome: BudgetOutcome, why: string): CaseBudget => ({\n case: name,\n rounds: values.length,\n aaRounds: aaValues.length,\n median: middle,\n aaMedian,\n difference,\n low: interval.low,\n high: interval.high,\n coverage: interval.coverage,\n outcome,\n reason: `The case ${JSON.stringify(name)} has the outcome \"${outcome}\": ${why} (${facts}).`,\n });\n if (difference === undefined) return decide(\"cannot decide\", \"the A/A arm does not have the case\");\n if (interval.coverage < level || aaCoverage < level) return decide(\"cannot decide\", `an arm has too few rounds for the level ${level}`);\n if (difference > maxDifference) return decide(\"cannot decide\", `the A/A difference is above ${maxDifference}`);\n if (interval.high <= limit) return decide(\"within\", \"the interval is at or below the limit\");\n if (interval.low > limit) return decide(\"beyond\", \"the interval is above the limit\");\n return decide(\"cannot decide\", \"the interval holds the limit\");\n}\n\n/**\n * This function gives the verdict of the claim \"the median of each case is at most `limit`\". The arm `aa` is a second\n * arm of the same build, and it shows the noise of the run as a difference. Values of 0 are valid.\n * - A case is `cannot decide` when the A/A arm does not have it, or when an arm has too few rounds for the level.\n * - A case is also `cannot decide` when the medians of the two arms differ by more than `maxDifference`.\n * - Other cases are `within` when the high end of the interval is at most the limit.\n * - They are `beyond` when the low end of the interval is above the limit.\n * - The verdict is `beyond` when a case is `beyond`, and `within` when each case is `within`.\n * - Each other verdict is `cannot decide`, and so is a verdict with no cases.\n */\nexport function budgetVerdict(rounds: readonly BudgetRound[], aa: readonly BudgetRound[], options: BudgetOptions): BudgetVerdict {\n const { limit, maxDifference } = options;\n const level = options.caseLevel ?? 0.95;\n if (!(limit >= 0 && Number.isFinite(limit))) throw new RangeError(`budgetVerdict: the limit is finite and 0 or more, not ${limit}.`);\n if (!(maxDifference >= 0 && Number.isFinite(maxDifference))) throw new RangeError(`budgetVerdict: the largest difference is finite and 0 or more, not ${maxDifference}.`);\n const values = valuesOfCases(\"the rounds\", rounds);\n const aaValues = valuesOfCases(\"the A/A arm\", aa);\n const cases = [...values.keys()].sort().map((name) => caseBudget(name, values.get(name) ?? [], aaValues.get(name) ?? [], options, level));\n return verdictOf(cases, { limit, maxDifference, level });\n}\n\n/** This function gives the verdict of a list of case verdicts. */\nfunction verdictOf(cases: readonly CaseBudget[], claim: Pick<BudgetVerdict, \"limit\" | \"maxDifference\" | \"level\">): BudgetVerdict {\n const facts = { ...claim, cases };\n if (cases.length === 0) return { outcome: \"cannot decide\", reason: \"The verdict has no cases.\", ...facts };\n const first = cases.find((c) => c.outcome === \"beyond\") ?? cases.find((c) => c.outcome === \"cannot decide\");\n if (first === undefined) {\n const top = cases.reduce((a, b) => (b.high > a.high ? b : a));\n return { outcome: \"within\", reason: `Each of the ${cases.length} cases is within. The largest is this one: ${top.reason}`, ...facts };\n }\n const count = cases.filter((c) => c.outcome === first.outcome).length;\n return { outcome: first.outcome, reason: `${count} of ${cases.length} cases have this outcome. The first is this one: ${first.reason}`, ...facts };\n}\n\n/** One look of a budget with looks: the rounds of each arm, and the level of the interval at those rounds. */\nexport interface BudgetLook {\n readonly rounds: number;\n readonly level: number;\n}\n\n/**\n * These looks start with 6 rounds, as `budgetVerdict` does, and they stop at 24. The three looks spend 0.0442 of the\n * overall 0.05. On the blocking times of a noisy web page, 97% of the runs with a median 16% under the limit stop by 24.\n */\nexport const BUDGET_LOOKS: readonly BudgetLook[] = [\n { rounds: 6, level: 0.95 },\n { rounds: 12, level: 0.99 },\n { rounds: 24, level: 0.99 },\n];\n\n/** The options of a budget verdict with looks. */\nexport interface BudgetLooksOptions {\n /** The largest median that the claim permits, in the unit of the values. */\n readonly limit: number;\n /** The largest difference between the medians of the two arms of the same build. */\n readonly maxDifference: number;\n /** The looks, with the rounds in rising order. The default is `BUDGET_LOOKS`. */\n readonly looks?: readonly BudgetLook[];\n /** The level over all looks of one case. The default is 0.95. */\n readonly level?: number;\n}\n\n/** The next look of one case: the rounds that each arm of the case needs. */\nexport interface BudgetMore {\n readonly case: string;\n readonly rounds: number;\n}\n\n/** A budget verdict with looks. The field `level` is the level over all looks. */\nexport interface BudgetLooksVerdict extends BudgetVerdict {\n /** The chance of error that the looks spend: the sum of 1 - coverage over the looks. */\n readonly spent: number;\n /** The cases with no outcome that can have another look. The list is empty when the verdict is final. */\n readonly more: readonly BudgetMore[];\n /** True only when the interval of a case is above the limit. A case with no outcome at the last look does not fail. */\n readonly fails: boolean;\n}\n\n/**\n * This function gives the chance of error that a list of looks spends: the sum of 1 - coverage of each look. This sum is\n * the Bonferroni bound over the looks. A look that has too few rounds for its level gives a `RangeError`.\n */\nexport function budgetLookSpend(looks: readonly BudgetLook[]): number {\n if (looks.length === 0) throw new RangeError(\"budgetLookSpend: the list of looks is empty.\");\n let spent = 0;\n let last = 0;\n for (const { rounds, level } of looks) {\n if (!(Number.isInteger(rounds) && rounds > last)) throw new RangeError(`budgetLookSpend: the rounds of the looks are whole numbers in rising order, not ${rounds} after ${last}.`);\n const { coverage } = medianInterval(\n Array.from({ length: rounds }, (_, i) => i),\n level,\n );\n if (coverage < level) throw new RangeError(`budgetLookSpend: ${rounds} rounds are too few for the level ${level}.`);\n spent += 1 - coverage;\n last = rounds;\n }\n return spent;\n}\n\n/** This function gives the outcome of one case: the first look with an outcome, or the last look that the rounds reach. */\nfunction caseAtLooks(name: string, values: readonly number[], aaValues: readonly number[], options: BudgetOptions, looks: readonly BudgetLook[]): { verdict: CaseBudget; next: number | undefined } {\n let verdict: CaseBudget | undefined;\n for (const { rounds, level } of looks) {\n if (values.length < rounds || aaValues.length < rounds) {\n return { verdict: verdict ?? caseBudget(name, values, aaValues, options, level), next: rounds };\n }\n verdict = caseBudget(name, values.slice(0, rounds), aaValues.slice(0, rounds), options, level);\n if (verdict.outcome !== \"cannot decide\") return { verdict, next: undefined };\n }\n return { verdict: verdict as CaseBudget, next: undefined };\n}\n\n/**\n * This function gives the budget verdict of a run that adds rounds. A caller gives all rounds so far, and it gets a\n * verdict and the field `more`. It adds the rounds of `more` to both arms, and it calls the function again.\n *\n * The chance of error of one look is 1 - coverage. The coverage is 1 - 2 P(X <= k - 1), for X ~ Binomial(n, 1/2) and\n * the rank k of the interval. The nominal level does not give this chance. The default looks have these figures:\n *\n * | Rounds n | Level | Rank k | Coverage | Chance of error |\n * | ---: | ---: | ---: | ---: | ---: |\n * | 6 | 0.95 | 1 | 0.96875 | 0.03125 |\n * | 12 | 0.99 | 2 | 0.99365 | 0.00635 |\n * | 24 | 0.99 | 6 | 0.99339 | 0.00661 |\n * | Sum | | | | 0.04421 |\n *\n * The sum is the Bonferroni bound over the looks. Each coverage needs independent rounds. Rounds with a shared cause, for\n * example a slow computer for one run, do not have that coverage.\n *\n * - The first look of a case with an outcome decides the case. Later rounds do not change it.\n * - Each look reads the rounds of that look in the order of their numbers. Thus a verdict comes again from its records.\n * - A sum of `budgetLookSpend` above 1 - `level` gives a `RangeError`, because many looks at one level spend too much.\n * - The field `fails` is true only for the outcome `beyond`. Tell a final `cannot decide` to the reader of the run.\n */\nexport function budgetLooksVerdict(rounds: readonly BudgetRound[], aa: readonly BudgetRound[], options: BudgetLooksOptions): BudgetLooksVerdict {\n const { limit, maxDifference } = options;\n const looks = options.looks ?? BUDGET_LOOKS;\n const level = options.level ?? 0.95;\n const spent = budgetLookSpend(looks);\n if (spent > 1 - level) throw new RangeError(`budgetLooksVerdict: the looks spend ${round(spent)}, over the ${round(1 - level)} of the level ${level}.`);\n if (!(limit >= 0 && Number.isFinite(limit))) throw new RangeError(`budgetLooksVerdict: the limit is finite and 0 or more, not ${limit}.`);\n if (!(maxDifference >= 0 && Number.isFinite(maxDifference))) throw new RangeError(`budgetLooksVerdict: the largest difference is finite and 0 or more, not ${maxDifference}.`);\n const byRound = (list: readonly BudgetRound[]): BudgetRound[] => [...list].sort((a, b) => a.round - b.round);\n const values = valuesOfCases(\"the rounds\", byRound(rounds));\n const aaValues = valuesOfCases(\"the A/A arm\", byRound(aa));\n const results = [...values.keys()].sort().map((name) => ({ name, ...caseAtLooks(name, values.get(name) ?? [], aaValues.get(name) ?? [], { limit, maxDifference }, looks) }));\n const verdict = verdictOf(\n results.map((r) => r.verdict),\n { limit, maxDifference, level },\n );\n const more = results.flatMap((r) => (r.next === undefined ? [] : [{ case: r.name, rounds: r.next }]));\n return { ...verdict, spent, more, fails: verdict.cases.some((c) => c.outcome === \"beyond\") };\n}\n\nfunction round(x: number): number {\n return Math.round(x * 10_000) / 10_000;\n}\n","/**\n * The gate of a bench: the result that a check of a merge reads. A verdict gives one of the words of `LimitOutcome` for each\n * case, and the gate gives \"pass\", \"block\" or \"no read\". A case with no outcome does not pass.\n */\nimport { holm, median, partialConjunction, signTest } from \"@mark1russell7/rigor-statistics\";\nimport type { BudgetMore } from \"./budget.ts\";\nimport type { LimitOutcome } from \"./limit.ts\";\nimport type { JobRecords } from \"./merge.ts\";\nimport { type Arm, type PairedTime, checkPairedTime } from \"./paired.ts\";\n\n/** The three results of a gate. */\nexport type GateOutcome = \"pass\" | \"block\" | \"no read\";\n\n/** The fields of a case that a gate reads. The cases of `limitVerdict`, `budgetVerdict` and the verdict of this file have them. */\nexport interface GateCaseOutcome {\n readonly case: string;\n readonly outcome: LimitOutcome;\n}\n\n/** The result of a gate, with the cases that make it. */\nexport interface Gate {\n readonly outcome: GateOutcome;\n /** The reason of the result, in one sentence. */\n readonly reason: string;\n /** The cases with the outcome `beyond`. */\n readonly blocks: readonly string[];\n /** The cases with the outcome `cannot decide`. */\n readonly noRead: readonly string[];\n}\n\n/**\n * This function gives the gate of a list of case outcomes.\n * - The result is \"block\" when a case is `beyond`.\n * - The result is \"pass\" when each case is `within`.\n * - Each other result is \"no read\", and so is a list with no cases. A caller does not count \"no read\" as a pass.\n */\nexport function gateOf(cases: readonly GateCaseOutcome[]): Gate {\n const names = (outcome: LimitOutcome): string[] => cases.filter((c) => c.outcome === outcome).map((c) => c.case);\n const blocks = names(\"beyond\");\n const noRead = names(\"cannot decide\");\n if (cases.length === 0) return { outcome: \"no read\", reason: \"The gate has no cases.\", blocks, noRead };\n if (blocks.length > 0) return { outcome: \"block\", reason: `${blocks.length} of ${cases.length} cases are beyond the claim. The first is ${JSON.stringify(blocks[0])}.`, blocks, noRead };\n if (noRead.length > 0) return { outcome: \"no read\", reason: `${noRead.length} of ${cases.length} cases have no outcome. The first is ${JSON.stringify(noRead[0])}.`, blocks, noRead };\n return { outcome: \"pass\", reason: `Each of the ${cases.length} cases is within the claim.`, blocks, noRead };\n}\n\n/** The word of a case for the claim \"not slower by more than the margin\". The word \"not slower\" is apart from `same` of `timeVerdict`. */\nexport type NotSlowerRead = \"not slower\" | \"slower\" | \"no read\";\n\nconst READ_OF: Record<LimitOutcome, NotSlowerRead> = { within: \"not slower\", beyond: \"slower\", \"cannot decide\": \"no read\" };\n\n/** The looks of `notSlowerVerdict`: the rounds in each job. The level of the family has an equal share at each look. */\nexport const GATE_LOOKS: readonly number[] = [12, 24, 48];\n\n/** The options of `notSlowerVerdict`. */\nexport interface NotSlowerOptions {\n /** The margin of each case on a log scale: a number, or a function of the name of the case. */\n readonly margin: number | ((name: string) => number);\n /** The chance of a false \"not slower\", and apart from it the chance of a false \"slower\", over the family and all looks. The default is 0.05. */\n readonly level?: number;\n /** The looks: even whole numbers in rising order. The default is `GATE_LOOKS`. */\n readonly looks?: readonly number[];\n /** The count of jobs that each need the bound. The default is 2, because more rounds do not remove a difference between jobs. */\n readonly jobs?: number;\n}\n\n/** The read of one case in one job, at one look. */\nexport interface GateJobRead {\n readonly job: string;\n /** The pairs of rounds that the look uses. Below the rounds of the look, the job has not reached the look. */\n readonly rounds: number;\n /** The count of pairs with a difference below the margin. */\n readonly below: number;\n /** The count of pairs with a difference above the margin. */\n readonly above: number;\n /** The one-sided p of the sign test of the claim \"the median difference is below the margin\". */\n readonly notSlower: number;\n /** The one-sided p of the sign test of the claim \"the median difference is above the margin\". */\n readonly slower: number;\n /** The median of the differences, or undefined when the job has not reached the look. */\n readonly centre: number | undefined;\n}\n\n/** The verdict of one case. */\nexport interface CaseGate extends GateCaseOutcome {\n readonly read: NotSlowerRead;\n readonly margin: number;\n /** The rounds of the look that decides the case, or undefined when the case has no outcome. */\n readonly look: number | undefined;\n /** The reads of each job, at the look that decides the case, or else at the last look that a job reached. */\n readonly jobs: readonly GateJobRead[];\n /** The reason of the outcome, in one sentence. */\n readonly reason: string;\n}\n\n/** The gate of the claim \"not slower by more than the margin\", with the facts that it uses. */\nexport interface NotSlowerVerdict extends Gate {\n readonly level: number;\n readonly looks: readonly number[];\n /** The count of jobs that each need the bound. */\n readonly need: number;\n readonly cases: readonly CaseGate[];\n /** The cases with no outcome that can have another look. The list is empty when the verdict is final. */\n readonly more: readonly BudgetMore[];\n}\n\n/** This function examines the options. */\nfunction checkOptions(level: number, looks: readonly number[], need: number): void {\n if (!(level > 0 && level < 1)) throw new RangeError(`notSlowerVerdict: the level is above 0 and below 1, not ${level}.`);\n if (looks.length === 0) throw new RangeError(\"notSlowerVerdict: the list of looks is empty.\");\n let last = 0;\n for (const rounds of looks) {\n if (!(Number.isInteger(rounds) && rounds > last && rounds % 2 === 0)) throw new RangeError(`notSlowerVerdict: the looks are even whole numbers in rising order, not ${rounds} after ${last}.`);\n last = rounds;\n }\n if (!(Number.isInteger(need) && need >= 1)) throw new RangeError(`notSlowerVerdict: the count of jobs is a whole number of 1 or more, not ${need}.`);\n}\n\n/** This function gives the records of one case of one job in the order of the rounds. It refuses a round that comes twice. */\nfunction casesOf(records: readonly PairedTime[]): Map<string, PairedTime[]> {\n const out = new Map<string, PairedTime[]>();\n for (const record of records) {\n checkPairedTime(record);\n const list = out.get(record.case) ?? [];\n if (list.some((r) => r.round === record.round)) throw new RangeError(`notSlowerVerdict: the round ${record.round} of ${JSON.stringify(record.case)} comes twice.`);\n list.push(record);\n out.set(record.case, list);\n }\n for (const list of out.values()) list.sort((a, b) => a.round - b.round);\n return out;\n}\n\n/**\n * This function gives the differences of the first `rounds` rounds: log(b / a) of the candidate minus log(b / a) of the A/A arm.\n * A pair has two records with the same first arm, because a difference of two orders holds the effect of the order.\n */\nfunction differences(candidate: readonly PairedTime[], aa: readonly PairedTime[], rounds: number): number[] {\n const out: number[] = [];\n const ofOrder = (list: readonly PairedTime[], first: Arm): PairedTime[] => list.slice(0, rounds).filter((r) => r.first === first);\n for (const first of [\"a\", \"b\"] as const) {\n const left = ofOrder(candidate, first);\n const right = ofOrder(aa, first);\n for (let i = 0; i < Math.min(left.length, right.length); i++) {\n const c = left[i] as PairedTime;\n const a = right[i] as PairedTime;\n out.push(Math.log(c.b / c.a) - Math.log(a.b / a.a));\n }\n }\n return out;\n}\n\n/** This function gives the read of one job. A job that has not reached the look gives a p of 1 in both directions. */\nfunction jobRead(job: string, diffs: readonly number[], margin: number, rounds: number): GateJobRead {\n if (diffs.length < rounds) return { job, rounds: diffs.length, below: 0, above: 0, notSlower: 1, slower: 1, centre: undefined };\n const below = diffs.filter((d) => d < margin).length;\n const above = diffs.filter((d) => d > margin).length;\n // A difference equal to the margin counts against each claim.\n return { job, rounds: diffs.length, below, above, notSlower: signTest(below, diffs.length - below), slower: signTest(above, diffs.length - above), centre: median(diffs) };\n}\n\n/** This function gives the words of the facts of one job, for a reason. */\nfunction jobFacts(read: GateJobRead): string {\n if (read.centre === undefined) return `job ${read.job} has ${read.rounds} pairs`;\n return `job ${read.job} has ${read.below} of ${read.rounds} pairs below the margin, centre ${Math.round(read.centre * 100_000) / 1000} %`;\n}\n\n/**\n * This function gives the gate of the claim \"the candidate is not slower than the A/A arm by more than the margin\" for each\n * case. A one-sided bound answers the claim. Thus a case with its whole interval under the margin reads \"not slower\", also\n * when its interval holds 1.\n *\n * - In each job, the sign test compares the median of the differences with the margin. It uses no random numbers.\n * - A case reads in `jobs` jobs or more: `partialConjunction` joins the p of each job, with no condition on how they depend.\n * - The level is for the family. Each look has `level / looks` of it, and `holm` corrects each look over all cases.\n * - The first look with an outcome decides a case. Later rounds do not change it. Each look uses the first rounds of a job.\n * - The result is \"block\" when a case reads \"slower\", and \"pass\" when each case reads \"not slower\".\n * - Each other result is \"no read\". The field `more` gives the next look of each case. After the last look, the caller adds jobs.\n *\n * The level needs independent rounds. Rounds with a shared cause, for example a slow computer for one job, do not have it.\n * A job that a caller adds after the last look is one more look, and the level does not count it.\n */\nexport function notSlowerVerdict(jobs: readonly JobRecords[], options: NotSlowerOptions): NotSlowerVerdict {\n const level = options.level ?? 0.05;\n const looks = options.looks ?? GATE_LOOKS;\n const need = options.jobs ?? 2;\n checkOptions(level, looks, need);\n const marginOf = (name: string): number => {\n const margin = typeof options.margin === \"number\" ? options.margin : options.margin(name);\n if (!(margin >= 0 && Number.isFinite(margin))) throw new RangeError(`notSlowerVerdict: the margin of ${JSON.stringify(name)} is finite and 0 or more, not ${margin}.`);\n return margin;\n };\n const records = jobs.map((job) => ({ job: job.job, candidate: casesOf(job.candidate), aa: casesOf(job.aa) }));\n const names = [...new Set(records.flatMap((job) => [...job.candidate.keys()]))].sort();\n const margins = names.map(marginOf);\n const decided = new Map<string, { outcome: LimitOutcome; look: number; reads: readonly GateJobRead[] }>();\n const reached = new Map<string, readonly GateJobRead[]>();\n const each = level / looks.length;\n for (const rounds of looks) {\n const reads = names.map((name, i) => records.map((job) => jobRead(job.job, differences(job.candidate.get(name) ?? [], job.aa.get(name) ?? [], rounds), margins[i] as number, rounds)));\n const joined = (pick: (read: GateJobRead) => number): number[] => reads.map((list) => (list.length < need ? 1 : partialConjunction(list.map(pick), need)));\n const within = holm(joined((read) => read.notSlower), each);\n const beyond = holm(joined((read) => read.slower), each);\n names.forEach((name, i) => {\n const list = reads[i] as GateJobRead[];\n if (!reached.has(name) || list.some((read) => read.rounds >= rounds)) reached.set(name, list);\n if (decided.has(name)) return;\n if (within[i]?.reject === true) decided.set(name, { outcome: \"within\", look: rounds, reads: list });\n else if (beyond[i]?.reject === true) decided.set(name, { outcome: \"beyond\", look: rounds, reads: list });\n });\n }\n const cases = names.map((name, i): CaseGate => {\n const decision = decided.get(name);\n const outcome = decision?.outcome ?? \"cannot decide\";\n const reads = decision?.reads ?? reached.get(name) ?? [];\n const facts = reads.map(jobFacts).join(\", \");\n const where = decision === undefined ? `no look of ${looks.join(\", \")} rounds decides it` : `the look of ${decision.look} rounds decides it`;\n return { case: name, outcome, read: READ_OF[outcome], margin: margins[i] as number, look: decision?.look, jobs: reads, reason: `The case ${JSON.stringify(name)} reads \"${READ_OF[outcome]}\": ${where} (${facts}).` };\n });\n const more = cases.flatMap((c): BudgetMore[] => {\n if (c.outcome !== \"cannot decide\") return [];\n const next = looks.find((rounds) => records.some((job) => differences(job.candidate.get(c.case) ?? [], job.aa.get(c.case) ?? [], rounds).length < rounds));\n return next === undefined ? [] : [{ case: c.case, rounds: next }];\n });\n return { ...gateOf(cases), level, looks, need, cases, more };\n}\n","/**\n * The load factor of a run, read from a control. Runs on shared machines differ by load. A change does not touch a control.\n * So the change of its time between two groups measures the machine and not the code.\n * The groups can be two runs, or the shards of one run.\n */\nimport { median, quantile } from \"@mark1russell7/rigor-statistics\";\n\n/** One time of the control in one group. */\nexport interface ControlRow {\n /** The name of the group: a run, or a shard of one run. */\n readonly group: string;\n /** The name of a class of work. The same key in two groups names equal work, so a ratio of the two measures the load. */\n readonly key: string;\n /** The time. It is finite and more than 0. */\n readonly value: number;\n /** This field is true when the run stopped the case at `value`. Thus the real time is at least `value`. */\n readonly censored?: boolean;\n}\n\n/** The options of `controlFactor`. */\nexport interface ControlOptions {\n /** The group that the factors compare with. Without it, the base of each key is the median of that key over the groups. */\n readonly base?: string;\n /** The least number of keys in a factor. A group with fewer keys has no factor. The default is 5. */\n readonly minPairs?: number;\n}\n\n/** The counts of one group, with or without a factor. */\nexport interface GroupCounts {\n readonly group: string;\n /** The number of keys that the factor reads. */\n readonly pairs: number;\n /** The number of keys that this function left out because a time of the key was censored. The factor reads low when this count is not 0. */\n readonly censored: number;\n /** The number of keys of this group that have no time to compare with, so no ratio reads them. */\n readonly unshared: number;\n}\n\n/** The factor of one group. */\nexport interface MeasuredFactor extends GroupCounts {\n /** The median ratio of the times of this group over the base. A factor of 1.6 means that this group took 1.6 times as long. */\n readonly factor: number;\n /** The quartiles of the ratios. A wide spread means that one factor does not explain the load. */\n readonly low: number;\n readonly high: number;\n}\n\n/** A group with too few usable keys. It has no factor, and the other groups keep theirs. */\nexport interface NoFactor extends GroupCounts {\n readonly factor: undefined;\n /** The reason that this group has no factor. */\n readonly reason: string;\n}\n\n/** The result of one group. Read `factor` first: a group with too few usable keys has no factor. */\nexport type GroupFactor = MeasuredFactor | NoFactor;\n\n/** The factors of a run, with the base that they use. */\nexport interface ControlFactors {\n /** The base group, or undefined when the base of each key is its median over the groups. */\n readonly base: string | undefined;\n readonly factors: readonly GroupFactor[];\n}\n\nconst DEFAULT_MIN_PAIRS = 5;\n\nfunction checkedRows(rows: readonly ControlRow[]): Map<string, Map<string, ControlRow>> {\n const groups = new Map<string, Map<string, ControlRow>>();\n for (const r of rows) {\n if (!(Number.isFinite(r.value) && r.value > 0)) throw new RangeError(`controlFactor: the value of ${JSON.stringify(r.key)} in ${JSON.stringify(r.group)} is finite and more than 0, not ${r.value}.`);\n const group = groups.get(r.group) ?? new Map<string, ControlRow>();\n if (group.has(r.key)) throw new RangeError(`controlFactor: the key ${JSON.stringify(r.key)} comes twice in ${JSON.stringify(r.group)}.`);\n group.set(r.key, r);\n groups.set(r.group, group);\n }\n return groups;\n}\n\nfunction factorOf(group: string, ratios: readonly number[], censored: number, unshared: number, minPairs: number): GroupFactor {\n const counts = { group, pairs: ratios.length, censored, unshared };\n if (ratios.length < minPairs) return { ...counts, factor: undefined, reason: `the group ${JSON.stringify(group)} has ${ratios.length} usable keys, and the least is ${minPairs}.` };\n return { ...counts, factor: median(ratios), low: quantile(ratios, 0.25), high: quantile(ratios, 0.75) };\n}\n\n/** This function refuses a result with no factor at all, because such a result measures nothing. */\nfunction withFactors(base: string | undefined, factors: readonly GroupFactor[]): ControlFactors {\n if (factors.every((f) => f.factor === undefined)) {\n const thin = factors.find((f): f is NoFactor => f.factor === undefined);\n throw new RangeError(`controlFactor: no group has a factor: ${thin?.reason ?? \"the rows hold no group to compare.\"}`);\n }\n return { base, factors };\n}\n\n/** This function gives the factors over one base group. Each factor reads the keys that the two groups share. */\nfunction againstGroup(groups: Map<string, Map<string, ControlRow>>, base: string, minPairs: number): ControlFactors {\n const baseRows = groups.get(base);\n if (baseRows === undefined) throw new RangeError(`controlFactor: the base ${JSON.stringify(base)} is not a group of the rows.`);\n const factors: GroupFactor[] = [];\n for (const [group, rows] of groups) {\n if (group === base) continue;\n const ratios: number[] = [];\n let censored = 0;\n let unshared = 0;\n for (const [key, r] of rows) {\n const b = baseRows.get(key);\n if (b === undefined) unshared += 1;\n else if (r.censored === true || b.censored === true) censored += 1;\n else ratios.push(r.value / b.value);\n }\n factors.push(factorOf(group, ratios, censored, unshared, minPairs));\n }\n return withFactors(base, factors);\n}\n\n/**\n * This function gives the factors over the median of each key, as one run grouped by shard needs.\n * Each group holds a different mix of work, so a time compares only with the times of the same key. A key in one group has nothing to compare with.\n */\nfunction againstKeys(groups: Map<string, Map<string, ControlRow>>, minPairs: number): ControlFactors {\n const clean = new Map<string, number[]>();\n for (const rows of groups.values()) {\n for (const [key, r] of rows) if (r.censored !== true) clean.set(key, [...(clean.get(key) ?? []), r.value]);\n }\n const factors = [...groups].map(([group, rows]) => {\n const ratios: number[] = [];\n let censored = 0;\n let unshared = 0;\n for (const [key, r] of rows) {\n const times = clean.get(key) ?? [];\n if (r.censored === true) censored += 1;\n else if (times.length >= 2) ratios.push(r.value / median(times));\n else unshared += 1;\n }\n return factorOf(group, ratios, censored, unshared, minPairs);\n });\n return withFactors(undefined, factors);\n}\n\n/**\n * This function gives the load factor of each group from the times of a control.\n *\n * With `base`, a factor compares the keys that a group shares with that group. Without it, a factor compares each time with the median of its key over the groups.\n * A key names a class of work, so equal keys in two groups mean equal work. Each group has at most one row for a key.\n *\n * A censored time is only a lower limit, so no ratio reads it, and the result counts those keys. A run stops its slowest cases, so a factor reads low when `censored` is not 0.\n *\n * A group with too few usable keys gets an entry with no factor and its reason, so the other groups keep their factors. This function refuses a result where no group has a factor.\n */\nexport function controlFactor(rows: readonly ControlRow[], options: ControlOptions = {}): ControlFactors {\n const minPairs = options.minPairs ?? DEFAULT_MIN_PAIRS;\n if (!(Number.isInteger(minPairs) && minPairs >= 1)) throw new RangeError(`controlFactor: minPairs is a whole number of 1 or more, not ${minPairs}.`);\n const groups = checkedRows(rows);\n return options.base === undefined ? againstKeys(groups, minPairs) : againstGroup(groups, options.base, minPairs);\n}\n","/**\n * The scale ladder of a product, as data. A ladder has rungs at sizes that grow, for example 1, 10 and 100 tenants. Each\n * rung has budgets, and it names the test that holds it. A rung is held only when a record of that test shows each budget\n * `within`. A number in a document is not a rung.\n */\nimport { quantile, quantileInterval, quantileSamples, wilson } from \"@mark1russell7/rigor-statistics\";\nimport { type BudgetOutcome, type BudgetRound, budgetVerdict } from \"./budget.ts\";\n\n/** The format name of a ladder. It changes when a reader of an older form cannot read the data. */\nexport const LADDER_FORMAT = \"rigor-ladder/1\";\n\n/** One dimension of a ladder, for example tenants or nodes. */\nexport interface LadderDimension {\n readonly name: string;\n /** What one unit of the dimension is, in plain words. */\n readonly describe: string;\n}\n\n/** A budget on the median of each case, for example the time of a read. A record gives rounds and an A/A arm. */\nexport interface MedianBudget {\n readonly kind: \"median\";\n readonly measure: string;\n /** The unit of the limit and of the values. */\n readonly unit: string;\n /** The largest median that the budget permits. */\n readonly limit: number;\n /** The largest difference between the medians of the two arms. A larger difference makes the run too noisy. */\n readonly maxDifference: number;\n /** The level of the interval of each median. The default is 0.95. */\n readonly caseLevel?: number;\n}\n\n/** A budget on the share of failed trials, for example failed requests. A record gives failures and trials. */\nexport interface RateBudget {\n readonly kind: \"rate\";\n readonly measure: string;\n /** The largest share of failures that the budget permits, from 0 to 1. */\n readonly limit: number;\n}\n\n/** A budget on the largest value of a set of drills, for example the writes that a restore lost. One bad drill is `beyond`. */\nexport interface WorstBudget {\n readonly kind: \"worst\";\n readonly measure: string;\n readonly unit: string;\n /** The largest value that the budget permits in any drill. */\n readonly limit: number;\n /** The number of drills that a verdict needs, 1 or more. With fewer, the budget is `cannot decide`. */\n readonly minDrills: number;\n}\n\n/**\n * A budget on a high quantile, for example the p99 of a read. A record gives the values. The verdict is the distribution-free\n * interval of the quantile against the limit. A p99 needs 368 independent values at the level 0.95: refer to `quantileSamples`.\n * Successive times of one run can follow each other. Space them apart, or give one value for each run.\n *\n * The evidence can also hold `censored`: a lower bound for each arrival with no reply, and for each arrival that was not\n * sent. The bound is the time that the arrival waited. The true value is that bound or more, with no upper limit. Thus the\n * low end of the interval reads the bounds, and the high end reads each censored value as `Infinity`. A `beyond` stays\n * provable from the bounds alone. A `within` needs real replies up to the upper rank of the interval.\n */\nexport interface QuantileBudget {\n readonly kind: \"quantile\";\n readonly measure: string;\n /** The unit of the limit and of the values. */\n readonly unit: string;\n /** The quantile, more than 0 and less than 1, for example 0.99. */\n readonly quantile: number;\n /** The largest quantile that the budget permits. */\n readonly limit: number;\n /** The level of the interval. The default is 0.95. */\n readonly level?: number;\n}\n\n/** One budget of a rung. */\nexport type RungBudget = MedianBudget | QuantileBudget | RateBudget | WorstBudget;\n\n/** One rung of a ladder. */\nexport interface Rung {\n /** The name of the rung, unique in the ladder. */\n readonly name: string;\n /** The size of the rung in each dimension that it names. */\n readonly at: Readonly<Record<string, number>>;\n readonly budgets: readonly RungBudget[];\n /** The name of the automatic test that holds the rung. */\n readonly test: string;\n /** True when a gate holds the rung: the verdict fails when the rung is not `within`. */\n readonly locked?: boolean;\n}\n\n/** The ladder of one subject. The rungs go from the smallest to the largest. */\nexport interface Ladder {\n readonly format: typeof LADDER_FORMAT;\n /** The product or the service that the ladder is for. */\n readonly subject: string;\n readonly dimensions: readonly LadderDimension[];\n readonly rungs: readonly Rung[];\n}\n\n/** The measured evidence for one budget. Its `kind` is the kind of the budget. */\nexport type RungEvidence =\n | { readonly kind: \"median\"; readonly measure: string; readonly rounds: readonly BudgetRound[]; readonly aa: readonly BudgetRound[] }\n | { readonly kind: \"quantile\"; readonly measure: string; readonly values: readonly number[]; readonly censored?: readonly number[] }\n | { readonly kind: \"rate\"; readonly measure: string; readonly failures: number; readonly trials: number }\n | { readonly kind: \"worst\"; readonly measure: string; readonly values: readonly number[] };\n\n/** One run of the test of a rung. */\nexport interface RungRecord {\n /** The name of the rung. */\n readonly rung: string;\n /** The commit that the run measured. */\n readonly commit: string;\n /** The time of the run, as an ISO 8601 string. */\n readonly at: string;\n /** What the run did for real, for example \"2 processes\" or \"a restore from a real backup\". */\n readonly real: readonly string[];\n /** What the run made up, for example \"90 % of the tenants as data at rest\". An empty list states that nothing was synthetic. */\n readonly synthetic: readonly string[];\n readonly evidence: readonly RungEvidence[];\n}\n\n/** The verdict of one budget of a rung. */\nexport interface BudgetResult {\n readonly measure: string;\n readonly outcome: BudgetOutcome;\n /** The reason of the outcome, in one sentence, with the numbers. */\n readonly reason: string;\n}\n\n/** The verdict of one rung. */\nexport interface RungVerdict {\n readonly rung: string;\n readonly test: string;\n readonly locked: boolean;\n readonly outcome: BudgetOutcome;\n /** The reason of the outcome, in one sentence. */\n readonly reason: string;\n readonly budgets: readonly BudgetResult[];\n /** The commit of the record, or undefined when the rung has no record. */\n readonly commit: string | undefined;\n readonly real: readonly string[];\n readonly synthetic: readonly string[];\n}\n\n/** The verdict of a ladder. */\nexport interface LadderVerdict {\n readonly subject: string;\n /** The highest rung with each rung up to it `within`, or undefined when the first rung is not `within`. */\n readonly held: string | undefined;\n /** The first rung that is not `within`, or undefined when each rung is `within`. */\n readonly next: string | undefined;\n /** True when a locked rung is not `within`. A rung with no result is not held, so `cannot decide` fails too. */\n readonly failed: boolean;\n /** The reason of `failed`, in one sentence. */\n readonly reason: string;\n readonly rungs: readonly RungVerdict[];\n}\n\n/** The options of a ladder verdict. */\nexport interface LadderOptions {\n /** The time of the verdict, as an ISO 8601 string. It is an input, so that a verdict is the same at each read. */\n readonly now: string;\n /** The largest age of a record, in days. An older record gives `cannot decide`. The default accepts any age. */\n readonly maxAgeDays?: number;\n}\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\n/** This function gives the problems of one budget. */\nfunction budgetProblems(where: string, budget: RungBudget): string[] {\n const out: string[] = [];\n const name = `${where}, budget ${JSON.stringify(budget.measure)}`;\n if (budget.measure.trim() === \"\") out.push(`${where}: a budget has no measure.`);\n if (!(Number.isFinite(budget.limit) && budget.limit >= 0)) out.push(`${name}: the limit is finite and 0 or more, not ${budget.limit}.`);\n if (budget.kind === \"rate\" && budget.limit > 1) out.push(`${name}: a rate limit is at most 1, not ${budget.limit}.`);\n if (budget.kind === \"median\" && !(Number.isFinite(budget.maxDifference) && budget.maxDifference >= 0)) {\n out.push(`${name}: the largest difference is finite and 0 or more, not ${budget.maxDifference}.`);\n }\n if (budget.kind === \"worst\" && !(Number.isInteger(budget.minDrills) && budget.minDrills >= 1)) {\n out.push(`${name}: the number of drills is a whole number of 1 or more, not ${budget.minDrills}.`);\n }\n if (budget.kind === \"quantile\" && !(budget.quantile > 0 && budget.quantile < 1)) out.push(`${name}: a quantile is more than 0 and less than 1, not ${budget.quantile}.`);\n if (budget.kind === \"quantile\" && budget.level !== undefined && !(budget.level > 0 && budget.level < 1)) out.push(`${name}: a level is more than 0 and less than 1, not ${budget.level}.`);\n return out;\n}\n\n/** This function gives the problems of one rung, in the order of its fields. */\nfunction rungProblems(rung: Rung, dimensions: ReadonlySet<string>): string[] {\n const where = `The rung ${JSON.stringify(rung.name)}`;\n const out: string[] = [];\n const names = Object.keys(rung.at);\n if (names.length === 0) out.push(`${where} names no dimension.`);\n for (const name of names) {\n if (!dimensions.has(name)) out.push(`${where} names the unknown dimension ${JSON.stringify(name)}.`);\n const size = rung.at[name];\n if (!(typeof size === \"number\" && Number.isFinite(size) && size > 0)) out.push(`${where}: the size of ${JSON.stringify(name)} is finite and above 0, not ${size}.`);\n }\n if (rung.test.trim() === \"\") out.push(`${where} names no test.`);\n if (rung.budgets.length === 0) out.push(`${where} has no budgets.`);\n const measures = new Set<string>();\n for (const budget of rung.budgets) {\n if (measures.has(budget.measure)) out.push(`${where} has two budgets of ${JSON.stringify(budget.measure)}.`);\n measures.add(budget.measure);\n out.push(...budgetProblems(where, budget));\n }\n return out;\n}\n\n/**\n * This function gives each problem of a ladder as data, or an empty list. A ladder needs a subject, one dimension or more,\n * and one rung or more. Names are unique. Each rung names a test and has budgets. From one rung to the next, each dimension\n * that the two rungs name grows.\n */\nexport function checkLadder(ladder: Ladder): readonly string[] {\n const out: string[] = [];\n if (ladder.format !== LADDER_FORMAT) out.push(`The format is ${JSON.stringify(LADDER_FORMAT)}, not ${JSON.stringify(ladder.format)}.`);\n if (ladder.subject.trim() === \"\") out.push(\"The ladder has no subject.\");\n if (ladder.dimensions.length === 0) out.push(\"The ladder has no dimensions.\");\n if (ladder.rungs.length === 0) out.push(\"The ladder has no rungs.\");\n const dimensions = new Set(ladder.dimensions.map((d) => d.name));\n if (dimensions.size !== ladder.dimensions.length) out.push(\"Two dimensions have the same name.\");\n if (new Set(ladder.rungs.map((r) => r.name)).size !== ladder.rungs.length) out.push(\"Two rungs have the same name.\");\n ladder.rungs.forEach((rung, index) => {\n out.push(...rungProblems(rung, dimensions));\n const before = ladder.rungs[index - 1];\n if (before === undefined) return;\n for (const [name, size] of Object.entries(rung.at)) {\n const low = before.at[name];\n if (low !== undefined && !(size > low)) out.push(`The rung ${JSON.stringify(rung.name)}: ${JSON.stringify(name)} does not grow from ${low} to ${size}.`);\n }\n });\n return out;\n}\n\n/** This function gives the verdict of a rate: the Wilson interval at 95 % against the limit. */\nfunction rateResult(budget: RateBudget, failures: number, trials: number): BudgetResult {\n const interval = wilson(failures, trials);\n const facts = `${failures} failures of ${trials} trials, interval ${interval.low} to ${interval.high}, limit ${budget.limit}`;\n const outcome: BudgetOutcome = trials === 0 ? \"cannot decide\" : interval.high <= budget.limit ? \"within\" : interval.low > budget.limit ? \"beyond\" : \"cannot decide\";\n return { measure: budget.measure, outcome, reason: `The measure ${JSON.stringify(budget.measure)} is \"${outcome}\" (${facts}).` };\n}\n\n/** This function gives the verdict of a set of drills: the largest value against the limit. */\nfunction worstResult(budget: WorstBudget, values: readonly number[]): BudgetResult {\n const largest = values.length === 0 ? undefined : Math.max(...values);\n const facts = `${values.length} drills, the largest ${largest ?? \"none\"} ${budget.unit}, limit ${budget.limit}`;\n const outcome: BudgetOutcome = largest !== undefined && largest > budget.limit ? \"beyond\" : values.length < budget.minDrills ? \"cannot decide\" : \"within\";\n return { measure: budget.measure, outcome, reason: `The measure ${JSON.stringify(budget.measure)} is \"${outcome}\" (${facts}, ${budget.minDrills} drills needed).` };\n}\n\n/**\n * This function gives the verdict of a quantile: its distribution-free interval against the limit. With censored values, the\n * low end reads their bounds and the high end reads them as `Infinity`. Each true sample has its interval inside that one.\n */\nfunction quantileResult(budget: QuantileBudget, values: readonly number[], censored: readonly number[]): BudgetResult {\n const level = budget.level ?? 0.95;\n const needed = quantileSamples(budget.quantile, level);\n const say = (outcome: BudgetOutcome, facts: string): BudgetResult => ({ measure: budget.measure, outcome, reason: `The measure ${JSON.stringify(budget.measure)} is \"${outcome}\" (${facts}, ${needed} values needed).` });\n const open = censored.length > 0;\n const bounds = [...values, ...censored];\n if (bounds.length === 0) return say(\"cannot decide\", `0 values, limit ${budget.limit} ${budget.unit}`);\n if (values.some((value) => Number.isNaN(value))) return say(\"cannot decide\", \"the values have a NaN\");\n if (!censored.every((value) => Number.isFinite(value))) return say(\"cannot decide\", \"a censored value is not a finite number\");\n const lowest = quantileInterval(bounds, budget.quantile, level);\n const highest = open ? quantileInterval([...values, ...censored.map(() => Infinity)], budget.quantile, level) : lowest;\n const [count, point] = open ? [`${values.length} values and ${censored.length} censored`, \"at least\"] : [`${values.length} values`, \"at\"];\n const facts = `${count}, quantile ${budget.quantile} ${point} ${quantile(bounds, budget.quantile, \"nearest-rank\")} ${budget.unit}, interval ${lowest.low} to ${highest.high}, limit ${budget.limit}`;\n return say(highest.high <= budget.limit ? \"within\" : lowest.low > budget.limit ? \"beyond\" : \"cannot decide\", facts);\n}\n\n/** This function gives the verdict of one budget from the evidence of a record. */\nfunction budgetResult(budget: RungBudget, evidence: readonly RungEvidence[]): BudgetResult {\n const found = evidence.find((e) => e.measure === budget.measure);\n const none = (why: string): BudgetResult => ({ measure: budget.measure, outcome: \"cannot decide\", reason: `The measure ${JSON.stringify(budget.measure)} is \"cannot decide\": ${why}.` });\n if (found === undefined) return none(\"the record has no evidence for it\");\n if (budget.kind === \"median\" && found.kind === \"median\") {\n const v = budgetVerdict(found.rounds, found.aa, { limit: budget.limit, maxDifference: budget.maxDifference, ...(budget.caseLevel === undefined ? {} : { caseLevel: budget.caseLevel }) });\n return { measure: budget.measure, outcome: v.outcome, reason: v.reason };\n }\n if (budget.kind === \"quantile\" && found.kind === \"quantile\") return quantileResult(budget, found.values, found.censored ?? []);\n if (budget.kind === \"rate\" && found.kind === \"rate\") return rateResult(budget, found.failures, found.trials);\n if (budget.kind === \"worst\" && found.kind === \"worst\") return worstResult(budget, found.values);\n return none(`the budget is ${budget.kind}, and the evidence is ${found.kind}`);\n}\n\n/** This function gives the reason that a record cannot decide a rung, or undefined when the record can. */\nfunction recordProblem(record: RungRecord, options: LadderOptions): string | undefined {\n if (record.real.length === 0) return \"the record does not state what was real\";\n const { maxAgeDays } = options;\n if (maxAgeDays === undefined) return undefined;\n const age = (Date.parse(options.now) - Date.parse(record.at)) / DAY_MS;\n if (!Number.isFinite(age)) return `a time does not parse: now ${options.now}, record ${record.at}`;\n return age > maxAgeDays ? `the record of ${record.at} is older than ${maxAgeDays} days` : undefined;\n}\n\n/** This function gives the outcome of a set of budgets: `beyond` first, then `cannot decide`, and `within` only when each budget is. */\nfunction worstOutcome(results: readonly BudgetResult[]): BudgetOutcome {\n if (results.some((r) => r.outcome === \"beyond\")) return \"beyond\";\n return results.length > 0 && results.every((r) => r.outcome === \"within\") ? \"within\" : \"cannot decide\";\n}\n\n/** This function gives the verdict of one rung from its record. With no record, the rung is `cannot decide`. */\nexport function rungVerdict(rung: Rung, record: RungRecord | undefined, options: LadderOptions): RungVerdict {\n const base = { rung: rung.name, test: rung.test, locked: rung.locked === true };\n if (record === undefined) {\n return { ...base, outcome: \"cannot decide\", reason: `The rung ${JSON.stringify(rung.name)} has no record of the test ${JSON.stringify(rung.test)}.`, budgets: [], commit: undefined, real: [], synthetic: [] };\n }\n const facts = { commit: record.commit, real: record.real, synthetic: record.synthetic };\n const problem = recordProblem(record, options);\n if (problem !== undefined) return { ...base, ...facts, outcome: \"cannot decide\", reason: `The rung ${JSON.stringify(rung.name)} is \"cannot decide\": ${problem}.`, budgets: [] };\n const budgets = rung.budgets.map((b) => budgetResult(b, record.evidence));\n const outcome = worstOutcome(budgets);\n const first = budgets.find((b) => b.outcome === outcome);\n return { ...base, ...facts, outcome, reason: outcome === \"within\" ? `The ${budgets.length} budgets of the rung ${JSON.stringify(rung.name)} are within.` : `The rung ${JSON.stringify(rung.name)} is \"${outcome}\". ${first?.reason ?? \"\"}`, budgets };\n}\n\n/** This function gives the newest record of each rung. It keeps the first of two records with the same time. */\nfunction newestRecords(records: readonly RungRecord[]): Map<string, RungRecord> {\n const out = new Map<string, RungRecord>();\n for (const record of records) {\n const old = out.get(record.rung);\n if (old === undefined || Date.parse(record.at) > Date.parse(old.at)) out.set(record.rung, record);\n }\n return out;\n}\n\n/**\n * This function gives the verdict of a ladder from the records of its rungs. It uses the newest record of each rung, so an\n * older pass does not hide a newer failure. A rung high up does not count when a rung below it is not `within`. It throws\n * a `RangeError` for a ladder with problems, because a verdict on a bad ladder has no meaning. See `checkLadder`.\n */\nexport function ladderVerdict(ladder: Ladder, records: readonly RungRecord[], options: LadderOptions): LadderVerdict {\n const problems = checkLadder(ladder);\n if (problems.length > 0) throw new RangeError(`ladderVerdict: ${problems.join(\" \")}`);\n const newest = newestRecords(records);\n const rungs = ladder.rungs.map((r) => rungVerdict(r, newest.get(r.name), options));\n const firstOpen = rungs.findIndex((r) => r.outcome !== \"within\");\n const heldCount = firstOpen === -1 ? rungs.length : firstOpen;\n const lost = rungs.filter((r) => r.locked && r.outcome !== \"within\");\n const reason = lost.length === 0 ? `Each of the ${rungs.filter((r) => r.locked).length} locked rungs is within.` : `${lost.length} locked rungs are not within. ${lost[0]?.reason ?? \"\"}`;\n return { subject: ladder.subject, held: rungs[heldCount - 1]?.rung, next: rungs[heldCount]?.rung, failed: lost.length > 0, reason, rungs };\n}\n","/**\n * The time verdict of a candidate against a baseline, with the noise of an A/A arm. An A/A pair runs the same code in\n * its two arms. Its ratios show how far apart two equal arms come on this machine. A candidate is faster or slower only\n * when its interval is out of that band.\n */\nimport { type BootstrapOptions, type Comparison, type Interval, bootstrapMedian, bootstrapTwo, compareRatios, median, quantile } from \"@mark1russell7/rigor-statistics\";\nimport { type CaseRatio, type PairedTime, caseRatios } from \"./paired.ts\";\n\n/**\n * The two kinds of an A/A band.\n * - The band `case` holds the ratio of one A/A case. It is wide, so it finds only a large change.\n * - The band `median` holds the median ratio of the A/A cases. It has the scale of the median of the candidate.\n */\nexport type BandKind = \"case\" | \"median\";\n\n/** The options of the A/A band. */\nexport interface BandOptions {\n /** The kind of the band. The default is `median`, from the power test of `verdictPower`. */\n readonly kind?: BandKind;\n /** The quantile of the band `case`, or the level of the bootstrap of the band `median`. The default is 0.95. */\n readonly level?: number;\n /** The fewest A/A cases that give a band. The default is 5, the 5-seed rule. */\n readonly minimum?: number;\n /** The bootstrap of the band `median`. The level of the band replaces its level. */\n readonly bootstrap?: BootstrapOptions;\n}\n\n/** The band of the A/A arm: two equal arms come out in this band of ratios. */\nexport interface Band {\n /** The count of the A/A cases. */\n readonly cases: number;\n readonly kind: BandKind;\n /**\n * The half width of the band on a log scale.\n * For the band `case`, it is the `level` quantile of `abs(log(ratio))` over the A/A cases.\n * For the band `median`, it is the larger distance of an end of the bootstrap interval of the A/A median from 0.\n */\n readonly noise: number;\n /** The ends of the band: `exp(-noise)` and `exp(noise)`. */\n readonly low: number;\n readonly high: number;\n /** The median ratio of the A/A cases. A value far from 1 shows a bias of the order or of the arm slots. */\n readonly median: number;\n}\n\n/** This function gives the band of the A/A arm. The band is symmetric on a log scale. It refuses fewer cases than `minimum`. */\nexport function aaBand(aa: readonly PairedTime[], options: BandOptions = {}): Band {\n const ratios = caseRatios(aa);\n const minimum = options.minimum ?? 5;\n if (ratios.length < minimum) throw new RangeError(`aaBand: the A/A arm has ${ratios.length} cases, and a band needs ${minimum} or more.`);\n const logs = ratios.map((r) => Math.log(r.ratio));\n const kind = options.kind ?? \"median\";\n const level = options.level ?? 0.95;\n let noise: number;\n if (kind === \"case\") noise = quantile(logs.map(Math.abs), level);\n else {\n const interval = bootstrapMedian(logs, { ...options.bootstrap, level });\n noise = Math.max(Math.abs(interval.low), Math.abs(interval.high));\n }\n return { cases: ratios.length, kind, noise, low: Math.exp(-noise), high: Math.exp(noise), median: Math.exp(quantile(logs, 0.5)) };\n}\n\n/**\n * This function gives the A/A spread: the `level` quantile of `abs(log(ratio))` over the A/A cases. The default level is 0.9.\n * It refuses an A/A arm with no cases.\n */\nexport function aaSpread(aa: readonly PairedTime[], level = 0.9): number {\n const ratios = caseRatios(aa);\n if (ratios.length === 0) throw new RangeError(\"aaSpread: the A/A arm has no cases.\");\n return spreadOf(ratios, level);\n}\n\nfunction spreadOf(ratios: readonly CaseRatio[], level: number): number {\n return quantile(ratios.map((r) => Math.abs(Math.log(r.ratio))), level);\n}\n\n/** The options of a pooled band: the A/A records of earlier quiet runs, and a floor. The caller keeps the pool. */\nexport interface PoolOptions {\n /** The A/A records of the earlier runs. Give each run its own case names, for example with the run id as a prefix. */\n readonly records: readonly PairedTime[];\n /** The smallest noise of the band, on a log scale. The default is 0. A floor of `Math.log(1.05)` gives at least the band `[1 / 1.05, 1.05]`. */\n readonly floor?: number;\n /** The fewest pooled cases that give a spread. With fewer cases, the noise of the band is the floor. The default is 5. */\n readonly minimum?: number;\n /**\n * The run of a record, for example the id of its CI run. The verdict counts the runs of the pool with it.\n * The cases of one run share one runner, so they are not independent. Many cases from few runs show the noise of few runners.\n */\n readonly run?: (record: PairedTime) => string;\n}\n\n/** The facts of the pooled band of a verdict. */\nexport interface PoolFacts {\n /** The count of the pooled A/A cases. */\n readonly cases: number;\n /** The count of the runs of the pool, from the option `run`. It is undefined without that option. */\n readonly runs: number | undefined;\n /** The A/A spread of the pooled cases, or undefined when the pool has fewer cases than `minimum`. */\n readonly spread: number | undefined;\n readonly floor: number;\n /** This value is `true` when the spread of the pool is larger than the floor, so the spread gives the noise of the band. */\n readonly pooled: boolean;\n}\n\n/**\n * This function gives the pooled band of the kind `case`. Its noise is the larger of the floor and the A/A spread of the pooled records.\n * The spread is the `level` quantile of `abs(log(ratio))`, with the default level 0.9.\n *\n * A band with fewer pooled cases than `minimum` uses the floor alone. A band with no pooled cases has the median 1.\n */\nexport function pooledBand(pool: PoolOptions, level = 0.9): Band {\n return poolOf(pool, level).band;\n}\n\nfunction poolOf(pool: PoolOptions, level: number): { band: Band; facts: PoolFacts } {\n const floor = pool.floor ?? 0;\n const minimum = pool.minimum ?? 5;\n if (!(floor >= 0 && Number.isFinite(floor))) throw new RangeError(`pooledBand: the floor is a finite number of 0 or more, not ${floor}.`);\n if (!Number.isSafeInteger(minimum) || minimum < 1) throw new RangeError(`pooledBand: the minimum is a whole number of 1 or more, not ${minimum}.`);\n const ratios = caseRatios(pool.records);\n const spread = ratios.length >= minimum ? spreadOf(ratios, level) : undefined;\n const noise = Math.max(floor, spread ?? 0);\n const median = ratios.length === 0 ? 1 : Math.exp(quantile(ratios.map((r) => Math.log(r.ratio)), 0.5));\n const band: Band = { cases: ratios.length, kind: \"case\", noise, low: Math.exp(-noise), high: Math.exp(noise), median };\n const runs = pool.run === undefined ? undefined : new Set(pool.records.map(pool.run)).size;\n return { band, facts: { cases: ratios.length, runs, spread, floor, pooled: spread !== undefined && spread > floor } };\n}\n\n/** The four outcomes of a time verdict. The candidate is the arm `b`, so `faster` is a ratio below 1. */\nexport type TimeOutcome = \"faster\" | \"slower\" | \"same\" | \"cannot decide\";\n\n/** The options of a time verdict. The bootstrap gives the interval of the median ratio of the candidate, and the band `median`. */\n/**\n * The two rules of a time verdict.\n * - The rule `band` compares the interval of the median ratio of the candidate with the A/A band.\n * - The rule `difference` compares the interval of the candidate median over the A/A median with 1 and with `margin`.\n */\nexport type VerdictRule = \"band\" | \"difference\";\n\n/** The options of a time verdict. The bootstrap gives each interval of the verdict. */\nexport interface VerdictOptions extends BandOptions {\n /** The rule of the verdict. The default is `difference`, from the power test of `verdictPower`. */\n readonly rule?: VerdictRule;\n /**\n * The half width on a log scale of the ratios that the rule `difference` calls `same`. The default is 0.05.\n * An interval in the margin is `same`, also when it is wholly below 1.\n */\n readonly margin?: number;\n /**\n * The noise cap on the A/A spread of the run, on a log scale. Above the cap, the outcome is `cannot decide`.\n * The cap also limits the bias of the A/A arm: an A/A median ratio out of `[exp(-noiseCap), exp(noiseCap)]` gives `cannot decide`.\n * The default is no cap.\n */\n readonly noiseCap?: number;\n /** The quantile of the A/A spread of the noise cap and of the pooled band. The default is 0.9. */\n readonly spreadLevel?: number;\n /**\n * The pooled band. It replaces the band of the A/A arm of the run in the rule `band` and in `comparison`.\n * The rule `difference` uses the larger of `margin` and the noise of the pooled band as its margin. The default is no pool.\n */\n readonly pool?: PoolOptions;\n}\n\n/** The noise cap of a verdict: the A/A spread of the run, the A/A median ratio of the run and the cap. */\nexport interface NoiseCheck {\n /** The A/A spread of the run, or undefined when the A/A arm has no cases. */\n readonly spread: number | undefined;\n readonly cap: number;\n /** This value is `true` when the spread is above the cap, or when the A/A arm has no cases. */\n readonly noisy: boolean;\n /** The median ratio of the A/A cases of the run, or undefined when the A/A arm has no cases. A value far from 1 shows a bias of the order or of the arm slots. */\n readonly aaMedian: number | undefined;\n /**\n * This value is `true` when the A/A median ratio of the run is out of `[exp(-cap), exp(cap)]`.\n * With a spread level of 0.5 or more, a biased run is also noisy. The check decides alone only below that level.\n */\n readonly biased: boolean;\n}\n\n/** A time verdict, with the facts that it uses. */\nexport interface TimeVerdict {\n readonly outcome: TimeOutcome;\n /** The reason of the outcome, in one sentence. */\n readonly reason: string;\n readonly cases: readonly CaseRatio[];\n readonly rule: VerdictRule;\n /**\n * The interval that the rule compares, or undefined when there are no candidate cases.\n * With too few A/A cases, it is the interval of the median ratio of the candidate.\n * For the rule `band`, it is the bootstrap interval of the median ratio of the candidate.\n * For the rule `difference`, it is the interval of the candidate median ratio over the A/A median ratio.\n */\n readonly interval: Interval | undefined;\n /** The band of the A/A arm, or undefined when the A/A arm has too few cases. */\n readonly band: Band | undefined;\n /**\n * The counts of the cases out of the band, or undefined without a band.\n * The comparison uses the value `1 + log(ratio)` of each case and the noise of the band, so its two sides are the ends of the band.\n */\n readonly comparison: Comparison | undefined;\n /** The facts of the pooled band. The verdict has this field only with the option `pool`. */\n readonly pool?: PoolFacts;\n /** The noise cap. The verdict has this field only with the option `noiseCap`. */\n readonly noise?: NoiseCheck;\n}\n\n/**\n * This function gives the time verdict of the candidate arm `b` against the baseline arm `a`.\n * - The rule `difference` gives `same` when the interval is in `[exp(-margin), exp(margin)]`. This test comes first, so\n * an interval in the margin and below 1 is `same`, not `faster`.\n * - Out of the margin, the rule `difference` gives `faster` when the whole interval is below 1, and `slower` when it is above 1.\n * With the margin 0, each outcome stays the same as in 0.1.2.\n * - The rule `band` gives `faster` below the band, `slower` above the band, and `same` in the band.\n * - Each other case is `cannot decide`, and so is an A/A arm with too few cases.\n * - With `noiseCap`, an A/A spread of the run above the cap gives `cannot decide`.\n * - With `noiseCap`, an A/A median ratio of the run out of `[exp(-noiseCap), exp(noiseCap)]` also gives `cannot decide`.\n * - With `pool`, the pooled band replaces the band of the A/A arm of the run. The run still needs `minimum` A/A cases.\n */\nexport function timeVerdict(candidate: readonly PairedTime[], aa: readonly PairedTime[], options: VerdictOptions = {}): TimeVerdict {\n const level = options.spreadLevel ?? 0.9;\n if (options.noiseCap !== undefined && !(options.noiseCap >= 0 && Number.isFinite(options.noiseCap))) {\n throw new RangeError(`timeVerdict: the noise cap is a finite number of 0 or more, not ${options.noiseCap}.`);\n }\n const pool = poolFor(options);\n let verdict = ruleVerdict(candidate, aa, options, pool?.band);\n if (pool !== undefined) verdict = { ...verdict, pool: pool.facts };\n if (options.noiseCap !== undefined) {\n const cap = options.noiseCap;\n const aaRatios = caseRatios(aa);\n const spread = aaRatios.length === 0 ? undefined : spreadOf(aaRatios, level);\n const aaMedian = aaRatios.length === 0 ? undefined : Math.exp(quantile(aaRatios.map((r) => Math.log(r.ratio)), 0.5));\n const biased = aaMedian !== undefined && Math.abs(Math.log(aaMedian)) > cap;\n const noise: NoiseCheck = { spread, cap, noisy: spread === undefined || spread > cap, aaMedian, biased };\n verdict = { ...verdict, noise };\n // The early outcomes (no candidate cases, too few A/A cases) keep their reason. Each other outcome gives way to the cap.\n if (noise.noisy && verdict.band !== undefined) {\n const why = spread === undefined ? \"The A/A arm of the run has no cases, so the noise cap has no spread.\" : `The A/A spread of the run is ${round(spread)}, above the noise cap ${cap}.`;\n const reason = `${why} Without the cap, the outcome is \"${verdict.outcome}\".`;\n verdict = { ...verdict, outcome: \"cannot decide\", reason };\n } else if (noise.biased && verdict.band !== undefined) {\n const reason = `The A/A median ratio of the run is ${round(aaMedian!)}, out of [${round(Math.exp(-cap))}, ${round(Math.exp(cap))}] of the noise cap ${cap}. Without the cap, the outcome is \"${verdict.outcome}\".`;\n verdict = { ...verdict, outcome: \"cannot decide\", reason };\n }\n }\n return verdict;\n}\n\n/** This function gives the pooled band and its facts of the options, or undefined without the option `pool`. */\nfunction poolFor(options: VerdictOptions): { band: Band; facts: PoolFacts } | undefined {\n return options.pool === undefined ? undefined : poolOf(options.pool, options.spreadLevel ?? 0.9);\n}\n\n/** This function gives the margin of the rule `difference`: the larger of `margin` and the noise of the pooled band. It refuses a margin below 0. */\nfunction marginOf(options: VerdictOptions, pooled: Band | undefined): number {\n const given = options.margin ?? 0.05;\n if (!(given >= 0)) throw new RangeError(`timeVerdict: the margin is 0 or more, not ${given}.`);\n return pooled === undefined ? given : Math.max(given, pooled.noise);\n}\n\n/**\n * This function gives the margin that the rule `difference` of `timeVerdict` uses with these options, on a log scale.\n * The margin is the larger of the option `margin` (default 0.05) and the noise of the pooled band. It uses the same code as the verdict.\n * The pooled band comes from the records of the option `pool`, not from the records of the run.\n * An interval in `[exp(-margin), exp(margin)]` has the outcome `same`. A page can draw that zone with this function.\n */\nexport function verdictMargin(options: VerdictOptions = {}): number {\n return marginOf(options, poolFor(options)?.band);\n}\n\n/** This function gives the outcome of the rule. A pooled band replaces the band of the A/A arm, and it widens the margin of the rule `difference`. */\nfunction ruleVerdict(candidate: readonly PairedTime[], aa: readonly PairedTime[], options: VerdictOptions, pooled: Band | undefined): TimeVerdict {\n const rule = options.rule ?? \"difference\";\n const cases = caseRatios(candidate);\n const aaRatios = caseRatios(aa);\n const minimum = options.minimum ?? 5;\n const none = { cases, rule, interval: undefined, band: undefined, comparison: undefined };\n if (cases.length === 0) return { ...none, outcome: \"cannot decide\", reason: \"The candidate has no cases.\" };\n if (aaRatios.length < minimum) {\n const interval = bootstrapMedian(cases.map((c) => c.ratio), options.bootstrap);\n return { ...none, interval, outcome: \"cannot decide\", reason: `The A/A arm has ${aaRatios.length} cases, and a band needs ${minimum} or more.` };\n }\n const band = pooled ?? aaBand(aa, options);\n const comparison = compareRatios(cases.map((c) => 1 + Math.log(c.ratio)), { better: \"lower\", noise: band.noise });\n const facts = { cases, rule, band, comparison };\n if (rule === \"difference\") {\n const margin = marginOf(options, pooled);\n const shown = pooled === undefined ? margin : round(margin);\n const logs = cases.map((c) => Math.log(c.ratio));\n const aaLogs = aaRatios.map((c) => Math.log(c.ratio));\n const d = bootstrapTwo(logs, aaLogs, (x, y) => median(x) - median(y), options.bootstrap);\n const interval: Interval = { ...d, estimate: Math.exp(d.estimate), low: Math.exp(d.low), high: Math.exp(d.high) };\n const span = `The interval of the candidate median over the A/A median is [${round(interval.low)}, ${round(interval.high)}].`;\n // The margin comes first: an interval in the margin is `same`, also when it is wholly below or above 1.\n if (d.low >= -margin && d.high <= margin) return { ...facts, interval, outcome: \"same\", reason: `${span} The interval is in the margin of ${shown}.` };\n if (interval.high < 1) return { ...facts, interval, outcome: \"faster\", reason: `${span} The interval is below 1.` };\n if (interval.low > 1) return { ...facts, interval, outcome: \"slower\", reason: `${span} The interval is above 1.` };\n return { ...facts, interval, outcome: \"cannot decide\", reason: `${span} The interval holds 1 and crosses the margin of ${shown}.` };\n }\n const interval = bootstrapMedian(cases.map((c) => c.ratio), options.bootstrap);\n const span = `The interval of the median ratio is [${round(interval.low)}, ${round(interval.high)}], and the A/A band is [${round(band.low)}, ${round(band.high)}].`;\n if (interval.high < band.low) return { ...facts, interval, outcome: \"faster\", reason: `${span} The interval is below the band.` };\n if (interval.low > band.high) return { ...facts, interval, outcome: \"slower\", reason: `${span} The interval is above the band.` };\n if (interval.low >= band.low && interval.high <= band.high) return { ...facts, interval, outcome: \"same\", reason: `${span} The interval is in the band.` };\n return { ...facts, interval, outcome: \"cannot decide\", reason: `${span} The interval crosses an end of the band.` };\n}\n\nfunction round(x: number): number {\n return Math.round(x * 10_000) / 10_000;\n}\n","/**\n * The limit verdict of a bench: is the ratio of each case at most a limit? For example, the claim \"the new code takes at most\n * 2 times the time of the old code\" needs it. The time verdict compares only with 1.\n */\nimport { medianInterval } from \"@mark1russell7/rigor-statistics\";\nimport { type CaseRatio, type PairedTime, caseRatios } from \"./paired.ts\";\nimport { type Band, type BandOptions, aaBand } from \"./verdict.ts\";\n\n/** The ratio of one case with the interval of its median over the rounds. */\nexport interface CaseInterval extends CaseRatio {\n /** The ends of the interval: `exp` of `medianInterval` over the values `log(b / a)` of the rounds. */\n readonly low: number;\n readonly high: number;\n /** The coverage of the interval. It is at least the level. */\n readonly coverage: number;\n}\n\n/**\n * This function gives the ratio of each case with a distribution-free interval of its median, in the order of\n * `caseRatios`. It needs enough rounds for the level: 6 rounds or more for the level 0.95.\n */\nexport function caseIntervals(records: readonly PairedTime[], level = 0.95): CaseInterval[] {\n const logs = new Map<string, number[]>();\n for (const r of records) {\n const list = logs.get(r.case) ?? [];\n list.push(Math.log(r.b / r.a));\n logs.set(r.case, list);\n }\n return caseRatios(records).map((c) => {\n const interval = medianInterval(logs.get(c.case)!, level);\n return { ...c, low: Math.exp(interval.low), high: Math.exp(interval.high), coverage: interval.coverage };\n });\n}\n\n/** The three outcomes of a limit verdict. */\nexport type LimitOutcome = \"within\" | \"beyond\" | \"cannot decide\";\n\n/** The options of a limit verdict. */\nexport interface LimitOptions extends BandOptions {\n /** The largest ratio `b / a` that the claim permits, for example 2. */\n readonly limit: number;\n /** The level of the interval of each case. The default is 0.95. */\n readonly caseLevel?: number;\n /**\n * The share of the cases that the claim needs `within`, above 0 and at most 1. The default 1 needs each case. With 0.95\n * and 20 cases, 1 case can be `beyond` or `cannot decide`. The option `timeTailQ` of a promotion record is this share.\n */\n readonly share?: number;\n}\n\n/** The verdict of one case against the limit. */\nexport interface CaseLimit extends CaseInterval {\n /** The high end of the interval of the case, times the high end of the A/A band. */\n readonly bound: number;\n /** The low end of the interval of the case, times the low end of the A/A band. */\n readonly floor: number;\n readonly outcome: LimitOutcome;\n}\n\n/** A limit verdict, with the facts that it uses. */\nexport interface LimitVerdict {\n readonly outcome: LimitOutcome;\n /** The reason of the outcome, in one sentence. */\n readonly reason: string;\n readonly limit: number;\n readonly cases: readonly CaseLimit[];\n /** The band of the A/A arm, or undefined when the A/A arm has too few cases. */\n readonly band: Band | undefined;\n /** The share of the option `share`. */\n readonly share: number;\n /** The number of cases that can be other than `within`: the floor of the number of cases times `1 - share`. */\n readonly allowed: number;\n}\n\n/**\n * This function gives the verdict of the claim \"the ratio `b / a` of each case is at most `limit`\". The A/A band widens\n * the interval of each case: the bound is the high end times the high end of the band.\n * - A case is `within` when its bound is at most the limit, and `beyond` when its floor is above the limit.\n * - The verdict is `within` when `allowed` cases or fewer are other than `within`. With the default share 1, `allowed` is 0.\n * - The verdict is `beyond` when more than `allowed` cases are `beyond`.\n * - Each other verdict is `cannot decide`, and so is an A/A arm with too few cases or a candidate with no cases.\n */\nexport function limitVerdict(candidate: readonly PairedTime[], aa: readonly PairedTime[], options: LimitOptions): LimitVerdict {\n const { limit } = options;\n if (!(limit > 0 && Number.isFinite(limit))) throw new RangeError(`limitVerdict: the limit is a finite number above 0, not ${limit}.`);\n const share = options.share ?? 1;\n if (!(share > 0 && share <= 1)) throw new RangeError(`limitVerdict: the share is above 0 and at most 1, not ${share}.`);\n const intervals = caseIntervals(candidate, options.caseLevel);\n const minimum = options.minimum ?? 5;\n // The small term keeps a product such as 10 * (1 - 0.9) = 0.9999999999999998 from a floor of 0.\n const allowed = Math.floor(intervals.length * (1 - share) + 1e-9);\n if (intervals.length === 0) return { outcome: \"cannot decide\", reason: \"The candidate has no cases.\", limit, cases: [], band: undefined, share, allowed };\n const aaCount = caseRatios(aa).length;\n if (aaCount < minimum) {\n const cases = intervals.map((c) => ({ ...c, bound: c.high, floor: c.low, outcome: \"cannot decide\" as const }));\n return { outcome: \"cannot decide\", reason: `The A/A arm has ${aaCount} cases, and a band needs ${minimum} or more.`, limit, cases, band: undefined, share, allowed };\n }\n const band = aaBand(aa, options);\n const cases = intervals.map((c): CaseLimit => {\n const bound = c.high * band.high;\n const floor = c.low * band.low;\n const outcome: LimitOutcome = bound <= limit ? \"within\" : floor > limit ? \"beyond\" : \"cannot decide\";\n return { ...c, bound, floor, outcome };\n });\n const facts = { limit, cases, band, share, allowed };\n const beyond = cases.filter((c) => c.outcome === \"beyond\");\n const others = cases.filter((c) => c.outcome !== \"within\");\n const permit = allowed === 0 ? \"\" : `, and the share ${share} permits ${allowed}`;\n if (beyond.length > allowed) {\n return { outcome: \"beyond\", reason: `${beyond.length} of ${cases.length} cases are above the limit ${limit}${permit}. The first is ${JSON.stringify(beyond[0]!.case)}.`, ...facts };\n }\n if (others.length <= allowed) {\n const inside = cases.filter((c) => c.outcome === \"within\");\n const top = (inside.length > 0 ? inside : cases).reduce((a, b) => (b.bound > a.bound ? b : a));\n const rest = others.length === 0 ? \"\" : ` ${others.length} of ${cases.length} cases are not within${permit}.`;\n return { outcome: \"within\", reason: `The largest bound of a case within is ${round(top.bound)} in the case ${JSON.stringify(top.case)}, and it is at most the limit ${limit}.${rest}`, ...facts };\n }\n const top = cases.reduce((a, b) => (b.bound > a.bound ? b : a));\n return { outcome: \"cannot decide\", reason: `${others.length} of ${cases.length} cases are not within${permit}. The bound of the case ${JSON.stringify(top.case)} is ${round(top.bound)}, above the limit ${limit}, and too few floors are above it.`, ...facts };\n}\n\nfunction round(x: number): number {\n return Math.round(x * 10_000) / 10_000;\n}\n","/**\n * The tail limit verdict of a bench with few rounds. The median of each case has one limit, and a high value of its rounds\n * has another limit. The verdict `limitVerdict` needs an interval of the median, and a few rounds give a wide interval.\n * This verdict reads each value as it is, and the A/A arm of the same run tells which tail is noise.\n */\nimport { type PairedTime, caseRatios } from \"./paired.ts\";\nimport type { LimitOutcome } from \"./limit.ts\";\n\n/** The value at one rank of the ratios of one case, from the largest. */\nexport interface CaseTail {\n readonly case: string;\n /** The value at the rank, or undefined when the rounds do not put the rank above the median. */\n readonly tail: number | undefined;\n readonly rounds: number;\n}\n\n/** The two limits of one case. */\nexport interface TailLimit {\n /** The largest median of the ratio `b / a` that the claim permits. */\n readonly median: number;\n /** The largest tail of the ratio `b / a` that the claim permits. */\n readonly tail: number;\n}\n\n/** The options of `tailFalseFails`. */\nexport interface TailRuleOptions {\n /** The limits of all the cases, or a function that gives the limits of one case. */\n readonly limit: TailLimit | ((caseName: string) => TailLimit);\n /** The rank of the tail, from the largest. The default 2 reads the second largest ratio, so one slow process cannot move it. */\n readonly rank?: number;\n}\n\n/** The options of a tail limit verdict. */\nexport interface TailLimitOptions extends TailRuleOptions {\n /**\n * The largest tail of the A/A arm that lets a run decide. Each row under the tail of the A/A arm passes the tail limit, so\n * a loud run has no power. This option has no default, because a run with no cap passes each row when it is loud.\n */\n readonly aaCap: number;\n /** The smallest number of A/A cases with a tail. The default is 5. */\n readonly minimum?: number;\n /**\n * The names of the cases that the run must have. A case of this list with no record reads `cannot decide`. Without this\n * option, the verdict reads only the cases of the candidate, so a run that loses a case can read `within`.\n */\n readonly expected?: readonly string[];\n}\n\n/** The verdict of one case. */\nexport interface CaseTailLimit extends CaseTail {\n /** The median ratio of the case: the value `ratio` of `caseRatios`. The value is undefined when the case has no record. */\n readonly ratio: number | undefined;\n readonly limit: TailLimit;\n /** The median is over its limit. */\n readonly overMedian: boolean;\n /** The tail is over its limit and over the tail of the A/A arm of the run. */\n readonly overTail: boolean;\n readonly outcome: LimitOutcome;\n}\n\n/** A case that an A/A arm cannot read, with the reason. */\nexport interface TailGainCase {\n readonly case: string;\n /** The reason in one sentence. It names the limit under 1. */\n readonly reason: string;\n}\n\n/** The result of `tailFalseFails`. */\nexport interface TailFalseFails {\n /** The cases that the rule fails on the A/A arm. Print the count of this list on the gate. */\n readonly fails: readonly string[];\n /** The cases with a limit under 1. These cases are not in `fails`, because an A/A pair shows no gain. */\n readonly gains: readonly TailGainCase[];\n}\n\n/** A tail limit verdict, with the facts that it uses. */\nexport interface TailLimitVerdict {\n readonly outcome: LimitOutcome;\n /** The reason of the outcome, in one sentence. */\n readonly reason: string;\n readonly cases: readonly CaseTailLimit[];\n /** The largest tail over the cases of the A/A arm, or undefined when that arm has too few cases. */\n readonly aaTail: number | undefined;\n readonly aaCap: number;\n readonly rank: number;\n}\n\nfunction ratiosOf(records: readonly PairedTime[]): Map<string, number[]> {\n const ratios = new Map<string, number[]>();\n for (const r of records) {\n const list = ratios.get(r.case) ?? [];\n list.push(r.b / r.a);\n ratios.set(r.case, list);\n }\n return ratios;\n}\n\nfunction checkRank(rank: number): void {\n if (!Number.isSafeInteger(rank) || rank < 1) throw new RangeError(`tail: the rank is a whole number of 1 or more, not ${rank}.`);\n}\n\n/**\n * This function gives the value at one rank of the ratios of each case, from the largest, in the order of `caseRatios`. It\n * examines the records as `caseRatios` does. A case needs `2 * rank + 1` rounds, so that the value is above the median.\n */\nexport function caseTails(records: readonly PairedTime[], rank = 2): CaseTail[] {\n checkRank(rank);\n const ratios = ratiosOf(records);\n return caseRatios(records).map((c) => {\n const sorted = (ratios.get(c.case) ?? []).toSorted((x, y) => y - x);\n return { case: c.case, rounds: c.rounds, tail: c.rounds >= 2 * rank + 1 ? sorted[rank - 1] : undefined };\n });\n}\n\nfunction limitOf(options: TailRuleOptions, name: string): TailLimit {\n const limit = typeof options.limit === \"function\" ? options.limit(name) : options.limit;\n for (const value of [limit.median, limit.tail]) {\n if (!(value > 0 && Number.isFinite(value))) throw new RangeError(`tail: each limit is a finite number above 0, not ${value} for the case ${JSON.stringify(name)}.`);\n }\n return limit;\n}\n\nfunction largestTail(tails: readonly CaseTail[]): number | undefined {\n const values = tails.flatMap((c) => (c.tail === undefined ? [] : [c.tail]));\n return values.length === 0 ? undefined : Math.max(...values);\n}\n\n/**\n * This function gives the verdict of the claim \"the median and the tail of each case are at most their limits\".\n * - A case is `beyond` when its median is over its limit. It is also `beyond` when its tail is over its limit and over the\n * largest tail of the A/A arm of the run.\n * - A case with too few rounds for the rank is `cannot decide`, unless its median is over its limit.\n * - A case of `expected` with no record is `cannot decide`.\n * - The verdict is `beyond` when a case is `beyond`, and `within` when each case is `within`.\n * - Each case and the verdict are `cannot decide` when the largest tail of the A/A arm is over `aaCap`. The same applies\n * when the A/A arm has fewer than `minimum` cases with a tail. This is not a pass, so the caller takes another read.\n *\n * With the default rank, a real cost in 1 round cannot fail the tail limit, because 1 round cannot be told from noise. A\n * cost in 2 rounds or more can fail it. The verdict has no interval, so a limit needs a margin from the spread of earlier\n * runs.\n */\nexport function tailLimitVerdict(candidate: readonly PairedTime[], aa: readonly PairedTime[], options: TailLimitOptions): TailLimitVerdict {\n const { aaCap } = options;\n const rank = options.rank ?? 2;\n const minimum = options.minimum ?? 5;\n checkRank(rank);\n if (!(aaCap > 0 && Number.isFinite(aaCap))) throw new RangeError(`tailLimitVerdict: the cap is a finite number above 0, not ${aaCap}.`);\n if (!Number.isSafeInteger(minimum) || minimum < 1) throw new RangeError(`tailLimitVerdict: the minimum is a whole number of 1 or more, not ${minimum}.`);\n const aaTails = caseTails(aa, rank).filter((c) => c.tail !== undefined);\n const aaTail = aaTails.length < minimum ? undefined : largestTail(aaTails);\n const tails = new Map(caseTails(candidate, rank).map((c) => [c.case, c]));\n const facts = { aaTail, aaCap, rank };\n const present = caseRatios(candidate).map((c): CaseTailLimit => {\n const { tail } = tails.get(c.case) ?? { tail: undefined };\n const limit = limitOf(options, c.case);\n if (aaTail === undefined || aaTail > aaCap) return { case: c.case, tail, rounds: c.rounds, ratio: c.ratio, limit, overMedian: false, overTail: false, outcome: \"cannot decide\" };\n const overMedian = c.ratio > limit.median;\n const overTail = tail !== undefined && tail > limit.tail && tail > aaTail;\n const outcome: LimitOutcome = overMedian || overTail ? \"beyond\" : tail === undefined ? \"cannot decide\" : \"within\";\n return { case: c.case, tail, rounds: c.rounds, ratio: c.ratio, limit, overMedian, overTail, outcome };\n });\n const found = new Set(present.map((c) => c.case));\n const missing = [...new Set(options.expected ?? [])]\n .filter((name) => !found.has(name))\n .map((name): CaseTailLimit => ({ case: name, tail: undefined, rounds: 0, ratio: undefined, limit: limitOf(options, name), overMedian: false, overTail: false, outcome: \"cannot decide\" }));\n const cases = [...present, ...missing];\n if (aaTail === undefined) return { ...facts, outcome: \"cannot decide\", cases, reason: `The A/A arm has ${aaTails.length} cases with a tail, and the verdict needs ${minimum} or more.` };\n if (aaTail > aaCap) return { ...facts, outcome: \"cannot decide\", cases, reason: `The largest tail ${round(aaTail)} of the A/A arm is over the cap ${aaCap}, so this run has no power.` };\n if (cases.length === 0) return { ...facts, outcome: \"cannot decide\", cases, reason: \"The candidate has no cases.\" };\n const beyond = cases.filter((c) => c.outcome === \"beyond\");\n if (beyond.length > 0) return { ...facts, outcome: \"beyond\", cases, reason: `${beyond.length} of ${cases.length} cases are over a limit. The first is ${JSON.stringify(beyond[0]!.case)}.` };\n if (missing.length > 0) return { ...facts, outcome: \"cannot decide\", cases, reason: `${missing.length} of ${cases.length} cases have no record. The first is ${JSON.stringify(missing[0]!.case)}.` };\n const open = cases.filter((c) => c.outcome === \"cannot decide\");\n if (open.length > 0) return { ...facts, outcome: \"cannot decide\", cases, reason: `${open.length} of ${cases.length} cases have too few rounds for the rank ${rank}. The first is ${JSON.stringify(open[0]!.case)}.` };\n return { ...facts, outcome: \"within\", cases, reason: `Each of the ${cases.length} cases is at most its limits, or its tail is at most the tail ${round(aaTail)} of the A/A arm.` };\n}\n\n/**\n * This function applies the rule of `tailLimitVerdict` to each case of the A/A arm, and gives the cases that fail. Each\n * case reads the tail of the other cases, because a case cannot be the noise of itself. An arm with one case gives no\n * failed case.\n *\n * A limit under 1 states a gain, and an A/A pair shows no gain. So the A/A arm has no read of that case, and the case goes\n * in `gains` with that reason. The tail of that case stays in the noise of the other cases. The false fails of a gain limit\n * come from repeat reads of an unchanged tree against its fixed base.\n */\nexport function tailFalseFails(aa: readonly PairedTime[], options: TailRuleOptions): TailFalseFails {\n const rank = options.rank ?? 2;\n const tails = caseTails(aa, rank);\n const ratios = new Map(caseRatios(aa).map((c) => [c.case, c.ratio]));\n const gains = tails.flatMap((c): TailGainCase[] => {\n const limit = limitOf(options, c.case);\n const under = Math.min(limit.median, limit.tail);\n return under < 1 ? [{ case: c.case, reason: `The limit ${under} is under 1, and an A/A pair shows no gain, so the A/A arm has no read of this case.` }] : [];\n });\n const noRead = new Set(gains.map((c) => c.case));\n const fails = tails\n .filter((c) => {\n if (noRead.has(c.case)) return false;\n const others = largestTail(tails.filter((other) => other !== c));\n if (others === undefined) return false;\n const limit = limitOf(options, c.case);\n return (ratios.get(c.case) ?? 0) > limit.median || (c.tail !== undefined && c.tail > limit.tail && c.tail > others);\n })\n .map((c) => c.case);\n return { fails, gains };\n}\n\nfunction round(x: number): number {\n return Math.round(x * 10_000) / 10_000;\n}\n","/**\n * The merge of the records of many jobs, and the pooled verdicts over them. Each job of a bench gives its own records.\n * A pooled verdict uses all jobs together, and the verdict of each job alone guards it.\n */\nimport { type LimitOptions, type LimitOutcome, type LimitVerdict, limitVerdict } from \"./limit.ts\";\nimport { type Arm, type PairedTime } from \"./paired.ts\";\nimport { type TimeOutcome, type TimeVerdict, type VerdictOptions, timeVerdict } from \"./verdict.ts\";\n\n/** The records of each case with a turned order, and the count of the records that the balance removed. */\nexport interface Balanced<T extends PairedTime> {\n readonly records: T[];\n /** The count of the removed records. It is 0 when each case has a turned order. */\n readonly trimmed: number;\n}\n\n/**\n * This function removes records until the two orders of each case differ in count by 1 or less.\n * It removes the records of the larger order with the highest rounds first. The other records keep their order.\n * A job that stopped early, or a missing job, can leave a case with 2 more rounds of one order. `caseRatios` refuses such a case.\n */\nexport function balanceOrders<T extends PairedTime>(records: readonly T[]): Balanced<T> {\n const byCase = new Map<string, Record<Arm, number[]>>();\n records.forEach((record, index) => {\n const orders = byCase.get(record.case) ?? { a: [], b: [] };\n orders[record.first === \"b\" ? \"b\" : \"a\"].push(index);\n byCase.set(record.case, orders);\n });\n const drop = new Set<number>();\n const highFirst = (x: number, y: number): number => records[y]!.round - records[x]!.round;\n for (const { a, b } of byCase.values()) {\n const [more, fewer] = a.length > b.length ? [a, b] : [b, a];\n const extra = more.length - fewer.length - 1;\n if (extra > 0) for (const index of more.toSorted(highFirst).slice(0, extra)) drop.add(index);\n }\n return { records: records.filter((_, index) => !drop.has(index)), trimmed: drop.size };\n}\n\n/** The records of one job: the candidate pair and the A/A pair. */\nexport interface JobRecords {\n /** The label of the job, for example the index of its CI job. A record with a field `job` has this label, or `poolRecords` refuses it. */\n readonly job: string;\n readonly candidate: readonly PairedTime[];\n readonly aa: readonly PairedTime[];\n /** The cases that the job skipped, as `freshRun` gives them. `poolRecords` removes each of these cases from all jobs. */\n readonly skipped?: readonly { readonly case: string }[];\n}\n\n/** The records of one job in a pool: the cases that no job skipped, balanced with `balanceOrders`. */\nexport interface PooledJob {\n readonly job: string;\n readonly candidate: PairedTime[];\n readonly aa: PairedTime[];\n}\n\n/** The pool of the jobs: the merged records of all jobs, and the records of each job alone. */\nexport interface PooledRecords {\n /** The merged candidate records of all jobs, balanced with `balanceOrders`. */\n readonly candidate: PairedTime[];\n /** The merged A/A records of all jobs, balanced with `balanceOrders`. */\n readonly aa: PairedTime[];\n /** The records of each job alone, in the order of the jobs. */\n readonly jobs: readonly PooledJob[];\n /** The count of the records that `balanceOrders` removed from the merged candidate and A/A records. */\n readonly trimmed: number;\n /** The cases that a job skipped, in sorted order. The pool has no record of these cases. */\n readonly dropped: string[];\n}\n\n/**\n * This function gives the pool of the jobs. `pooledVerdict` and `pooledLimitVerdict` use it.\n * - It refuses two jobs with one label, and a record with a different job label. It also refuses two jobs with a record of one case and one round.\n * - It removes each case that a job skipped from all jobs, so all jobs have the same cases.\n * - It merges the records of the jobs, and it balances the merged records and the records of each job with `balanceOrders`.\n */\nexport function poolRecords(jobs: readonly JobRecords[]): PooledRecords {\n return pool(jobs, \"poolRecords\");\n}\n\n/** The pool of `poolRecords`. Each error starts with the name `caller`. */\nfunction pool(jobs: readonly JobRecords[], caller: string): PooledRecords {\n const labels = new Set<string>();\n for (const { job } of jobs) {\n if (labels.has(job)) throw new RangeError(`${caller}: two jobs have the label ${JSON.stringify(job)}.`);\n labels.add(job);\n }\n for (const { job, candidate: c, aa: a } of jobs) {\n for (const r of [...c, ...a] as readonly (PairedTime & { readonly job?: unknown })[]) {\n if (r.job !== undefined && r.job !== job) throw new RangeError(`${caller}: a record of the job ${JSON.stringify(job)} has the job ${JSON.stringify(r.job)}.`);\n }\n }\n const dropped = [...new Set(jobs.flatMap((j) => (j.skipped ?? []).map((s) => s.case)))].sort();\n const gone = new Set(dropped);\n const keep = (records: readonly PairedTime[]): PairedTime[] => records.filter((r) => !gone.has(r.case));\n const kept = jobs.map((j) => ({ job: j.job, candidate: keep(j.candidate), aa: keep(j.aa) }));\n uniqueRounds(kept, \"candidate\", caller);\n uniqueRounds(kept, \"aa\", caller);\n const candidate = balanceOrders(kept.flatMap((j) => j.candidate));\n const aa = balanceOrders(kept.flatMap((j) => j.aa));\n const each = kept.map(({ job, candidate: c, aa: a }): PooledJob => ({ job, candidate: balanceOrders(c).records, aa: balanceOrders(a).records }));\n return { candidate: candidate.records, aa: aa.records, jobs: each, trimmed: candidate.trimmed + aa.trimmed, dropped };\n}\n\n/** This function refuses two jobs with a record of one case and one round in one pair. */\nfunction uniqueRounds(jobs: readonly PooledJob[], pair: \"candidate\" | \"aa\", caller: string): void {\n const seen = new Map<string, string>();\n for (const { job, [pair]: records } of jobs) {\n for (const r of records) {\n const key = `${r.case}\\u0000${r.round}`;\n const other = seen.get(key);\n if (other !== undefined && other !== job) {\n throw new RangeError(\n `${caller}: the jobs ${JSON.stringify(other)} and ${JSON.stringify(job)} both have the round ${r.round} of the case ${JSON.stringify(r.case)} in the ${pair} pair. Set roundOffset of each job to job * rounds.`,\n );\n }\n seen.set(key, job);\n }\n }\n}\n\n/** The guard of a pooled verdict: the outcome, the opposed jobs and the reason. */\ninterface Guarded<O extends string> {\n readonly outcome: O | \"cannot decide\";\n readonly opposed: string[];\n readonly reason: string;\n}\n\n/**\n * This function applies the guard of the jobs to a pooled verdict. A job whose outcome is `opposite` of the pooled outcome\n * makes the outcome `cannot decide`. Each other job does not change the outcome.\n */\nfunction guard<O extends string>(\n pooled: { readonly outcome: O; readonly reason: string },\n jobs: readonly { readonly job: string; readonly verdict: { readonly outcome: O } }[],\n opposite: Partial<Record<O, O>>,\n): Guarded<O> {\n const against = opposite[pooled.outcome];\n const opposed = against === undefined ? [] : jobs.filter((j) => j.verdict.outcome === against).map((j) => j.job);\n if (opposed.length === 0) return { outcome: pooled.outcome, opposed, reason: pooled.reason };\n const names = opposed.map((j) => JSON.stringify(j)).join(\", \");\n const reason = `${pooled.reason} The pooled outcome is \"${pooled.outcome}\", but the jobs ${names} give \"${against}\". Thus the outcome is \"cannot decide\".`;\n return { outcome: \"cannot decide\", opposed, reason };\n}\n\n/** The verdict of one job alone. */\nexport interface JobVerdict {\n readonly job: string;\n readonly verdict: TimeVerdict;\n}\n\n/** The pooled verdict over the jobs, with the verdict of each job alone. */\nexport interface PooledVerdict {\n /** The outcome of the pooled verdict, or `cannot decide` when a job decides the opposite direction. */\n readonly outcome: TimeOutcome;\n /** The verdict of the merged and balanced records of all jobs. */\n readonly pooled: TimeVerdict;\n /** The verdict of each job alone, with the options of the pooled verdict. */\n readonly jobs: readonly JobVerdict[];\n /** The jobs whose own outcome is the opposite direction of the pooled outcome. */\n readonly opposed: string[];\n /** The count of the records that `balanceOrders` removed from the merged candidate and A/A records. */\n readonly trimmed: number;\n /** The cases that a job skipped, in sorted order. The verdicts use no record of these cases. */\n readonly dropped: string[];\n /** The reason of the pooled verdict, and the opposed jobs. */\n readonly reason: string;\n}\n\nconst opposite: Partial<Record<TimeOutcome, TimeOutcome>> = { faster: \"slower\", slower: \"faster\" };\n\n/**\n * This function gives the time verdict over the records of all jobs.\n * - It makes the pool of the jobs with `poolRecords`, and it gives the time verdict of the merged records.\n * - The verdict of each job alone uses the same options. A job with `cannot decide` or `same` does not change the outcome.\n * - A job that decides the opposite direction of the pooled outcome makes the outcome `cannot decide`.\n */\nexport function pooledVerdict(jobs: readonly JobRecords[], options: VerdictOptions = {}): PooledVerdict {\n const { candidate, aa, jobs: each, trimmed, dropped } = pool(jobs, \"pooledVerdict\");\n const pooled = timeVerdict(candidate, aa, options);\n const verdicts = each.map(({ job, candidate: c, aa: a }): JobVerdict => ({ job, verdict: timeVerdict(c, a, options) }));\n const { outcome, opposed, reason } = guard(pooled, verdicts, opposite);\n return { outcome, pooled, jobs: verdicts, opposed, trimmed, dropped, reason };\n}\n\n/** The limit verdict of one job alone. */\nexport interface JobLimitVerdict {\n readonly job: string;\n readonly verdict: LimitVerdict;\n}\n\n/** The pooled limit verdict over the jobs, with the limit verdict of each job alone. */\nexport interface PooledLimitVerdict {\n /** The outcome of the pooled limit verdict, or `cannot decide` when a job gives the opposite outcome. */\n readonly outcome: LimitOutcome;\n /** The limit verdict of the merged and balanced records of all jobs. */\n readonly pooled: LimitVerdict;\n /** The limit verdict of each job alone, with the options of the pooled verdict. */\n readonly jobs: readonly JobLimitVerdict[];\n /** The jobs whose own outcome is the opposite of the pooled outcome: `beyond` against `within`, or the reverse. */\n readonly opposed: string[];\n /** The count of the records that `balanceOrders` removed from the merged candidate and A/A records. */\n readonly trimmed: number;\n /** The cases that a job skipped, in sorted order. The verdicts use no record of these cases. */\n readonly dropped: string[];\n /** The reason of the pooled limit verdict, and the opposed jobs. */\n readonly reason: string;\n}\n\nconst limitOpposite: Partial<Record<LimitOutcome, LimitOutcome>> = { within: \"beyond\", beyond: \"within\" };\n\n/**\n * This function gives the limit verdict over the records of all jobs, for example for a speed gate on limits over a CI matrix.\n * - It makes the pool of the jobs with `poolRecords`, and it gives the limit verdict of the merged records.\n * - The verdict of each job alone uses the same options. A job with `cannot decide` does not change the outcome.\n * - A job with `beyond` against a pooled `within`, or the reverse, makes the outcome `cannot decide`.\n */\nexport function pooledLimitVerdict(jobs: readonly JobRecords[], options: LimitOptions): PooledLimitVerdict {\n const { candidate, aa, jobs: each, trimmed, dropped } = pool(jobs, \"pooledLimitVerdict\");\n const pooled = limitVerdict(candidate, aa, options);\n const verdicts = each.map(({ job, candidate: c, aa: a }): JobLimitVerdict => ({ job, verdict: limitVerdict(c, a, options) }));\n const { outcome, opposed, reason } = guard(pooled, verdicts, limitOpposite);\n return { outcome, pooled, jobs: verdicts, opposed, trimmed, dropped, reason };\n}\n\n/** The pairs of a run: the records of each pair, by the id of the pair. */\nexport interface RunPairs {\n readonly pairs: Readonly<Record<string, readonly PairedTime[]>>;\n}\n\n/**\n * This function gives the verdict of each candidate pair of a run against its A/A pair `aaPair`.\n * It balances the records of each pair with `balanceOrders` first. It refuses an `aaPair` that the run does not have.\n */\nexport function armVerdicts(run: RunPairs, aaPair: string, options: VerdictOptions = {}): Record<string, TimeVerdict> {\n const aaRecords = run.pairs[aaPair];\n if (aaRecords === undefined) throw new RangeError(`armVerdicts: the run has no pair ${JSON.stringify(aaPair)}.`);\n const aa = balanceOrders(aaRecords).records;\n const out: Record<string, TimeVerdict> = {};\n for (const [pair, records] of Object.entries(run.pairs)) {\n if (pair !== aaPair) out[pair] = timeVerdict(balanceOrders(records).records, aa, options);\n }\n return out;\n}\n","/**\n * The check that a trick does not buy a measure. A control is a strategy made to win one measure and nothing else.\n * A real entry that wins that measure can do the same trick, so the win alone tells little. This check reads the controls of a\n * bench, and it tells which wins need a partner measure beside them. It also tells which measures separate nothing.\n *\n * A test compares paired values with the sign test of `rigor-statistics` and with the Holm correction. The keys of one stratum come\n * from one family of inputs, so they are not independent draws. The p of a test holds only under the sign test's own null: each\n * untied key is a fair coin. A result is about these keys, and this check claims nothing about other inputs.\n */\nimport { holm, median, signTest, signTestPower } from \"@mark1russell7/rigor-statistics\";\n\n/** One value of one measure, for one entry and one input. */\nexport interface MeasureRow {\n /** The name of the measure. */\n readonly measure: string;\n /** The name of the entry: a real strategy or a control. */\n readonly group: string;\n /** The name of the input. Equal keys in two groups name equal work, so the two values make a pair. */\n readonly key: string;\n /** The value. It is finite. No test reads the value of a censored row. */\n readonly value: number;\n /** This field is true when the entry did not finish this input, for example over its budget. */\n readonly censored?: boolean;\n /** The way that the value was made, for example a sample or a full count. Two ways in one measure do not compare. */\n readonly method?: string;\n /** The family of the input. A key has one stratum in all its rows. Rows without a stratum make one group. */\n readonly stratum?: string;\n}\n\n/** A measure with no control yet: the reason and the date of the control. */\nexport interface NoControl {\n /** The reason that the measure has no control at this time. */\n readonly because: string;\n /** The date of the control, as `YYYY-MM-DD`. A date before `asOf` gives the finding `control-late`. */\n readonly until: string;\n}\n\n/** The rule of one measure. */\nexport interface MeasureRule {\n readonly measure: string;\n /** The direction of a better value. */\n readonly sense: \"higher\" | \"lower\";\n /** The controls made to win this measure. Each one is in `controls` of the options. */\n readonly controls: readonly string[];\n /** The measures that a control of this measure is to lose. Each one has its own rule. */\n readonly partners: readonly string[];\n /** The smallest median paired difference that counts. Without it, only the test decides, and the output says so. It has no default. */\n readonly resolution?: number;\n /** The reason and the date, for a rule with no controls. */\n readonly noControl?: NoControl;\n}\n\n/** The options of `checkMeasures`. */\nexport interface MeasureCheckOptions {\n readonly rules: readonly MeasureRule[];\n /** Each group that is a control. Each other group is a real entry. */\n readonly controls: readonly string[];\n /** The date of the check, as `YYYY-MM-DD`. The caller gives it, so the function stays pure. */\n readonly asOf: string;\n /** The level of each family of tests. The default is 0.05. */\n readonly alpha?: number;\n}\n\n/** One test: `better` beats `other` on the keys that the two finished. */\nexport interface Comparison {\n readonly better: string;\n readonly other: string;\n readonly stratum: string | undefined;\n /** The keys that both finished. */\n readonly shared: number;\n /** The shared keys with different values. The test reads only these. */\n readonly n: number;\n readonly ties: number;\n /** The keys where `better` has the better value. */\n readonly wins: number;\n /** The keys where `other` has the better value. */\n readonly losses: number;\n /** The median paired difference over the shared keys, with ties. A positive value favours `better`. */\n readonly medianDifference: number;\n /** The p of the sign test. */\n readonly p: number;\n /** The p after the Holm correction. */\n readonly adjusted: number;\n /** The size of the Holm family. */\n readonly family: number;\n /** The least count of untied keys with the power to pass in this family. */\n readonly needs: number;\n /** This field is true when `n` is under `needs`. Such a test beats nothing. */\n readonly tooFew: boolean;\n /** This field is true when the shared keys reach `needs` and ties took them under it. So the two read as equal, not as unread. */\n readonly tied: boolean;\n /** The test passes, and the median difference is over the resolution when the measure has one. */\n readonly beats: boolean;\n}\n\n/** The read of one control on one measure and one stratum. */\nexport interface ControlRead {\n readonly measure: string;\n readonly control: string;\n readonly stratum: string | undefined;\n /**\n * The state of the read. `wins`: no real entry with enough pairs beats the control. `beaten`: a real entry beats it.\n * `too-few`: no real entry has enough shared keys. `no-rows`: no real entry shares a finished key with it.\n */\n readonly status: \"wins\" | \"beaten\" | \"too-few\" | \"no-rows\";\n /** The real entries with fewer winning keys than the control. It is a plain count with no test. */\n readonly aheadOf: number;\n /** One test for each real entry: `better` is the real entry, and `other` is the control. */\n readonly comparisons: readonly Comparison[];\n /** The real entries that the control beats by test on this stratum. */\n readonly beatsEntries: number;\n /** The tests of the control against the real entries that have power on this stratum. */\n readonly of: number;\n /** One test for each real entry: `better` is the control, and `other` is the real entry. This family is apart from `comparisons`. */\n readonly against: readonly Comparison[];\n}\n\n/** The counts of one entry on one measure and one stratum. */\nexport interface EntryCount {\n readonly group: string;\n readonly stratum: string | undefined;\n readonly finished: number;\n readonly censored: number;\n}\n\n/** The read of the spread of one measure on one stratum, over the pairs of real entries. */\nexport interface SpreadRead {\n readonly stratum: string | undefined;\n /** The pairs of real entries that share a finished key. */\n readonly pairs: number;\n /** The pairs with a test that passes in one direction. */\n readonly separated: number;\n /** The pairs with too few shared keys for the test. A pair that ties on enough keys does not count here. */\n readonly tooFew: number;\n /** The largest absolute median paired difference of a pair. */\n readonly widest: number | undefined;\n}\n\n/** The result of one control and one partner on one stratum. */\nexport interface PartnerRead {\n readonly partner: string;\n /**\n * `lost`: a real entry beats the control at the level divided by the count of partners. Each partner is one more chance to clear the control.\n * `not-lost`: no real entry does. `too-few`: no test has the power at that level. `no-rows`: nothing to read.\n */\n readonly status: \"lost\" | \"not-lost\" | \"too-few\" | \"no-rows\";\n}\n\n/** The result of one control on its measure and one stratum, with its partners. */\nexport interface GuardRead {\n readonly control: string;\n readonly stratum: string | undefined;\n readonly status: ControlRead[\"status\"];\n readonly partners: readonly PartnerRead[];\n}\n\n/** The read of one measure. */\nexport interface MeasureCheck {\n readonly measure: string;\n readonly sense: \"higher\" | \"lower\";\n /** `test only`: a measure with no resolution. `test and resolution`: a measure with one. */\n readonly basis: \"test only\" | \"test and resolution\";\n /** The only method of the rows. It is undefined when the rows give none. */\n readonly method: string | undefined;\n /** This field is true when the rows mix methods. The check then has no read of the measure. */\n readonly mixed: boolean;\n readonly guards: readonly GuardRead[];\n readonly spread: readonly SpreadRead[];\n readonly entries: readonly EntryCount[];\n /** The partners that the rule names. */\n readonly partners: readonly string[];\n /** The reason and the date, for a measure with no control. */\n readonly open: NoControl | undefined;\n}\n\n/** The kind of a finding. Each finding fails a gate. */\nexport type MeasureFindingKind = \"uncaught\" | \"weak-control\" | \"censored-win\" | \"no-spread\" | \"too-few\" | \"mixed-method\" | \"no-rule\" | \"no-rows\" | \"no-control\" | \"control-late\";\n\n/** One finding of the check, with the numbers behind it. */\nexport interface MeasureFinding {\n readonly kind: MeasureFindingKind;\n readonly measure: string;\n readonly stratum?: string | undefined;\n readonly control?: string;\n /** The count of the partners of the rule, for a finding about the partners of a control. */\n readonly partners?: number;\n /** The finding in plain words, with its numbers. */\n readonly text: string;\n /** The tests behind the finding. */\n readonly comparisons: readonly Comparison[];\n}\n\n/** The result of `checkMeasures`. */\nexport interface MeasureChecks {\n /** The level of each family of tests. */\n readonly alpha: number;\n readonly measures: readonly MeasureCheck[];\n /** Each read of a control, on its own measures and on their partners. */\n readonly reads: readonly ControlRead[];\n readonly findings: readonly MeasureFinding[];\n}\n\n/** What a page says about the win of one entry on one measure. */\nexport interface WinClaim {\n /** This field is true only when a control was read on this measure and this entry beats each control on it. A win by another entry does not count. */\n readonly alone: boolean;\n /** The partners that a winning control loses. When this entry does not beat a control that does not win, or with no read of a control, all partners of the rule. */\n readonly show: readonly string[];\n /** This field is true when this entry does not beat a control on this measure and beats it on no partner. The win then reads the same as the trick. The status of the control does not change this. */\n readonly likeControl: boolean;\n /** The censored keys of this entry and of each control that it does not beat. A page shows them beside the win. */\n readonly censored: { readonly entry: number; readonly controls: readonly { readonly control: string; readonly censored: number }[] };\n /** The reason and the date, for a measure with no control. */\n readonly open: NoControl | undefined;\n}\n\nconst DEFAULT_ALPHA = 0.05;\nconst DATE = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n/** The rows of one measure: for each stratum, for each group, the rows by key. */\ntype StratumRows = Map<string | undefined, Map<string, Map<string, MeasureRow>>>;\n\nfunction checkedDate(name: string, date: string): string {\n const time = Date.parse(`${date}T00:00:00Z`);\n if (!DATE.test(date) || !Number.isFinite(time) || new Date(time).toISOString().slice(0, 10) !== date) throw new RangeError(`checkMeasures: ${name} is a date as YYYY-MM-DD, not ${JSON.stringify(date)}.`);\n return date;\n}\n\n/** This function refuses the rules that contradict each other, because a wrong rule reads as a passed check. */\nfunction checkedRules(options: MeasureCheckOptions): Map<string, MeasureRule> {\n const controls = new Set(options.controls);\n const rules = new Map<string, MeasureRule>();\n for (const rule of options.rules) {\n if (rules.has(rule.measure)) throw new RangeError(`checkMeasures: the measure ${JSON.stringify(rule.measure)} has two rules.`);\n rules.set(rule.measure, rule);\n }\n for (const rule of options.rules) {\n const name = JSON.stringify(rule.measure);\n for (const control of rule.controls) if (!controls.has(control)) throw new RangeError(`checkMeasures: the control ${JSON.stringify(control)} of ${name} is not in the controls of the options.`);\n for (const partner of rule.partners) {\n if (partner === rule.measure) throw new RangeError(`checkMeasures: ${name} names itself as a partner.`);\n if (!rules.has(partner)) throw new RangeError(`checkMeasures: the partner ${JSON.stringify(partner)} of ${name} has no rule.`);\n }\n if (rule.resolution !== undefined && !(Number.isFinite(rule.resolution) && rule.resolution >= 0)) throw new RangeError(`checkMeasures: the resolution of ${name} is finite and 0 or more, not ${rule.resolution}.`);\n if (rule.noControl !== undefined) {\n if (rule.controls.length > 0) throw new RangeError(`checkMeasures: ${name} has controls and also noControl.`);\n checkedDate(`the date of ${name}`, rule.noControl.until);\n }\n }\n return rules;\n}\n\n/** This function groups the rows. It refuses a value that is not finite, a repeat, and a key in two strata. */\nfunction groupedRows(rows: readonly MeasureRow[]): Map<string, StratumRows> {\n const strata = new Map<string, string | undefined>();\n const measures = new Map<string, StratumRows>();\n for (const row of rows) {\n const where = `${JSON.stringify(row.key)} of ${JSON.stringify(row.group)} on ${JSON.stringify(row.measure)}`;\n if (!Number.isFinite(row.value)) throw new RangeError(`checkMeasures: the value of ${where} is not finite: ${row.value}.`);\n if (strata.has(row.key) && strata.get(row.key) !== row.stratum) throw new RangeError(`checkMeasures: the key ${JSON.stringify(row.key)} has two strata.`);\n strata.set(row.key, row.stratum);\n const measure = measures.get(row.measure) ?? (new Map() as StratumRows);\n measures.set(row.measure, measure);\n const groups = measure.get(row.stratum) ?? new Map<string, Map<string, MeasureRow>>();\n measure.set(row.stratum, groups);\n const keys = groups.get(row.group) ?? new Map<string, MeasureRow>();\n groups.set(row.group, keys);\n if (keys.has(row.key)) throw new RangeError(`checkMeasures: the row ${where} comes twice. State how the repeats reduce to one row.`);\n keys.set(row.key, row);\n }\n return measures;\n}\n\n/** This function gives the least count of untied keys with the power to pass at `level`. */\nfunction pairsNeeded(level: number, sides: 1 | 2): number {\n let n = 1;\n while (signTestPower(n, level, sides) === undefined) n += 1;\n return n;\n}\n\n/** The numbers of one pair before the correction. */\ninterface RawTest {\n readonly better: string;\n readonly other: string;\n readonly stratum: string | undefined;\n readonly shared: number;\n readonly wins: number;\n readonly losses: number;\n readonly medianDifference: number;\n}\n\n/** This function compares two groups on the keys that both finished. A positive difference favours `better`. */\nfunction rawTest(better: string, other: string, stratum: string | undefined, groups: Map<string, Map<string, MeasureRow>>, sense: MeasureRule[\"sense\"]): RawTest | undefined {\n const a = groups.get(better);\n const b = groups.get(other);\n if (a === undefined || b === undefined) return undefined;\n const differences: number[] = [];\n for (const [key, row] of a) {\n const pair = b.get(key);\n if (pair === undefined || row.censored === true || pair.censored === true) continue;\n differences.push(sense === \"higher\" ? row.value - pair.value : pair.value - row.value);\n }\n if (differences.length === 0) return undefined;\n const wins = differences.filter((d) => d > 0).length;\n const losses = differences.filter((d) => d < 0).length;\n return { better, other, stratum, shared: differences.length, wins, losses, medianDifference: median(differences) };\n}\n\n/** This function corrects one family of tests, over all strata. A test with too few keys beats nothing, even when a step of Holm passes it. */\nfunction corrected(tests: readonly RawTest[], sides: 1 | 2, alpha: number, resolution: number | undefined): Comparison[] {\n if (tests.length === 0) return [];\n const family = tests.length;\n const needs = pairsNeeded(alpha / family, sides);\n const ps = tests.map((t) => signTest(t.wins, t.losses, sides));\n const steps = holm(ps, alpha);\n return tests.map((t, i) => {\n const n = t.wins + t.losses;\n const tooFew = n < needs;\n const size = sides === 1 ? t.medianDifference : Math.abs(t.medianDifference);\n const clears = resolution === undefined || size > resolution;\n return { ...t, n, ties: t.shared - n, p: ps[i] as number, adjusted: steps[i]?.adjusted as number, family, needs, tooFew, tied: tooFew && t.shared >= needs, beats: !tooFew && steps[i]?.reject === true && clears };\n });\n}\n\nconst stratumText = (stratum: string | undefined): string => (stratum === undefined ? \"\" : ` in the stratum ${JSON.stringify(stratum)}`);\n\n/** This function tells that a test has too few keys to read, so a tie on enough keys is a read. */\nconst unread = (c: Comparison): boolean => c.tooFew && !c.tied;\n\n/** The reads of one control on one measure: one for each stratum of the measure. */\nfunction controlReads(measure: string, control: string, data: StratumRows | undefined, rule: MeasureRule, real: readonly string[], alpha: number): ControlRead[] {\n if (data === undefined) return [];\n const tests = [...data].flatMap(([stratum, groups]) => real.flatMap((entry) => rawTest(entry, control, stratum, groups, rule.sense) ?? []));\n const comparisons = corrected(tests, 1, alpha, rule.resolution);\n const attacks = corrected(\n [...data].flatMap(([stratum, groups]) => real.flatMap((entry) => rawTest(control, entry, stratum, groups, rule.sense) ?? [])),\n 1,\n alpha,\n rule.resolution,\n );\n return [...data.keys()].map((stratum) => {\n const here = comparisons.filter((c) => c.stratum === stratum);\n const against = attacks.filter((c) => c.stratum === stratum);\n const status: ControlRead[\"status\"] = here.length === 0 ? \"no-rows\" : here.some((c) => c.beats) ? \"beaten\" : here.every(unread) ? \"too-few\" : \"wins\";\n return { measure, control, stratum, status, aheadOf: here.filter((c) => c.losses > c.wins).length, comparisons: here, beatsEntries: against.filter((c) => c.beats).length, of: against.filter((c) => !unread(c)).length, against };\n });\n}\n\n/** The read of the spread of one measure: one family over all pairs of real entries and all strata. */\nfunction spreadReads(data: StratumRows, rule: MeasureRule, real: readonly string[], alpha: number): { reads: SpreadRead[]; comparisons: Comparison[] } {\n const tests = [...data].flatMap(([stratum, groups]) => real.flatMap((entry, i) => real.slice(i + 1).flatMap((other) => rawTest(entry, other, stratum, groups, rule.sense) ?? [])));\n const comparisons = corrected(tests, 2, alpha, rule.resolution);\n const reads = [...data.keys()].map((stratum) => {\n const here = comparisons.filter((c) => c.stratum === stratum);\n const widest = here.length === 0 ? undefined : Math.max(...here.map((c) => Math.abs(c.medianDifference)));\n return { stratum, pairs: here.length, separated: here.filter((c) => c.beats).length, tooFew: here.filter(unread).length, widest };\n });\n return { reads, comparisons };\n}\n\nfunction countsOf(data: StratumRows | undefined): EntryCount[] {\n const counts: EntryCount[] = [];\n for (const [stratum, groups] of data ?? []) {\n for (const [group, keys] of groups) {\n const censored = [...keys.values()].filter((row) => row.censored === true).length;\n counts.push({ group, stratum, finished: keys.size - censored, censored });\n }\n }\n return counts;\n}\n\n/** This function gives the methods of a measure. A row with no method counts as one more method beside a named one. */\nfunction methodsOf(data: StratumRows | undefined): readonly (string | undefined)[] {\n const methods = new Set<string | undefined>();\n for (const groups of data?.values() ?? []) for (const keys of groups.values()) for (const row of keys.values()) methods.add(row.method);\n return [...methods];\n}\n\n/** This function tells that a test clears a control on one of `partners` partners. One passed partner is enough, so the level divides by their count. */\nconst clearsPartner = (c: Comparison, partners: number, alpha: number): boolean => c.beats && c.adjusted * partners <= alpha;\n\n/** This function reads a control on one of `partners` partners. A test with too few shared keys for the divided level has no power, so a miss there is not a read. */\nconst partnerStatus = (read: ControlRead | undefined, partners: number, alpha: number): PartnerRead[\"status\"] => {\n if (read === undefined || read.status === \"no-rows\") return \"no-rows\";\n if (read.comparisons.some((c) => clearsPartner(c, partners, alpha))) return \"lost\";\n const needs = pairsNeeded(alpha / ((read.comparisons[0]?.family ?? 1) * partners), 1);\n return read.comparisons.every((c) => c.shared < needs) ? \"too-few\" : \"not-lost\";\n};\n\n/** The inputs of the reads, with the reads that the check already made. */\ninterface Reading {\n readonly rules: Map<string, MeasureRule>;\n readonly data: Map<string, StratumRows>;\n readonly real: readonly string[];\n readonly alpha: number;\n readonly mixed: ReadonlySet<string>;\n readonly memo: Map<string, ControlRead[]>;\n}\n\nfunction readsOf(reading: Reading, measure: string, control: string): ControlRead[] {\n const memoKey = JSON.stringify([measure, control]);\n const known = reading.memo.get(memoKey);\n if (known !== undefined) return known;\n const rule = reading.rules.get(measure) as MeasureRule;\n const reads = reading.mixed.has(measure) ? [] : controlReads(measure, control, reading.data.get(measure), rule, reading.real, reading.alpha);\n reading.memo.set(memoKey, reads);\n return reads;\n}\n\n/** The findings of the rows and the controls of one rule that have nothing to read. */\nfunction missingFindings(rule: MeasureRule, reading: Reading): MeasureFinding[] {\n const findings: MeasureFinding[] = [];\n const hasRows = (measure: string, group: string): boolean => [...(reading.data.get(measure)?.values() ?? [])].some((groups) => groups.has(group));\n const missing = (text: string, control?: string): void => {\n findings.push({ kind: \"no-rows\", measure: rule.measure, ...(control === undefined ? {} : { control }), text, comparisons: [] });\n };\n if (!reading.data.has(rule.measure)) missing(`The measure ${rule.measure} has a rule and no rows.`);\n for (const control of rule.controls) {\n if (reading.data.has(rule.measure) && !hasRows(rule.measure, control)) missing(`The control ${control} has no rows on ${rule.measure}, so it reads as nothing and not as \"not beaten\".`, control);\n for (const partner of rule.partners) {\n if (!hasRows(partner, control)) missing(`The control ${control} has no rows on the partner ${partner} of ${rule.measure}, so it reads as nothing and not as \"not beaten\".`, control);\n }\n }\n return findings;\n}\n\n/** The findings of the win of a control on one stratum: the partners and the censored keys. */\nfunction winFindings(rule: MeasureRule, read: ControlRead, guard: GuardRead, counts: readonly EntryCount[], partnerReads: readonly ControlRead[]): MeasureFinding[] {\n const findings: MeasureFinding[] = [];\n const where = stratumText(read.stratum);\n const count = guard.partners.length;\n const thin = guard.partners.filter((p) => p.status === \"too-few\").map((p) => p.partner);\n const noRows = guard.partners.some((p) => p.status === \"no-rows\");\n const behind = partnerReads.flatMap((r) => r.comparisons);\n if (!guard.partners.some((p) => p.status === \"lost\")) {\n if (thin.length > 0) {\n findings.push({ kind: \"too-few\", measure: rule.measure, stratum: read.stratum, control: read.control, partners: count, text: `The control ${read.control} wins ${rule.measure}${where} and loses no partner. Of its ${count} partners, ${thin.join(\", \")} have too few keys for a read.`, comparisons: behind });\n } else if (!noRows) {\n const list = count === 0 ? \"It has no partner.\" : `It loses none of its ${count} partners, ${guard.partners.map((p) => p.partner).join(\", \")}.`;\n findings.push({ kind: \"uncaught\", measure: rule.measure, stratum: read.stratum, control: read.control, partners: count, text: `The control ${read.control} wins ${rule.measure}${where}. ${list}`, comparisons: [...read.comparisons, ...behind] });\n }\n }\n const own = counts.find((c) => c.group === read.control && c.stratum === read.stratum)?.censored ?? 0;\n const fewer = counts.filter((c) => c.group !== read.control && c.stratum === read.stratum && read.comparisons.some((t) => t.better === c.group) && c.censored < own);\n if (fewer.length > 0) {\n const list = fewer.map((c) => `${c.group} ${c.censored}`).join(\", \");\n findings.push({ kind: \"censored-win\", measure: rule.measure, stratum: read.stratum, control: read.control, text: `The control ${read.control} wins ${rule.measure}${where} with ${own} censored keys, more than ${list}. Its win can come from the easy keys.`, comparisons: read.comparisons.filter((t) => fewer.some((c) => c.group === t.better)) });\n }\n return findings;\n}\n\n/** The read of one rule, with its findings. */\nfunction checkRule(rule: MeasureRule, reading: Reading, asOf: string): { check: MeasureCheck; findings: MeasureFinding[]; reads: ControlRead[] } {\n const data = reading.data.get(rule.measure);\n const methods = methodsOf(data);\n const mixed = reading.mixed.has(rule.measure);\n const counts = countsOf(data);\n const findings = missingFindings(rule, reading);\n const reads: ControlRead[] = [];\n const guards: GuardRead[] = [];\n\n if (mixed) {\n findings.push({ kind: \"mixed-method\", measure: rule.measure, text: `The measure ${rule.measure} mixes the methods ${methods.map((m) => m ?? \"(none)\").join(\", \")}. The check has no read of it until the rows are split or marked.`, comparisons: [] });\n }\n if (rule.controls.length === 0) {\n if (rule.noControl === undefined) findings.push({ kind: \"no-control\", measure: rule.measure, text: `The measure ${rule.measure} has no control and no noControl with a date.`, comparisons: [] });\n else if (rule.noControl.until < asOf) findings.push({ kind: \"control-late\", measure: rule.measure, text: `The control of ${rule.measure} was due on ${rule.noControl.until}, and the date of the check is ${asOf}.`, comparisons: [] });\n }\n\n for (const control of rule.controls) {\n for (const read of readsOf(reading, rule.measure, control)) {\n const partnerReads = rule.partners.map((partner) => readsOf(reading, partner, control).find((r) => r.stratum === read.stratum));\n const partners = rule.partners.map((partner, i) => ({ partner, status: partnerStatus(partnerReads[i], rule.partners.length, reading.alpha) }));\n const guard = { control, stratum: read.stratum, status: read.status, partners };\n guards.push(guard);\n reads.push(read, ...partnerReads.filter((r) => r !== undefined));\n if (read.status === \"wins\") findings.push(...winFindings(rule, read, guard, counts, partnerReads.filter((r) => r !== undefined)));\n }\n }\n const controlComparisons = guards.length === 0 ? [] : reads.filter((r) => r.measure === rule.measure).flatMap((r) => r.comparisons);\n if (rule.controls.length > 0 && guards.length > 0 && !mixed) {\n if (guards.every((g) => g.status === \"too-few\" || g.status === \"no-rows\")) {\n const needs = Math.max(0, ...controlComparisons.map((c) => c.needs));\n findings.push({ kind: \"too-few\", measure: rule.measure, text: `No control of ${rule.measure} has enough pairs for a read. A test needs ${needs} untied pairs.`, comparisons: controlComparisons });\n } else {\n for (const control of rule.controls) {\n const own = reads.filter((r) => r.measure === rule.measure && r.control === control);\n const of = own.reduce((sum, r) => sum + r.of, 0);\n if (of > 0 && own.every((r) => r.beatsEntries === 0)) {\n findings.push({ kind: \"weak-control\", measure: rule.measure, control, text: `The control ${control} beats 0 of ${of} real entries on ${rule.measure} by test, in all strata. The trick buys nothing.`, comparisons: own.flatMap((r) => r.against) });\n }\n }\n }\n }\n\n let spread: SpreadRead[] = [];\n if (data !== undefined && !mixed) {\n const { reads: spreadRows, comparisons } = spreadReads(data, rule, reading.real, reading.alpha);\n spread = spreadRows;\n const testable = comparisons.filter((c) => !unread(c));\n if (comparisons.length > 0 && testable.length === 0) {\n findings.push({ kind: \"too-few\", measure: rule.measure, text: `No pair of real entries has enough keys for a read of the spread of ${rule.measure}. A test needs ${comparisons[0]?.needs} untied pairs.`, comparisons: [] });\n } else if (testable.length > 0 && !comparisons.some((c) => c.beats)) {\n const widest = Math.max(...comparisons.map((c) => Math.abs(c.medianDifference)));\n const basis = rule.resolution === undefined ? \"by the test only\" : `by the test and the resolution ${rule.resolution}`;\n findings.push({ kind: \"no-spread\", measure: rule.measure, text: `No pair of the ${comparisons.length} pairs of real entries separates on ${rule.measure}, ${basis}. The widest median difference is ${widest}.`, comparisons: [...comparisons].sort((a, b) => a.adjusted - b.adjusted).slice(0, 1) });\n }\n }\n\n const check: MeasureCheck = {\n measure: rule.measure,\n sense: rule.sense,\n basis: rule.resolution === undefined ? \"test only\" : \"test and resolution\",\n method: mixed ? undefined : methods[0],\n mixed,\n guards,\n spread,\n entries: counts,\n partners: rule.partners,\n open: rule.noControl,\n };\n return { check, findings, reads };\n}\n\n/**\n * This function reads the controls and the spread of each measure of a bench.\n *\n * - A control wins a measure when no real entry beats it on the keys that both finished. A tie counts for the control.\n * - A real entry beats a control when the Holm-corrected sign test passes and the median paired difference is over the resolution.\n * - One Holm family holds the tests of one control on one measure over all real entries and all strata.\n * - One more Holm family holds the tests of one control against the real entries, with the same need and resolution. A control that beats none of them is weak.\n * - One Holm family holds the tests of the spread of one measure over all pairs of real entries and all strata.\n * - A test with fewer untied keys than `signTestPower` needs for that family reads `tooFew` and beats nothing.\n * - A test with enough shared keys and too few untied keys is `tied`. The two entries read as equal, so a constant measure is `no-spread` and not `too-few`.\n * - A control loses a partner only at the level divided by the count of its partners. One passed partner clears `uncaught`, so each partner is one more chance.\n *\n * The function throws a `RangeError` for a value that is not finite, a repeat of measure, group and key, or a key in two strata.\n * It also throws one for rules that contradict each other.\n * The rules, the controls and the date are stated, so the result depends only on the arguments.\n */\nexport function checkMeasures(rows: readonly MeasureRow[], options: MeasureCheckOptions): MeasureChecks {\n const alpha = options.alpha ?? DEFAULT_ALPHA;\n if (!(alpha > 0 && alpha < 1)) throw new RangeError(`checkMeasures: alpha is over 0 and under 1, not ${alpha}.`);\n const asOf = checkedDate(\"asOf\", options.asOf);\n const rules = checkedRules(options);\n const data = groupedRows(rows);\n const controls = new Set(options.controls);\n const real = [...new Set(rows.map((row) => row.group))].filter((group) => !controls.has(group));\n const mixed = new Set([...data.keys()].filter((measure) => methodsOf(data.get(measure)).length > 1));\n const reading: Reading = { rules, data, real, alpha, mixed, memo: new Map() };\n\n const findings: MeasureFinding[] = [];\n for (const measure of data.keys()) {\n if (!rules.has(measure)) findings.push({ kind: \"no-rule\", measure, text: `The measure ${measure} has rows and no rule.`, comparisons: [] });\n }\n const measures: MeasureCheck[] = [];\n const reads = new Map<string, ControlRead>();\n for (const rule of options.rules) {\n const result = checkRule(rule, reading, asOf);\n measures.push(result.check);\n findings.push(...result.findings);\n for (const read of result.reads) reads.set(JSON.stringify([read.measure, read.control, read.stratum ?? null]), read);\n }\n return { alpha, measures, reads: [...reads.values()], findings };\n}\n\n/**\n * This function tells what a page says about the win of one real entry on one measure.\n * The claim is about this entry: only this entry beating the control, on this measure or on a partner, clears the entry. A win by another entry clears nothing.\n * With a stratum, the function reads that stratum. Without one, it reads the rows with no stratum.\n * The function throws a `RangeError` for a measure with no read and for an entry that the rows do not hold.\n */\nexport function winClaim(check: MeasureChecks, measure: string, entry: string, stratum?: string): WinClaim {\n const read = check.measures.find((m) => m.measure === measure);\n if (read === undefined) throw new RangeError(`winClaim: the measure ${JSON.stringify(measure)} has no rule.`);\n const count = read.entries.find((c) => c.group === entry && c.stratum === stratum);\n if (count === undefined) throw new RangeError(`winClaim: the entry ${JSON.stringify(entry)} has no rows on ${JSON.stringify(measure)}${stratumText(stratum)}.`);\n const guards = read.guards.filter((g) => g.stratum === stratum);\n const winning = guards.filter((g) => g.status === \"wins\");\n const lostByControl = (guard: GuardRead): readonly string[] => guard.partners.filter((p) => p.status === \"lost\").map((p) => p.partner);\n const testsOf = (of: string, control: string): readonly Comparison[] => check.reads.find((r) => r.measure === of && r.control === control && r.stratum === stratum)?.comparisons ?? [];\n const notBeaten = guards.filter((g) => !testsOf(measure, g.control).some((c) => c.better === entry && c.beats));\n const clearsOnPartner = (guard: GuardRead): boolean => guard.partners.some((p) => testsOf(p.partner, guard.control).some((c) => c.better === entry && clearsPartner(c, guard.partners.length, check.alpha)));\n const countOf = (control: string): number => read.entries.find((c) => c.group === control && c.stratum === stratum)?.censored ?? 0;\n const alone = guards.length > 0 && notBeaten.length === 0;\n const onlyWinners = notBeaten.length > 0 && notBeaten.every((g) => g.status === \"wins\");\n const show = onlyWinners ? [...new Set(winning.flatMap(lostByControl))] : alone ? [] : read.partners;\n return {\n alone,\n show,\n likeControl: notBeaten.some((guard) => !clearsOnPartner(guard)),\n censored: { entry: count.censored, controls: notBeaten.map((g) => ({ control: g.control, censored: countOf(g.control) })) },\n open: read.open,\n };\n}\n","/**\n * The power test of a time verdict. It draws seeded benches with a known speedup and counts the verdicts that find it.\n * It also draws benches with equal arms and counts the false verdicts.\n */\nimport { random } from \"@mark1russell7/rigor-generators\";\nimport { firstArm, type PairedTime } from \"./paired.ts\";\nimport { type TimeOutcome, type VerdictOptions, timeVerdict, verdictMargin } from \"./verdict.ts\";\n\n/** The options of a power test. */\nexport interface PowerOptions {\n /** The count of the cases of the candidate and of the A/A arm. */\n readonly cases: number;\n /** The count of the rounds of each case. The default is 5. */\n readonly rounds?: number;\n /** The true ratio of the candidate time to the baseline time, for example 0.93 for a speedup of 7%. */\n readonly ratio: number;\n /** The standard deviation of the log time of one arm in one round. The default is 0.1. */\n readonly sigma?: number;\n /** The count of the seeded benches. The default is 200. */\n readonly trials?: number;\n /** The seed of the draws. The default is 1. */\n readonly seed?: number | string;\n /** The options of the verdict of each bench. */\n readonly verdict?: VerdictOptions;\n}\n\n/** The result of a power test: the share of each outcome over the trials. */\nexport interface Power {\n readonly trials: number;\n readonly outcomes: Readonly<Record<TimeOutcome, number>>;\n /**\n * The share of the trials whose outcome is the true one. For the rule `difference`, a ratio in the margin of the verdict has the true outcome `same`.\n * That margin is the larger of `margin` and the noise of the pooled band. The pool is the same in each trial, so each trial has the same margin.\n * Out of that margin, and for the rule `band`, the true outcome is `faster` below 1, `slower` above 1 and `same` at 1.\n */\n readonly power: number;\n}\n\n/**\n * This function draws `trials` benches and gives the share of each verdict. Each case has its own log scale.\n * Each arm of each round adds a normal noise of `sigma` to the log time.\n */\nexport function verdictPower(options: PowerOptions): Power {\n const rounds = options.rounds ?? 5;\n const sigma = options.sigma ?? 0.1;\n const trials = options.trials ?? 200;\n if (!Number.isSafeInteger(options.cases) || options.cases < 1) throw new RangeError(`verdictPower: cases is a whole number of 1 or more, not ${options.cases}.`);\n if (!(options.ratio > 0 && Number.isFinite(options.ratio))) throw new RangeError(`verdictPower: the ratio is a finite number above 0, not ${options.ratio}.`);\n const r = random(options.seed ?? 1);\n const bench = (ratio: number, prefix: string): PairedTime[] => {\n const out: PairedTime[] = [];\n for (let c = 0; c < options.cases; c++) {\n const scale = 10 * Math.exp(r.normal());\n for (let round = 0; round < rounds; round++) {\n const a = scale * Math.exp(r.normal(0, sigma));\n const b = scale * ratio * Math.exp(r.normal(0, sigma));\n out.push({ case: `${prefix}${c}`, round, first: firstArm(round, c), a, b });\n }\n }\n return out;\n };\n const truth = trueOutcome(options.ratio, options.verdict);\n const counts: Record<TimeOutcome, number> = { faster: 0, slower: 0, same: 0, \"cannot decide\": 0 };\n for (let t = 0; t < trials; t++) {\n const aa = bench(1, \"aa\");\n const candidate = bench(options.ratio, \"c\");\n counts[timeVerdict(candidate, aa, options.verdict).outcome]++;\n }\n const outcomes = Object.fromEntries(Object.entries(counts).map(([k, n]) => [k, n / trials])) as Record<TimeOutcome, number>;\n return { trials, outcomes, power: outcomes[truth] };\n}\n\n/** This function gives the true outcome of a ratio. The margin of the rule `difference` comes first, as in `timeVerdict`. */\nfunction trueOutcome(ratio: number, verdict: VerdictOptions = {}): TimeOutcome {\n if ((verdict.rule ?? \"difference\") === \"difference\" && Math.abs(Math.log(ratio)) <= verdictMargin(verdict)) return \"same\";\n return ratio < 1 ? \"faster\" : ratio > 1 ? \"slower\" : \"same\";\n}\n","/**\n * The timed rounds of one case in one process. The two arms first run for a warm-up time. Then the count of calls of\n * one batch grows until a batch of arm `a` takes the target time. Each round times one batch of each arm, in the order\n * of `firstArm`. Start this function in a fresh process for each case.\n */\nimport { type Arm, type PairedTime, firstArm } from \"./paired.ts\";\n\n/** The options of the timed rounds of one case. */\nexport interface RoundsOptions {\n /** The name of the case. */\n readonly case: string;\n /** The count of the rounds. */\n readonly rounds: number;\n /** The offset of `firstArm`: give the index of the case, so half of the cases start with each arm. The default is 0. */\n readonly offset?: number;\n /** The least time in milliseconds of one batch of arm `a`. The default is 10. */\n readonly targetMs?: number;\n /** The time in milliseconds of the warm-up of the two arms. The default is 1000. */\n readonly warmMs?: number;\n /** The clock in milliseconds. The default is `performance.now` of the global `performance` of Node and of each browser. */\n readonly now?: () => number;\n}\n\n/** The result of the timed rounds of one case. */\nexport interface Rounds {\n readonly records: PairedTime[];\n /** The count of calls of each arm in one batch. */\n readonly count: number;\n /** The sum of the numbers that the arms gave. The engine cannot remove the work of a call, because this sum uses it. */\n readonly sink: number;\n}\n\n/**\n * This function times the arms `a` and `b` of one case, and gives one `PairedTime` record for each round. The time of\n * a record is the time of one batch, in milliseconds. Each call of an arm gives a number, and the sum of these numbers\n * keeps the work.\n */\nexport function timeRounds(arms: Readonly<Record<Arm, () => number>>, options: RoundsOptions): Rounds {\n const { rounds } = options;\n const offset = options.offset ?? 0;\n const targetMs = options.targetMs ?? 10;\n const warmMs = options.warmMs ?? 1000;\n const now = options.now ?? (() => performance.now());\n if (!Number.isSafeInteger(rounds) || rounds < 1) throw new RangeError(`timeRounds: the rounds are a whole number of 1 or more, not ${rounds}.`);\n if (!Number.isSafeInteger(offset)) throw new RangeError(`timeRounds: the offset is a whole number, not ${offset}.`);\n if (!(targetMs > 0) || !(warmMs >= 0)) throw new RangeError(\"timeRounds: the target time is above 0, and the warm-up time is 0 or more.\");\n let sink = 0;\n const batch = (arm: Arm, count: number): number => {\n const run = arms[arm];\n const start = now();\n for (let i = 0; i < count; i++) sink += run();\n return now() - start;\n };\n let count = 1;\n const warmUntil = now() + warmMs;\n while (now() < warmUntil) {\n if (batch(\"a\", count) < targetMs / 4) count *= 2;\n batch(\"b\", count);\n }\n while (batch(\"a\", count) < targetMs) count *= 2;\n const records: PairedTime[] = [];\n for (let round = 0; round < rounds; round++) {\n const first = firstArm(round, offset);\n const second: Arm = first === \"a\" ? \"b\" : \"a\";\n const times = { [first]: batch(first, count), [second]: batch(second, count) } as Record<Arm, number>;\n records.push({ case: options.case, round, first, a: times.a, b: times.b });\n }\n return { records, count, sink };\n}\n"],"mappings":"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"}
|