@mark1russell7/rigor-statistics 0.1.18 → 0.1.20

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/build/index.js CHANGED
@@ -303,7 +303,7 @@ function sides(values, against) {
303
303
  };
304
304
  }
305
305
  /** The interval of the finite statistics of the runs. When no run is finite, low and high are equal to the estimate. */
306
- function ends(values, estimate, s, seed) {
306
+ function ends$1(values, estimate, s, seed) {
307
307
  const { runs, level } = s;
308
308
  const p = sides(values, s.against);
309
309
  if (values.length === 0) return {
@@ -341,7 +341,7 @@ function percentile(name, options, run, all) {
341
341
  const v = run(r);
342
342
  if (Number.isFinite(v)) values.push(v);
343
343
  }
344
- return ends(values, all(), s, r.seed);
344
+ return ends$1(values, all(), s, r.seed);
345
345
  }
346
346
  /**
347
347
  * The percentile bootstrap of `k` statistics from the same draws. Each run gives `k` statistics. Each statistic
@@ -356,7 +356,7 @@ function percentiles(name, options, k, run, all) {
356
356
  for (let j = 0; j < k; j++) if (Number.isFinite(v[j])) values[j].push(v[j]);
357
357
  }
358
358
  const estimate = all();
359
- return values.map((list, j) => ends(list, estimate[j], s, r.seed));
359
+ return values.map((list, j) => ends$1(list, estimate[j], s, r.seed));
360
360
  }
361
361
  /** A bootstrap interval of the median. */
362
362
  function bootstrapMedian(values, options = {}) {
@@ -399,7 +399,7 @@ function bootstrapClusters(rows, cluster, statistic, options = {}) {
399
399
  * The interval is narrow for a small sample. The draws give the variance of the sample with the divisor `m`, not
400
400
  * `m - 1`, so the width gets the factor `sqrt((m - 1) / m)`. The skew of the values adds to the miss. In the tests,
401
401
  * 400 samples of `m = 8` of `n = 40` hold the total 346 times (Wilson 0.828 to 0.895). At `m = 100` of `n = 200`,
402
- * the coverage agrees with 95%.
402
+ * the coverage agrees with 95%. For a total over the pairs of the items, use `uStatisticInterval`.
403
403
  */
404
404
  function sampleTotalInterval(values, options) {
405
405
  const name = "sampleTotalInterval";
@@ -2247,7 +2247,7 @@ function fitResponse(data, options = {}) {
2247
2247
  * The tests of a difference: the sign test, the paired permutation test, the Wilson interval of a proportion and
2248
2248
  * the Holm correction for several tests.
2249
2249
  */
2250
- function whole$1(name, value) {
2250
+ function whole$2(name, value) {
2251
2251
  if (!Number.isSafeInteger(value) || value < 0) throw new RangeError(`${name}: ${value} is not a whole number of 0 or more.`);
2252
2252
  }
2253
2253
  /** The log of each binomial term C(n, k) / 2^n, for each k from 0 to n. */
@@ -2275,8 +2275,8 @@ function upperTail(k, n) {
2275
2275
  * two times the tail of the larger count, at most 1. The one-sided p is equal to `signTestP` of packing.
2276
2276
  */
2277
2277
  function signTest(better, worse, sides = 1) {
2278
- whole$1("signTest", better);
2279
- whole$1("signTest", worse);
2278
+ whole$2("signTest", better);
2279
+ whole$2("signTest", worse);
2280
2280
  const n = better + worse;
2281
2281
  if (n === 0) return 1;
2282
2282
  if (sides === 1) return upperTail(better, n);
@@ -2287,7 +2287,7 @@ function signTest(better, worse, sides = 1) {
2287
2287
  * n wins out of n are not enough. Use it before a run, to know how many inputs a claim needs.
2288
2288
  */
2289
2289
  function signTestPower(n, level = .05, sides = 2) {
2290
- whole$1("signTestPower", n);
2290
+ whole$2("signTestPower", n);
2291
2291
  for (let k = Math.ceil(n / 2); k <= n; k++) if (signTest(k, n - k, sides) < level) return k;
2292
2292
  }
2293
2293
  /** The z of a two-sided 95% interval. */
@@ -2297,8 +2297,8 @@ const Z95 = 1.959963984540054;
2297
2297
  * a proportion near 0 or 1, where the normal interval does not. For n = 0 the interval is 0 to 1.
2298
2298
  */
2299
2299
  function wilson(k, n, z = Z95) {
2300
- whole$1("wilson", k);
2301
- whole$1("wilson", n);
2300
+ whole$2("wilson", k);
2301
+ whole$2("wilson", n);
2302
2302
  if (k > n) throw new RangeError(`wilson: k ${k} is more than n ${n}.`);
2303
2303
  if (n === 0) return {
2304
2304
  low: 0,
@@ -2345,7 +2345,7 @@ function holm(pValues, level = .05) {
2345
2345
  */
2346
2346
  function partialConjunction(pValues, need) {
2347
2347
  for (const p of pValues) if (!(p >= 0 && p <= 1)) throw new RangeError(`partialConjunction: each p is from 0 to 1, not ${p}.`);
2348
- whole$1("partialConjunction", need);
2348
+ whole$2("partialConjunction", need);
2349
2349
  const m = pValues.length;
2350
2350
  if (need < 1 || need > m) throw new RangeError(`partialConjunction: need is from 1 to the count of tests ${m}, not ${need}.`);
2351
2351
  const sorted = [...pValues].sort((a, b) => a - b);
@@ -2448,7 +2448,7 @@ function twoSamplePermutation(a, b, options = {}) {
2448
2448
  */
2449
2449
  function wilsonSampleSize(target, expected, z = Z95, max = 1e6) {
2450
2450
  if (!(target >= 0 && target <= 1 && expected >= 0 && expected <= 1)) throw new RangeError(`wilsonSampleSize: target ${target} and expected ${expected} must be from 0 to 1.`);
2451
- whole$1("wilsonSampleSize", max);
2451
+ whole$2("wilsonSampleSize", max);
2452
2452
  if (expected <= target) return void 0;
2453
2453
  for (let n = 1; n <= max; n++) if (wilson(Math.round(expected * n), n, z).low >= target) return n;
2454
2454
  }
@@ -2566,7 +2566,7 @@ function kendallTau(a, b, seed = 1) {
2566
2566
  * The intervals that come from a discrete distribution. The interval of a median or of a quantile comes from the order
2567
2567
  * statistics. The central interval of a count comes from a binomial or a negative binomial distribution.
2568
2568
  */
2569
- function whole(name, value) {
2569
+ function whole$1(name, value) {
2570
2570
  if (!Number.isSafeInteger(value) || value < 0) throw new RangeError(`${name}: ${value} is not a whole number of 0 or more.`);
2571
2571
  }
2572
2572
  function levelOf(name, level) {
@@ -2675,7 +2675,7 @@ function quantileSamples(p, level = .95) {
2675
2675
  * or less. The two tails are separate sums, so that a small upper tail keeps its digits.
2676
2676
  */
2677
2677
  function binomialInterval(n, p, level = .95) {
2678
- whole("binomialInterval", n);
2678
+ whole$1("binomialInterval", n);
2679
2679
  if (!(p >= 0 && p <= 1)) throw new RangeError(`binomialInterval: p is from 0 to 1, not ${p}.`);
2680
2680
  const tail = levelOf("binomialInterval", level);
2681
2681
  const terms = binomialTerms(n, p);
@@ -2700,12 +2700,47 @@ function binomialInterval(n, p, level = .95) {
2700
2700
  };
2701
2701
  }
2702
2702
  /**
2703
+ * This function gives the p of the exact one-sided binomial test of `k` successes in `n` trials, with
2704
+ * X ~ Binomial(n, p). The side `"less"` gives `P(X <= k)`. A small value rejects the claim "the chance is `p` or
2705
+ * more". The side `"greater"` gives `P(X >= k)`. A small value rejects the claim "the chance is `p` or less".
2706
+ *
2707
+ * The sum starts at the largest term of the tail, so a small tail keeps its digits. At `p = 1/2`, the side
2708
+ * `"greater"` is equal to the one-sided `signTest(k, n - k)`.
2709
+ *
2710
+ * @param k - The count of successes, a whole number from 0 to `n`.
2711
+ * @param n - The count of trials, a whole number of 0 or more.
2712
+ * @param p - The chance of a success under the claim, from 0 to 1.
2713
+ * @param side - The side of the tail.
2714
+ * @returns The p of the test, from 0 to 1.
2715
+ */
2716
+ function binomialTest(k, n, p, side) {
2717
+ whole$1("binomialTest", k);
2718
+ whole$1("binomialTest", n);
2719
+ if (k > n) throw new RangeError(`binomialTest: k ${k} is more than n ${n}.`);
2720
+ if (!(p >= 0 && p <= 1)) throw new RangeError(`binomialTest: p is from 0 to 1, not ${p}.`);
2721
+ if (side !== "less" && side !== "greater") throw new RangeError(`binomialTest: side is "less" or "greater", not ${String(side)}.`);
2722
+ const [from, to] = side === "less" ? [0, k] : [k, n];
2723
+ if (from === 0 && to === n) return 1;
2724
+ if (p === 0) return from === 0 ? 1 : 0;
2725
+ if (p === 1) return to === n ? 1 : 0;
2726
+ const [logP, logQ] = [Math.log(p), Math.log1p(-p)];
2727
+ const logs = [];
2728
+ let logChoose = 0;
2729
+ for (let i = 0; i <= to; i++) {
2730
+ if (i > 0) logChoose += Math.log((n - i + 1) / i);
2731
+ if (i >= from) logs.push(logChoose + i * logP + (n - i) * logQ);
2732
+ }
2733
+ const top = Math.max(...logs);
2734
+ const sum = logs.reduce((s, l) => s + Math.exp(l - top), 0);
2735
+ return Math.min(1, Math.exp(top) * sum);
2736
+ }
2737
+ /**
2703
2738
  * The central interval of a negative binomial count. X is the count of failures before `successes` successes, and
2704
2739
  * `p` is the chance of a success at each try. `low` is the smallest k with P(X <= k) > (1 - level) / 2.
2705
2740
  * `high` is the smallest k with P(X <= k) >= 1 - (1 - level) / 2.
2706
2741
  */
2707
2742
  function negativeBinomialInterval(successes, p, level = .95) {
2708
- whole("negativeBinomialInterval", successes);
2743
+ whole$1("negativeBinomialInterval", successes);
2709
2744
  if (!(p > 0 && p <= 1)) throw new RangeError(`negativeBinomialInterval: p is more than 0 and 1 or less, not ${p}.`);
2710
2745
  const tail = levelOf("negativeBinomialInterval", level);
2711
2746
  const logQ = Math.log1p(-p);
@@ -2972,6 +3007,286 @@ function optionFloor(options) {
2972
3007
  }
2973
3008
  throw new RangeError(`optionFloor: no count under 10,000,000 for sigma ${sigma} and delta ${delta}.`);
2974
3009
  }
2975
- export { KENDALL_EXACT, RESPONSE_LAMBDAS, RESPONSE_MAX_POWER, RESPONSE_MAX_TERMS, RESPONSE_RECORDS_SCHEMA, Z95, bestSmoothLaw, binomialInterval, bootstrap, bootstrapClusters, bootstrapLeastSquares, bootstrapMedian, bootstrapMedianRatio, bootstrapTwo, brier, calibration, cohenKappa, compareRatios, fitResponse, heldOutError, heldOutErrorAt, holm, kendallTau, leastSquares, mean, median, medianInterval, modeCount, negativeBinomialInterval, noiseFloor, noiseVerdict, optionFloor, pairedPermutation, parseResponseRecord, partialConjunction, predictResponse, quantile, quantileInterval, quantileSamples, quantileSorted, ranks, responseCells, ridgeSolve, sampleTotalInterval, sd, signTest, signTestPower, sliceResponse, smoothLawScores, sorted, spearman, summarize, surfaceResponse, tQuantile, twoSamplePermutation, whenHolds, wilson, wilsonSampleSize };
3010
+ // src/coverage.ts
3011
+ /**
3012
+ * The rule that finds the smallest sample at which an interval method keeps its level. The input is the hits of the
3013
+ * method on the true value in seeded cells. The bar is fixed before the run.
3014
+ */
3015
+ function whole(name, value, min) {
3016
+ if (!Number.isSafeInteger(value) || value < min) throw new RangeError(`coverageMinSample: ${name} is a whole number of ${min} or more, not ${value}.`);
3017
+ }
3018
+ /**
3019
+ * This function applies a fixed bar of coverage to the cells of a study. It gives the smallest sample size `m` from
3020
+ * which an interval method keeps its level. The method qualifies at `m` when the cells with a sample of `m` or more
3021
+ * pass two tests:
3022
+ *
3023
+ * 1. No cell rejects the coverage `level`. Each cell has the exact one-sided binomial test `P(X <= hits)`, with
3024
+ * X ~ Binomial(draws, level). The family of these tests gets the Holm correction at `alpha`.
3025
+ * 2. The Wilson lower end of the pooled coverage, the sum of the hits over the sum of the draws, is `pooledLow`
3026
+ * or more.
3027
+ *
3028
+ * Each step tells the result of the two tests at its `m`. A step does not depend on the steps of other sizes. At a
3029
+ * small `m`, the pool also holds the cells of the larger sizes. Thus a small `m` can pass while a larger `m` fails
3030
+ * alone, for example near `m = n`.
3031
+ *
3032
+ * Thus the set of sizes is closed upward. The result is the smallest `m` of the cells such that each size of `m` or
3033
+ * more qualifies. The field `blocking` gives the largest size that fails. When the largest size fails, the result is
3034
+ * infinite.
3035
+ *
3036
+ * @param cells - The hits and the draws of each cell. Each cell has its own sample size.
3037
+ * @param bar - The level, the alpha of the Holm family and the pooled lower end.
3038
+ * @returns The smallest size from which each size qualifies, the size that blocks, and the result at each size.
3039
+ */
3040
+ function coverageMinSample(cells, bar) {
3041
+ const { level, alpha, pooledLow } = bar;
3042
+ const z = bar.z ?? 1.959963984540054;
3043
+ if (!(level > 0 && level < 1)) throw new RangeError(`coverageMinSample: level is more than 0 and less than 1, not ${level}.`);
3044
+ if (!(alpha > 0 && alpha < 1)) throw new RangeError(`coverageMinSample: alpha is more than 0 and less than 1, not ${alpha}.`);
3045
+ if (!(pooledLow >= 0 && pooledLow <= 1)) throw new RangeError(`coverageMinSample: pooledLow is from 0 to 1, not ${pooledLow}.`);
3046
+ if (!(z > 0 && Number.isFinite(z))) throw new RangeError(`coverageMinSample: z is a finite number more than 0, not ${z}.`);
3047
+ for (const cell of cells) {
3048
+ whole("sample", cell.sample, 1);
3049
+ whole("draws", cell.draws, 1);
3050
+ whole("hits", cell.hits, 0);
3051
+ if (cell.hits > cell.draws) throw new RangeError(`coverageMinSample: the hits ${cell.hits} of the cell ${cell.name} are more than its draws ${cell.draws}.`);
3052
+ }
3053
+ const p = cells.map((cell) => binomialTest(cell.hits, cell.draws, level, "less"));
3054
+ const steps = [...new Set(cells.map((cell) => cell.sample))].sort((a, b) => a - b).map((m) => {
3055
+ const at = cells.map((cell, i) => ({
3056
+ cell,
3057
+ p: p[i]
3058
+ })).filter(({ cell }) => cell.sample >= m);
3059
+ const corrected = holm(at.map(({ p: value }) => value), alpha);
3060
+ const rejected = at.filter((_, i) => corrected[i]?.reject === true).map(({ cell }) => cell.name);
3061
+ const smallestAdjusted = Math.min(...corrected.map((c) => c.adjusted));
3062
+ let hits = 0;
3063
+ let draws = 0;
3064
+ for (const { cell } of at) {
3065
+ hits += cell.hits;
3066
+ draws += cell.draws;
3067
+ }
3068
+ const pooled = wilson(hits, draws, z);
3069
+ const cellOk = rejected.length === 0;
3070
+ const pooledOk = pooled.low >= pooledLow;
3071
+ const reason = cellOk ? pooledOk ? "qualifies" : "pooled-low" : pooledOk ? "cell-rejected" : "cell-rejected-and-pooled-low";
3072
+ return {
3073
+ sample: m,
3074
+ cells: at.length,
3075
+ rejected,
3076
+ smallestAdjusted,
3077
+ hits,
3078
+ draws,
3079
+ pooled,
3080
+ qualifies: cellOk && pooledOk,
3081
+ reason
3082
+ };
3083
+ });
3084
+ let minSample = Number.POSITIVE_INFINITY;
3085
+ let blocking;
3086
+ for (let i = steps.length - 1; i >= 0; i--) {
3087
+ const step = steps[i];
3088
+ if (!step.qualifies) {
3089
+ blocking = step.sample;
3090
+ break;
3091
+ }
3092
+ minSample = step.sample;
3093
+ }
3094
+ return blocking === void 0 ? {
3095
+ minSample,
3096
+ steps
3097
+ } : {
3098
+ minSample,
3099
+ blocking,
3100
+ steps
3101
+ };
3102
+ }
3103
+ // src/u-statistic.ts
3104
+ /**
3105
+ * The interval of a U-statistic from a uniform sample of `m` of `n` units, drawn without replacement. A kernel `h`
3106
+ * gives a value to each set of `r` units. The total of the population is the sum of `h` over all its sets of `r`.
3107
+ */
3108
+ /**
3109
+ * The smallest sample `m` at which the method `"auto"` uses the method `"tight"`. The calibration study
3110
+ * `u-statistic-interval` gives the value with `coverageMinSample`. The value is the smallest `m` of the grid such that
3111
+ * each `m` of the grid from this value up passes the bar. Until a run of the study gives a value, the value is
3112
+ * infinite. The TSDoc of `uStatisticInterval` gives the bar of the study.
3113
+ */
3114
+ const U_STATISTIC_TIGHT_MIN_SAMPLE = Number.POSITIVE_INFINITY;
3115
+ /**
3116
+ * This function gives the interval of a total over all the sets of `r` units of a population. The data is a uniform
3117
+ * sample of `m` of the `n` units, without replacement. An example is the count of crossings between all pairs of
3118
+ * routes. The input is the total of each sampled unit: the sum of the kernel over the sets of `r` sampled units
3119
+ * that hold the unit. Thus the sum of the totals is `r * S`, with `S` the total of the sample. The kernel is
3120
+ * symmetric.
3121
+ *
3122
+ * The estimate is `S * C(n, r) / C(m, r)`. It is the U-statistic `U = S / C(m, r)` times `C(n, r)`. At `r = 1`,
3123
+ * the estimate is `n / m` times the sum of the sample. When `m` is `n`, the interval is the estimate.
3124
+ *
3125
+ * The method `"conservative"` uses the inequality of Hoeffding (1963) for U-statistics, with `k = floor(m / r)`. The
3126
+ * half width of the mean is `(b - a) * sqrt(ln(2 / (1 - level)) / (2 k))`, with `[a, b]` the range of the kernel.
3127
+ * The bound is also true for a sample without replacement (Ai, Kuželka and Wang 2022, Blanc 2023 Theorem 6).
3128
+ * Thus the interval holds at each `m`. It is wide at a small `m`.
3129
+ *
3130
+ * The method `"tight"` uses the jackknife variance of `U`, from the totals only, times the finite population
3131
+ * correction `1 - m / n`. The interval is `U` plus or minus the t quantile with `m - 1` degrees of freedom, times
3132
+ * the standard error.
3133
+ *
3134
+ * The correction comes from the inclusion probabilities of a sample without replacement. The variance of the linear
3135
+ * part of `U` (its Hájek projection) gets exactly the factor `1 - m / n`. The variance of the remainder gets a
3136
+ * smaller factor, near `(1 - m / n)^2`, relative to an independent sample. For `r = 2` this factor is
3137
+ * `(n - m)(n - m - 1) / ((n - 2)(n - 3))`. Thus this estimate of the variance is exact for a linear kernel, and
3138
+ * larger than the variance for other kernels. The tests read the two facts over all samples of small populations.
3139
+ *
3140
+ * The method `"tight"` does not give an interval of width 0 when `m` is less than `n`. When all the totals are
3141
+ * equal, the jackknife variance is 0. Then the function uses the method `"conservative"` for the sample, and the
3142
+ * result has `method: "conservative"`. Without `range`, the function throws a `RangeError` for this sample.
3143
+ *
3144
+ * The method `"tight"` has no proof of its coverage. The tests use 200 samples of made-up populations at the level
3145
+ * 0.95. The table gives the hits of 200 for each population `n` and sample `m`. Each count includes the fallback.
3146
+ *
3147
+ * | n / m | sparse | crossings | skewed |
3148
+ * | --- | --- | --- | --- |
3149
+ * | 40 / 8 | 200 | 200 | 183 |
3150
+ * | 40 / 10 | 200 | 200 | 187 |
3151
+ * | 40 / 12 | 200 | 183 | 189 |
3152
+ * | 40 / 20 | 180 | 183 | 188 |
3153
+ * | 40 / 36 | 192 | 189 | 193 |
3154
+ * | 60 / 8 | 200 | 200 | 181 |
3155
+ * | 60 / 10 | 200 | 200 | 180 |
3156
+ * | 60 / 12 | 200 | 195 | 186 |
3157
+ * | 60 / 20 | 184 | 190 | 183 |
3158
+ * | 60 / 40 | 186 | 193 | 180 |
3159
+ * | 120 / 8 | 200 | 200 | 177 |
3160
+ * | 120 / 10 | 200 | 192 | 175 |
3161
+ * | 120 / 12 | 200 | 189 | 178 |
3162
+ * | 120 / 20 | 191 | 193 | 182 |
3163
+ * | 120 / 40 | 194 | 192 | 185 |
3164
+ * | 120 / 60 | 195 | 189 | 185 |
3165
+ * | 120 / 108 | 187 | 185 | 190 |
3166
+ *
3167
+ * The sparse kernel holds 2% to 3% of the pairs. The skewed kernel has a few large values. At `m = 8`, the skewed
3168
+ * kernel gets 177 to 183 of 200, a coverage of 0.885 to 0.915. No row has 190 or more in each kernel.
3169
+ *
3170
+ * The method `"auto"` needs `range`. It uses the method `"tight"` when `m` is `U_STATISTIC_TIGHT_MIN_SAMPLE` or more
3171
+ * and the variance is more than 0. Otherwise, it uses the method `"conservative"`.
3172
+ *
3173
+ * The calibration study `u-statistic-interval` sets `U_STATISTIC_TIGHT_MIN_SAMPLE`. Its bar was fixed before its run.
3174
+ * The study draws 1000 samples in each cell of the 3 kernels and the 17 cells of the table. The method `"tight"`
3175
+ * qualifies at `m` when the cells with a sample of `m` or more pass two tests.
3176
+ *
3177
+ * First, no cell rejects the coverage 0.95 in a one-sided exact binomial test at alpha 0.05, with the Holm
3178
+ * correction over these cells. Second, the Wilson lower end of the pooled coverage of these cells is 0.94 or more.
3179
+ * `coverageMinSample` applies this bar.
3180
+ *
3181
+ * The set of sizes is closed upward. The constant is the smallest `m` of the grid such that each `m` of the grid from
3182
+ * this value up qualifies. A small `m` pools the good cells of the larger sizes, so it can pass while a larger `m`
3183
+ * fails alone. The upward rule keeps the method `"auto"` away from a size that failed.
3184
+ *
3185
+ * When the largest `m` fails, the constant is infinite. Until a run of the study gives a value, the constant is infinite. Thus the method `"auto"`
3186
+ * uses the method `"conservative"` at each `m` less than `n`.
3187
+ *
3188
+ * With `range`, the interval of the mean stays in `[a, b]`, and each total is in the range of a sum of
3189
+ * `C(m - 1, r - 1)` kernel values.
3190
+ *
3191
+ * @param totals - The total of each unit of the sample. The sample has more units than `r`.
3192
+ * @param options - The order, the population, the method, the level and the range of the kernel.
3193
+ * @returns The estimate and the interval of the total, and of the mean of the kernel.
3194
+ */
3195
+ function uStatisticInterval(totals, options) {
3196
+ const name = "uStatisticInterval";
3197
+ const { order: r, population: n, method: requested } = options;
3198
+ const m = totals.length;
3199
+ const level = options.level ?? .95;
3200
+ if (!Number.isSafeInteger(r) || r < 1) throw new RangeError(`${name}: order is a whole number of 1 or more, not ${r}.`);
3201
+ if (m <= r) throw new RangeError(`${name}: the sample has more units than the order ${r}, not ${m}.`);
3202
+ if (!Number.isSafeInteger(n) || n < m) throw new RangeError(`${name}: population is a whole number of ${m} (the sample) or more, not ${n}.`);
3203
+ if (requested !== "conservative" && requested !== "tight" && requested !== "auto") throw new RangeError(`${name}: method is "conservative", "tight" or "auto", not ${String(requested)}.`);
3204
+ if (!(level > 0 && level < 1)) throw new RangeError(`${name}: level is more than 0 and less than 1, not ${level}.`);
3205
+ for (const t of totals) if (!Number.isFinite(t)) throw new RangeError(`${name}: each total is a finite number, not ${t}.`);
3206
+ const range = options.range;
3207
+ if (range !== void 0) {
3208
+ const [a, b] = range;
3209
+ if (!(Number.isFinite(a) && Number.isFinite(b) && a < b)) throw new RangeError(`${name}: range is two finite numbers a < b, not ${a} and ${b}.`);
3210
+ const sets = choose(m - 1, r - 1);
3211
+ const slack = 1e-9 * Math.max(Math.abs(a), Math.abs(b)) * sets;
3212
+ for (const t of totals) if (t < a * sets - slack || t > b * sets + slack) throw new RangeError(`${name}: each total is from ${a * sets} to ${b * sets} for this range, not ${t}.`);
3213
+ } else if (requested !== "tight") throw new RangeError(`${name}: the method "${requested}" needs the range of the kernel.`);
3214
+ let sum = 0;
3215
+ for (const t of totals) sum += t;
3216
+ const s = sum / r;
3217
+ const subsets = choose(n, r);
3218
+ const sampleSets = choose(m, r);
3219
+ const estimate = s * subsets / sampleSets;
3220
+ const u = s / sampleSets;
3221
+ const base = {
3222
+ estimate,
3223
+ level,
3224
+ requested,
3225
+ subsets
3226
+ };
3227
+ const centre = sum / m;
3228
+ let squares = 0;
3229
+ for (const t of totals) squares += (t - centre) ** 2;
3230
+ const variance = totals.every((t) => t === totals[0]) ? 0 : (1 - m / n) * ((m - 1) / m) * squares / choose(m - 1, r) ** 2;
3231
+ if (m === n) {
3232
+ const method = requested === "conservative" || requested === "auto" && m < U_STATISTIC_TIGHT_MIN_SAMPLE ? "conservative" : "tight";
3233
+ return {
3234
+ ...base,
3235
+ low: estimate,
3236
+ high: estimate,
3237
+ method,
3238
+ mean: {
3239
+ estimate: u,
3240
+ low: u,
3241
+ high: u
3242
+ },
3243
+ ...method === "tight" ? {
3244
+ standardError: 0,
3245
+ df: m - 1
3246
+ } : {}
3247
+ };
3248
+ }
3249
+ if ((requested === "tight" || requested === "auto" && m >= U_STATISTIC_TIGHT_MIN_SAMPLE) && variance > 0) {
3250
+ const df = m - 1;
3251
+ const se = Math.sqrt(variance);
3252
+ const half = tQuantile(1 - (1 - level) / 2, df) * se;
3253
+ return {
3254
+ ...base,
3255
+ method: "tight",
3256
+ ...ends(u, u - half, u + half, range, subsets),
3257
+ standardError: se * subsets,
3258
+ df
3259
+ };
3260
+ }
3261
+ if (range === void 0) throw new RangeError(`${name}: the jackknife variance is 0, because all the totals are equal. Give the range, or use the method "conservative".`);
3262
+ const k = Math.floor(m / r);
3263
+ const half = (range[1] - range[0]) * Math.sqrt(Math.log(2 / (1 - level)) / (2 * k));
3264
+ return {
3265
+ ...base,
3266
+ method: "conservative",
3267
+ ...ends(u, u - half, u + half, range, subsets)
3268
+ };
3269
+ }
3270
+ /** This function gives the interval of the mean in the range, if there is a range, and scales it to the total. */
3271
+ function ends(u, lowMean, highMean, range, subsets) {
3272
+ const low = range ? Math.max(range[0], lowMean) : lowMean;
3273
+ const high = range ? Math.min(range[1], highMean) : highMean;
3274
+ return {
3275
+ low: low * subsets,
3276
+ high: high * subsets,
3277
+ mean: {
3278
+ estimate: u,
3279
+ low,
3280
+ high
3281
+ }
3282
+ };
3283
+ }
3284
+ /** The binomial coefficient `C(n, k)`, as a product. Each step is a whole number, so it is exact below 2^53. */
3285
+ function choose(n, k) {
3286
+ let c = 1;
3287
+ for (let j = 0; j < k; j++) c = c * (n - j) / (j + 1);
3288
+ return c;
3289
+ }
3290
+ export { KENDALL_EXACT, RESPONSE_LAMBDAS, RESPONSE_MAX_POWER, RESPONSE_MAX_TERMS, RESPONSE_RECORDS_SCHEMA, U_STATISTIC_TIGHT_MIN_SAMPLE, Z95, bestSmoothLaw, binomialInterval, binomialTest, bootstrap, bootstrapClusters, bootstrapLeastSquares, bootstrapMedian, bootstrapMedianRatio, bootstrapTwo, brier, calibration, cohenKappa, compareRatios, coverageMinSample, fitResponse, heldOutError, heldOutErrorAt, holm, kendallTau, leastSquares, mean, median, medianInterval, modeCount, negativeBinomialInterval, noiseFloor, noiseVerdict, optionFloor, pairedPermutation, parseResponseRecord, partialConjunction, predictResponse, quantile, quantileInterval, quantileSamples, quantileSorted, ranks, responseCells, ridgeSolve, sampleTotalInterval, sd, signTest, signTestPower, sliceResponse, smoothLawScores, sorted, spearman, summarize, surfaceResponse, tQuantile, twoSamplePermutation, uStatisticInterval, whenHolds, wilson, wilsonSampleSize };
2976
3291
 
2977
3292
  //# sourceMappingURL=index.js.map