@mark1russell7/rigor-bench 0.2.14 → 0.2.16

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 CHANGED
@@ -42,6 +42,11 @@ v.comparison; // the cases that gain and dro
42
42
  | `pooledBand(pool, level)` | The pooled band: the larger of the floor and the A/A spread of the records of earlier runs. |
43
43
  | `caseIntervals(records, level)` | The ratio of each case with a distribution-free interval of its median over the rounds. The level 0.95 needs 6 rounds or more. |
44
44
  | `limitVerdict(candidate, aa, options)` | The verdict of the claim "the ratio of each case is at most `limit`": `within`, `beyond` or `cannot decide`. |
45
+ | `tailLimitVerdict(candidate, aa, options)` | The verdict of the claim "the median and a high value of each case are at most their limits", for a bench with few rounds. |
46
+ | `caseTails(records, rank)` | The value at one rank of the ratios of each case, from the largest. |
47
+ | `tailFalseFails(aa, options)` | The cases of an A/A arm that the rule of `tailLimitVerdict` fails, and apart from these the cases with a limit under 1. |
48
+ | `gateOf(cases)` | The gate of a list of case outcomes: `pass`, `block` or `no read`. |
49
+ | `notSlowerVerdict(jobs, options)` | The gate of the claim "not slower by more than the margin", with looks and a family level. |
45
50
  | `budgetVerdict(rounds, aa, options)` | The verdict of the claim "the median of each case is at most `limit`", for one build: `within`, `beyond` or `cannot decide`. |
46
51
  | `budgetLooksVerdict(rounds, aa, options)` | The budget verdict of a run that adds rounds to the cases with no outcome, up to a stated budget. |
47
52
  | `budgetLookSpend(looks)` | The chance of error that a list of looks spends. |
@@ -78,6 +83,60 @@ v.cases; // the interval, the bound and
78
83
 
79
84
  The verdict has no correction for many cases. Each case has its own interval at the level `caseLevel`. Thus with many cases, a verdict `beyond` can come from noise only. Set `caseLevel` higher when a bench has many cases. A correction of Holm is an option for a later version.
80
85
 
86
+ ## A claim with a limit on a tail
87
+
88
+ `limitVerdict` needs an interval of the median, and a few rounds give a wide interval. `tailLimitVerdict` reads each value as it is. An example is a gate with 7 rounds and one limit for each module:
89
+
90
+ ```ts
91
+ const v = tailLimitVerdict(records, aaRecords, {
92
+ limit: (name) => limits[name],
93
+ aaCap: 1.3,
94
+ });
95
+ v.outcome; // "within", "beyond" or "cannot decide"
96
+ v.aaTail; // the largest tail of the A/A arm
97
+ ```
98
+
99
+ The rule of the verdict:
100
+
101
+ - The tail of a case is the value at `rank` of its ratios, from the largest. The default rank is 2, so one slow process cannot move it.
102
+ - A case is `beyond` when its median is over `limit.median`.
103
+ - A case is also `beyond` when its tail is over `limit.tail` and over the largest tail of the A/A arm of the run.
104
+ - Each case is `cannot decide` when the largest tail of the A/A arm is over `aaCap`. A loud run has no power, and this is not a pass. The caller takes another read.
105
+ - The option `aaCap` has no default, because a run with no cap passes each row when it is loud.
106
+ - The option `expected` names the cases that the run must have. A case of that list with no record reads `cannot decide`. Without this option, a run that loses a case reads the other cases only.
107
+ - `gateOf(v.cases)` gives the gate of the verdict: `pass`, `block` or `no read`.
108
+
109
+ With the default rank, a real cost in 1 round cannot fail the tail limit. This is by design: of 7 rounds, 1 round passes the tail, because 1 round cannot be told from noise. A cost in 2 rounds or more can fail it.
110
+
111
+ The verdict has no interval, so a limit needs a margin from the spread of earlier runs. `tailFalseFails` applies the rule to each case of an A/A arm. Each case reads the tail of the other cases. Print the count of `fails` on the gate, to state what the rule costs on noise.
112
+
113
+ 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 in `gains` with that reason. The false fails of a gain limit come from repeat reads of an unchanged tree against its fixed base.
114
+
115
+ ## A gate that can fail
116
+
117
+ A check that blocks a merge needs a result that can fail. `gateOf` reads the case outcomes of a verdict, and `notSlowerVerdict` gives the claim of a speed gate.
118
+
119
+ ```ts
120
+ const gate = notSlowerVerdict(jobs, { margin: Math.log(1.015) });
121
+
122
+ gate.outcome; // "pass", "block" or "no read"
123
+ gate.cases; // "not slower", "slower" or "no read" for each case, with the facts of each job
124
+ gate.more; // the next look of each case with no outcome
125
+ ```
126
+
127
+ - The claim is "not slower by more than the margin". A one-sided bound answers it, thus a case can read `not slower` when its interval holds 1. The word `same` of `timeVerdict` asks for more.
128
+ - The outcome of each case uses the words of `LimitOutcome`: `within` is `not slower`, `beyond` is `slower`, and `cannot decide` is `no read`. Thus `gateOf` also reads `limitVerdict` and `budgetVerdict`.
129
+ - A case needs its bound in each of `jobs` jobs, by default 2. More rounds do not remove a difference between jobs.
130
+ - The claim "the bound holds in at least `r` of `J` jobs" is a partial conjunction. Its p is `(J - r + 1)` times the `r`-th smallest p of the jobs (Benjamini and Heller, 2008). With 2 jobs of 2, this p is the larger p.
131
+ - The sign test compares the median difference with the margin in each job. It uses no random numbers.
132
+ - A pair holds two records with the same first arm. A runner can give the two arms opposite orders in one round, and a difference of two orders holds the effect of the order.
133
+ - The `level` is for the family. `holm` corrects each look over all cases. Each look has an equal share of the level.
134
+ - The first look with an outcome decides a case. `GATE_LOOKS` is 12, 24 and 48 rounds.
135
+ - Take 16 cases and the default looks. The first test of a family at 12 rounds needs 12 of 12 pairs below the margin in both jobs. Thus a noisy case needs more rounds, or it stays `no read`.
136
+ - `no read` is not a pass. A caller adds the rounds of `more`, then more jobs. A job that it adds after the last look is one more look, and the level does not count it.
137
+
138
+ The level needs independent rounds. Rounds with a shared cause, for example a slow computer for one job, do not have it.
139
+
81
140
  ## A claim with a budget
82
141
 
83
142
  `limitVerdict` judges a ratio of two arms. A budget is an absolute limit on one build. An example is "the median blocking time of this page is at most 450 ms". A budget needs `budgetVerdict`:
@@ -406,7 +465,7 @@ v.pool; // { cases, runs, spread, floo
406
465
  - The rule `difference` uses the larger of `margin` and the noise of the pooled band as its margin.
407
466
  - The run still needs its own A/A arm of 5 cases or more. The noise cap uses that arm.
408
467
 
409
- For a fixed limit, for example 1.10 against a fixed base, use `limitVerdict`.
468
+ For a fixed limit, for example 1.10 against a fixed base, use `limitVerdict`. With few rounds and a limit on a high value of each case, use `tailLimitVerdict`.
410
469
 
411
470
  ## The outcomes
412
471