nano-benchmark 1.0.13 → 1.0.14

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  BSD 3-Clause License
2
2
 
3
- Copyright (c) 2022, Eugene Lazutkin
3
+ Copyright (c) 2022-2026, Eugene Lazutkin
4
4
  All rights reserved.
5
5
 
6
6
  Redistribution and use in source and binary forms, with or without
package/README.md CHANGED
@@ -111,6 +111,7 @@ BSD 3-Clause License
111
111
 
112
112
  ## Release history
113
113
 
114
+ - 1.0.14: _Fixed Kruskal-Wallis post-hoc (Conover-Iman) pairwise comparison bug: corrected rank variance computation and critical value distribution. Added regression test._
114
115
  - 1.0.13: _Improved CLI help texts and documentation for brevity and clarity._
115
116
  - 1.0.12: _Added AI coding skills for writing benchmark files (write-bench, write-watch), shipped via npm. Added findLevel() tests. Expanded test suite._
116
117
  - 1.0.11: _Fixed MedianCounter.clone() bug, expanded test suite (204 tests), added CodeQL workflow, multi-OS CI matrix, and new Windsurf workflows._
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nano-benchmark",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "CLI micro-benchmarking with nonparametric statistics and significance testing.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -1,9 +1,12 @@
1
1
  // Kruskal-Wallis significance test
2
- // based on https://en.wikipedia.org/wiki/Kruskal%E2%80%93Wallis_one-way_analysis_of_variance
3
- // beta approximation: https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.661.7863&rep=rep1&type=pdf
2
+ // https://en.wikipedia.org/wiki/Kruskal%E2%80%93Wallis_one-way_analysis_of_variance
3
+ // beta approximation for H: https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.661.7863&rep=rep1&type=pdf
4
+ // Conover-Iman post-hoc pairwise comparisons (Fisher's LSD on ranks):
5
+ // https://www.statsdirect.com/help/nonparametric_methods/kruskal_wallis.htm
6
+ // uses Student t(N-k) critical value, approximated here by z for large df
4
7
 
5
8
  import betaPpf from '../stats/beta-ppf.js';
6
- import chiSquaredPpf from '../stats/chi-squared-ppf.js';
9
+ import zPpf from '../stats/z-ppf.js';
7
10
  import rank, {getTotal} from '../stats/rank.js';
8
11
 
9
12
  export const getParameters = (groups, N = getTotal(groups)) => {
@@ -29,18 +32,18 @@ export const rankData = groups => {
29
32
  for (let i = 0; i < avgGroupRank.length; ++i) {
30
33
  const x = avgGroupRank[i] - avgRank;
31
34
  numerator += groups[i].length * x * x;
32
- T += (groupRank[i] * groupRank[i]) / groups[i].length - avgRankC;
35
+ T += (groupRank[i] * groupRank[i]) / groups[i].length;
33
36
  }
37
+ T -= avgRankC;
34
38
 
35
39
  let denominator = 0,
36
40
  S2 = 0;
37
41
  for (let i = 0; i < t.length; ++i) {
38
42
  const x = t[i].rank - avgRank;
39
43
  denominator += x * x;
40
- S2 += t[i].rank * t[i].rank - avgRankC;
44
+ S2 += t[i].rank * t[i].rank;
41
45
  }
42
-
43
- S2 /= N - 1;
46
+ S2 = (S2 - avgRankC) / (N - 1);
44
47
  T /= S2;
45
48
 
46
49
  // calculate and return H statistics
@@ -57,10 +60,11 @@ export const kwtest = (sortedArrays, alpha = 0.05) => {
57
60
 
58
61
  if (!results.different || k < 3) return results;
59
62
 
60
- // post-hoc tests
63
+ // Conover-Iman post-hoc: pairwise significance using t(N-k), approximated by z.
64
+ // groupDifference[i][j] is true when pair (i,j) is significantly different.
61
65
 
62
66
  const m = new Array(k),
63
- C = chiSquaredPpf(1 - alpha / 2, N - k) * Math.sqrt((S2 * (N - 1 - T)) / (N - k));
67
+ C = zPpf(1 - alpha / 2) * Math.sqrt((S2 * (N - 1 - T)) / (N - k));
64
68
 
65
69
  for (let i = 0; i < k; ++i) {
66
70
  m[i] = new Array(k);