@fuzdev/fuz_util 0.43.0 → 0.44.0
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/dist/benchmark_baseline.d.ts.map +1 -1
- package/dist/benchmark_baseline.js +5 -32
- package/dist/benchmark_format.d.ts +7 -12
- package/dist/benchmark_format.d.ts.map +1 -1
- package/dist/benchmark_format.js +19 -80
- package/dist/benchmark_stats.d.ts.map +1 -1
- package/dist/benchmark_stats.js +3 -120
- package/dist/git.d.ts +12 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +14 -0
- package/dist/maths.d.ts +4 -0
- package/dist/maths.d.ts.map +1 -1
- package/dist/maths.js +8 -0
- package/dist/source_json.d.ts +4 -4
- package/dist/stats.d.ts +58 -4
- package/dist/stats.d.ts.map +1 -1
- package/dist/stats.js +151 -11
- package/dist/string.d.ts +13 -0
- package/dist/string.d.ts.map +1 -1
- package/dist/string.js +58 -0
- package/dist/time.d.ts +4 -0
- package/dist/time.d.ts.map +1 -1
- package/dist/time.js +4 -0
- package/package.json +1 -1
- package/src/lib/benchmark_baseline.ts +5 -40
- package/src/lib/benchmark_format.ts +19 -84
- package/src/lib/benchmark_stats.ts +4 -141
- package/src/lib/git.ts +24 -0
- package/src/lib/maths.ts +8 -0
- package/src/lib/stats.ts +193 -12
- package/src/lib/string.ts +66 -0
- package/src/lib/time.ts +5 -0
package/dist/stats.d.ts
CHANGED
|
@@ -95,18 +95,18 @@ export declare const stats_outliers_mad: (values: Array<number>, options?: Stats
|
|
|
95
95
|
/**
|
|
96
96
|
* Common z-scores for confidence intervals.
|
|
97
97
|
*/
|
|
98
|
-
export declare const
|
|
98
|
+
export declare const STATS_CONFIDENCE_Z_SCORES: Record<number, number>;
|
|
99
99
|
/**
|
|
100
100
|
* Convert a confidence level (0-1) to a z-score.
|
|
101
101
|
* Uses a lookup table for common values, approximates others.
|
|
102
102
|
*
|
|
103
103
|
* @example
|
|
104
104
|
* ```ts
|
|
105
|
-
*
|
|
106
|
-
*
|
|
105
|
+
* stats_confidence_level_to_z_score(0.95); // 1.96
|
|
106
|
+
* stats_confidence_level_to_z_score(0.99); // 2.576
|
|
107
107
|
* ```
|
|
108
108
|
*/
|
|
109
|
-
export declare const
|
|
109
|
+
export declare const stats_confidence_level_to_z_score: (level: number) => number;
|
|
110
110
|
/**
|
|
111
111
|
* Configuration options for confidence interval calculation.
|
|
112
112
|
*/
|
|
@@ -123,4 +123,58 @@ export interface StatsConfidenceIntervalOptions {
|
|
|
123
123
|
* @returns [lower_bound, upper_bound]
|
|
124
124
|
*/
|
|
125
125
|
export declare const stats_confidence_interval: (values: Array<number>, options?: StatsConfidenceIntervalOptions) => [number, number];
|
|
126
|
+
/**
|
|
127
|
+
* Calculate confidence interval from summary statistics (mean, std_dev, sample_size).
|
|
128
|
+
* Useful when raw data is not available.
|
|
129
|
+
* @param mean - Mean of the data
|
|
130
|
+
* @param std_dev - Standard deviation of the data
|
|
131
|
+
* @param sample_size - Number of samples
|
|
132
|
+
* @param options - Configuration options
|
|
133
|
+
* @returns [lower_bound, upper_bound]
|
|
134
|
+
*/
|
|
135
|
+
export declare const stats_confidence_interval_from_summary: (mean: number, std_dev: number, sample_size: number, options?: StatsConfidenceIntervalOptions) => [number, number];
|
|
136
|
+
/**
|
|
137
|
+
* Result from Welch's t-test calculation.
|
|
138
|
+
*/
|
|
139
|
+
export interface StatsWelchTTestResult {
|
|
140
|
+
/** The t-statistic */
|
|
141
|
+
t_statistic: number;
|
|
142
|
+
/** Welch-Satterthwaite degrees of freedom */
|
|
143
|
+
degrees_of_freedom: number;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Calculate Welch's t-test statistic and degrees of freedom.
|
|
147
|
+
* Welch's t-test is more robust than Student's t-test when variances are unequal.
|
|
148
|
+
*
|
|
149
|
+
* @param mean1 - Mean of first sample
|
|
150
|
+
* @param std1 - Standard deviation of first sample
|
|
151
|
+
* @param n1 - Size of first sample
|
|
152
|
+
* @param mean2 - Mean of second sample
|
|
153
|
+
* @param std2 - Standard deviation of second sample
|
|
154
|
+
* @param n2 - Size of second sample
|
|
155
|
+
*/
|
|
156
|
+
export declare const stats_welch_t_test: (mean1: number, std1: number, n1: number, mean2: number, std2: number, n2: number) => StatsWelchTTestResult;
|
|
157
|
+
/**
|
|
158
|
+
* Standard normal CDF approximation (Abramowitz and Stegun formula 7.1.26).
|
|
159
|
+
*/
|
|
160
|
+
export declare const stats_normal_cdf: (x: number) => number;
|
|
161
|
+
/**
|
|
162
|
+
* Log gamma function approximation (Lanczos approximation).
|
|
163
|
+
*/
|
|
164
|
+
export declare const stats_ln_gamma: (z: number) => number;
|
|
165
|
+
/**
|
|
166
|
+
* Approximate regularized incomplete beta function for p-value calculation.
|
|
167
|
+
* Uses continued fraction expansion for reasonable accuracy.
|
|
168
|
+
*/
|
|
169
|
+
export declare const stats_incomplete_beta: (x: number, a: number, b: number) => number;
|
|
170
|
+
/**
|
|
171
|
+
* Approximate two-tailed p-value from t-distribution.
|
|
172
|
+
* For large df (>100), uses normal approximation.
|
|
173
|
+
* For smaller df, uses incomplete beta function.
|
|
174
|
+
*
|
|
175
|
+
* @param t - Absolute value of t-statistic
|
|
176
|
+
* @param df - Degrees of freedom
|
|
177
|
+
* @returns Two-tailed p-value
|
|
178
|
+
*/
|
|
179
|
+
export declare const stats_t_distribution_p_value: (t: number, df: number) => number;
|
|
126
180
|
//# sourceMappingURL=stats.d.ts.map
|
package/dist/stats.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stats.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/stats.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,QAAQ,KAAK,CAAC,MAAM,CAAC,KAAG,MAGlD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,KAAK,CAAC,MAAM,CAAC,KAAG,MAKpD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,MAAM,KAAG,MAKpE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,MAAM,KAAG,MAIrE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,QAAQ,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,KAAG,MAmBnE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,MAGxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,KAAK,CAAC,MAAM,CAAC,KAAG;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAU9E,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,qCAAqC;IACrC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACvB,8BAA8B;IAC9B,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC9B,QAAQ,KAAK,CAAC,MAAM,CAAC,EACrB,UAAU,uBAAuB,KAC/B,kBAgCF,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,+EAA+E;IAC/E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oEAAoE;IACpE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uDAAuD;IACvD,WAAW,CAAC,EAAE,uBAAuB,CAAC;CACtC;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC9B,QAAQ,KAAK,CAAC,MAAM,CAAC,EACrB,UAAU,uBAAuB,KAC/B,kBAqEF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/stats.ts"],"names":[],"mappings":"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"}
|
package/dist/stats.js
CHANGED
|
@@ -204,7 +204,7 @@ export const stats_outliers_mad = (values, options) => {
|
|
|
204
204
|
/**
|
|
205
205
|
* Common z-scores for confidence intervals.
|
|
206
206
|
*/
|
|
207
|
-
export const
|
|
207
|
+
export const STATS_CONFIDENCE_Z_SCORES = {
|
|
208
208
|
0.8: 1.282,
|
|
209
209
|
0.9: 1.645,
|
|
210
210
|
0.95: 1.96,
|
|
@@ -217,17 +217,17 @@ export const CONFIDENCE_Z_SCORES = {
|
|
|
217
217
|
*
|
|
218
218
|
* @example
|
|
219
219
|
* ```ts
|
|
220
|
-
*
|
|
221
|
-
*
|
|
220
|
+
* stats_confidence_level_to_z_score(0.95); // 1.96
|
|
221
|
+
* stats_confidence_level_to_z_score(0.99); // 2.576
|
|
222
222
|
* ```
|
|
223
223
|
*/
|
|
224
|
-
export const
|
|
224
|
+
export const stats_confidence_level_to_z_score = (level) => {
|
|
225
225
|
if (level <= 0 || level >= 1) {
|
|
226
226
|
throw new Error('Confidence level must be between 0 and 1 (exclusive)');
|
|
227
227
|
}
|
|
228
228
|
// Check lookup table first
|
|
229
|
-
if (level in
|
|
230
|
-
return
|
|
229
|
+
if (level in STATS_CONFIDENCE_Z_SCORES) {
|
|
230
|
+
return STATS_CONFIDENCE_Z_SCORES[level];
|
|
231
231
|
}
|
|
232
232
|
// For confidence level c, we want z such that P(-z < Z < z) = c
|
|
233
233
|
// This means Φ(z) = (1 + c) / 2, so z = Φ⁻¹((1 + c) / 2)
|
|
@@ -248,15 +248,155 @@ export const confidence_level_to_z_score = (level) => {
|
|
|
248
248
|
* @returns [lower_bound, upper_bound]
|
|
249
249
|
*/
|
|
250
250
|
export const stats_confidence_interval = (values, options) => {
|
|
251
|
-
// z_score takes precedence, then confidence_level, then default
|
|
252
|
-
const z_score = options?.z_score ??
|
|
253
|
-
(options?.confidence_level ? confidence_level_to_z_score(options.confidence_level) : null) ??
|
|
254
|
-
DEFAULT_CONFIDENCE_Z;
|
|
255
251
|
if (values.length === 0)
|
|
256
252
|
return [NaN, NaN];
|
|
257
253
|
const mean = stats_mean(values);
|
|
258
254
|
const std_dev = stats_std_dev(values, mean);
|
|
259
|
-
|
|
255
|
+
return stats_confidence_interval_from_summary(mean, std_dev, values.length, options);
|
|
256
|
+
};
|
|
257
|
+
/**
|
|
258
|
+
* Calculate confidence interval from summary statistics (mean, std_dev, sample_size).
|
|
259
|
+
* Useful when raw data is not available.
|
|
260
|
+
* @param mean - Mean of the data
|
|
261
|
+
* @param std_dev - Standard deviation of the data
|
|
262
|
+
* @param sample_size - Number of samples
|
|
263
|
+
* @param options - Configuration options
|
|
264
|
+
* @returns [lower_bound, upper_bound]
|
|
265
|
+
*/
|
|
266
|
+
export const stats_confidence_interval_from_summary = (mean, std_dev, sample_size, options) => {
|
|
267
|
+
// z_score takes precedence, then confidence_level, then default
|
|
268
|
+
const z_score = options?.z_score ??
|
|
269
|
+
(options?.confidence_level
|
|
270
|
+
? stats_confidence_level_to_z_score(options.confidence_level)
|
|
271
|
+
: null) ??
|
|
272
|
+
DEFAULT_CONFIDENCE_Z;
|
|
273
|
+
if (sample_size === 0)
|
|
274
|
+
return [NaN, NaN];
|
|
275
|
+
const se = std_dev / Math.sqrt(sample_size);
|
|
260
276
|
const margin = z_score * se;
|
|
261
277
|
return [mean - margin, mean + margin];
|
|
262
278
|
};
|
|
279
|
+
/**
|
|
280
|
+
* Calculate Welch's t-test statistic and degrees of freedom.
|
|
281
|
+
* Welch's t-test is more robust than Student's t-test when variances are unequal.
|
|
282
|
+
*
|
|
283
|
+
* @param mean1 - Mean of first sample
|
|
284
|
+
* @param std1 - Standard deviation of first sample
|
|
285
|
+
* @param n1 - Size of first sample
|
|
286
|
+
* @param mean2 - Mean of second sample
|
|
287
|
+
* @param std2 - Standard deviation of second sample
|
|
288
|
+
* @param n2 - Size of second sample
|
|
289
|
+
*/
|
|
290
|
+
export const stats_welch_t_test = (mean1, std1, n1, mean2, std2, n2) => {
|
|
291
|
+
const var1 = std1 ** 2;
|
|
292
|
+
const var2 = std2 ** 2;
|
|
293
|
+
const se1 = var1 / n1;
|
|
294
|
+
const se2 = var2 / n2;
|
|
295
|
+
const t_statistic = (mean1 - mean2) / Math.sqrt(se1 + se2);
|
|
296
|
+
// Welch-Satterthwaite degrees of freedom
|
|
297
|
+
const numerator = (se1 + se2) ** 2;
|
|
298
|
+
const denominator = se1 ** 2 / (n1 - 1) + se2 ** 2 / (n2 - 1);
|
|
299
|
+
const degrees_of_freedom = numerator / denominator;
|
|
300
|
+
return { t_statistic, degrees_of_freedom };
|
|
301
|
+
};
|
|
302
|
+
/**
|
|
303
|
+
* Standard normal CDF approximation (Abramowitz and Stegun formula 7.1.26).
|
|
304
|
+
*/
|
|
305
|
+
export const stats_normal_cdf = (x) => {
|
|
306
|
+
const t = 1 / (1 + 0.2316419 * Math.abs(x));
|
|
307
|
+
const d = 0.3989423 * Math.exp((-x * x) / 2);
|
|
308
|
+
const p = d * t * (0.3193815 + t * (-0.3565638 + t * (1.781478 + t * (-1.821256 + t * 1.330274))));
|
|
309
|
+
return x > 0 ? 1 - p : p;
|
|
310
|
+
};
|
|
311
|
+
/**
|
|
312
|
+
* Log gamma function approximation (Lanczos approximation).
|
|
313
|
+
*/
|
|
314
|
+
export const stats_ln_gamma = (z) => {
|
|
315
|
+
const g = 7;
|
|
316
|
+
const c = [
|
|
317
|
+
0.99999999999980993, 676.5203681218851, -1259.1392167224028, 771.32342877765313,
|
|
318
|
+
-176.61502916214059, 12.507343278686905, -0.13857109526572012, 9.9843695780195716e-6,
|
|
319
|
+
1.5056327351493116e-7,
|
|
320
|
+
];
|
|
321
|
+
if (z < 0.5) {
|
|
322
|
+
return Math.log(Math.PI / Math.sin(Math.PI * z)) - stats_ln_gamma(1 - z);
|
|
323
|
+
}
|
|
324
|
+
const z_adj = z - 1;
|
|
325
|
+
let x = c[0];
|
|
326
|
+
for (let i = 1; i < g + 2; i++) {
|
|
327
|
+
x += c[i] / (z_adj + i);
|
|
328
|
+
}
|
|
329
|
+
const t = z_adj + g + 0.5;
|
|
330
|
+
return 0.5 * Math.log(2 * Math.PI) + (z_adj + 0.5) * Math.log(t) - t + Math.log(x);
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* Approximate regularized incomplete beta function for p-value calculation.
|
|
334
|
+
* Uses continued fraction expansion for reasonable accuracy.
|
|
335
|
+
*/
|
|
336
|
+
export const stats_incomplete_beta = (x, a, b) => {
|
|
337
|
+
// Simple approximation using the relationship between beta and normal distributions
|
|
338
|
+
// For our use case (t-distribution p-values), this provides sufficient accuracy
|
|
339
|
+
if (x <= 0)
|
|
340
|
+
return 0;
|
|
341
|
+
if (x >= 1)
|
|
342
|
+
return 1;
|
|
343
|
+
// Use symmetry if needed
|
|
344
|
+
if (x > (a + 1) / (a + b + 2)) {
|
|
345
|
+
return 1 - stats_incomplete_beta(1 - x, b, a);
|
|
346
|
+
}
|
|
347
|
+
// Continued fraction approximation (first few terms)
|
|
348
|
+
const lnBeta = stats_ln_gamma(a) + stats_ln_gamma(b) - stats_ln_gamma(a + b);
|
|
349
|
+
const front = Math.exp(Math.log(x) * a + Math.log(1 - x) * b - lnBeta) / a;
|
|
350
|
+
// Simple continued fraction (limited iterations for speed)
|
|
351
|
+
let f = 1;
|
|
352
|
+
let c = 1;
|
|
353
|
+
let d = 0;
|
|
354
|
+
for (let m = 1; m <= 100; m++) {
|
|
355
|
+
const m2 = 2 * m;
|
|
356
|
+
// Even step
|
|
357
|
+
let aa = (m * (b - m) * x) / ((a + m2 - 1) * (a + m2));
|
|
358
|
+
d = 1 + aa * d;
|
|
359
|
+
if (Math.abs(d) < 1e-30)
|
|
360
|
+
d = 1e-30;
|
|
361
|
+
c = 1 + aa / c;
|
|
362
|
+
if (Math.abs(c) < 1e-30)
|
|
363
|
+
c = 1e-30;
|
|
364
|
+
d = 1 / d;
|
|
365
|
+
f *= d * c;
|
|
366
|
+
// Odd step
|
|
367
|
+
aa = (-(a + m) * (a + b + m) * x) / ((a + m2) * (a + m2 + 1));
|
|
368
|
+
d = 1 + aa * d;
|
|
369
|
+
if (Math.abs(d) < 1e-30)
|
|
370
|
+
d = 1e-30;
|
|
371
|
+
c = 1 + aa / c;
|
|
372
|
+
if (Math.abs(c) < 1e-30)
|
|
373
|
+
c = 1e-30;
|
|
374
|
+
d = 1 / d;
|
|
375
|
+
const delta = d * c;
|
|
376
|
+
f *= delta;
|
|
377
|
+
if (Math.abs(delta - 1) < 1e-8)
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
return front * f;
|
|
381
|
+
};
|
|
382
|
+
/**
|
|
383
|
+
* Approximate two-tailed p-value from t-distribution.
|
|
384
|
+
* For large df (>100), uses normal approximation.
|
|
385
|
+
* For smaller df, uses incomplete beta function.
|
|
386
|
+
*
|
|
387
|
+
* @param t - Absolute value of t-statistic
|
|
388
|
+
* @param df - Degrees of freedom
|
|
389
|
+
* @returns Two-tailed p-value
|
|
390
|
+
*/
|
|
391
|
+
export const stats_t_distribution_p_value = (t, df) => {
|
|
392
|
+
// Use normal approximation for large df
|
|
393
|
+
if (df > 100) {
|
|
394
|
+
return 2 * (1 - stats_normal_cdf(t));
|
|
395
|
+
}
|
|
396
|
+
// For smaller df, use a more accurate approximation
|
|
397
|
+
// Based on the incomplete beta function relationship
|
|
398
|
+
const x = df / (df + t * t);
|
|
399
|
+
const a = df / 2;
|
|
400
|
+
const b = 0.5;
|
|
401
|
+
return stats_incomplete_beta(x, a, b);
|
|
402
|
+
};
|
package/dist/string.d.ts
CHANGED
|
@@ -48,4 +48,17 @@ export declare const strip_ansi: (str: string) => string;
|
|
|
48
48
|
* @source https://2ality.com/2025/04/stringification-javascript.html
|
|
49
49
|
*/
|
|
50
50
|
export declare const stringify: (value: unknown) => string;
|
|
51
|
+
/**
|
|
52
|
+
* Calculate the display width of a string in terminal columns.
|
|
53
|
+
* - Strips ANSI escape codes (they have 0 width)
|
|
54
|
+
* - Emojis and other wide characters take 2 columns
|
|
55
|
+
* - Tab characters take 4 columns
|
|
56
|
+
* - Newlines and other control characters take 0 columns
|
|
57
|
+
* - Uses `Intl.Segmenter` to properly handle grapheme clusters (e.g., family emoji "👨👩👧👦")
|
|
58
|
+
*/
|
|
59
|
+
export declare const string_display_width: (str: string) => number;
|
|
60
|
+
/**
|
|
61
|
+
* Pad a string to a target display width (accounting for wide characters).
|
|
62
|
+
*/
|
|
63
|
+
export declare const pad_width: (str: string, target_width: number, align?: "left" | "right") => string;
|
|
51
64
|
//# sourceMappingURL=string.d.ts.map
|
package/dist/string.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/string.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,EAAE,WAAW,MAAM,EAAE,eAAc,KAAG,MAMzE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAG9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAG5D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAK9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAK/D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,EAAE,SAAS,MAAM,KAAG,MAG9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,EAAE,SAAS,MAAM,KAAG,MAG5D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,KAAG,MAK1B,CAAC;AAEd;;GAEG;AACH,eAAO,MAAM,MAAM,GAAI,OAAO,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,eAAY,KAAG,MAC9C,CAAC;AAE3B;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,KAAG,MACI,CAAC;AAEnD;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,KAAG,MAAsD,CAAC;AAEhG;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,OAAO,KAAG,MACwC,CAAC"}
|
|
1
|
+
{"version":3,"file":"string.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/string.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,EAAE,WAAW,MAAM,EAAE,eAAc,KAAG,MAMzE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAG9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAG5D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAK9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,EAAE,UAAU,MAAM,KAAG,MAK/D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,EAAE,SAAS,MAAM,KAAG,MAG9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,EAAE,SAAS,MAAM,KAAG,MAG5D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,KAAG,MAK1B,CAAC;AAEd;;GAEG;AACH,eAAO,MAAM,MAAM,GAAI,OAAO,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,eAAY,KAAG,MAC9C,CAAC;AAE3B;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,KAAG,MACI,CAAC;AAEnD;;GAEG;AACH,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,KAAG,MAAsD,CAAC;AAEhG;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,OAAO,KAAG,MACwC,CAAC;AAEpF;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,MAAM,KAAG,MAuClD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,GACrB,KAAK,MAAM,EACX,cAAc,MAAM,EACpB,QAAO,MAAM,GAAG,OAAgB,KAC9B,MAQF,CAAC"}
|
package/dist/string.js
CHANGED
|
@@ -90,3 +90,61 @@ export const strip_ansi = (str) => str.replaceAll(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
|
|
|
90
90
|
* @source https://2ality.com/2025/04/stringification-javascript.html
|
|
91
91
|
*/
|
|
92
92
|
export const stringify = (value) => typeof value === 'bigint' ? value + 'n' : (JSON.stringify(value) ?? String(value)); // eslint-disable-line @typescript-eslint/no-unnecessary-condition
|
|
93
|
+
/**
|
|
94
|
+
* Calculate the display width of a string in terminal columns.
|
|
95
|
+
* - Strips ANSI escape codes (they have 0 width)
|
|
96
|
+
* - Emojis and other wide characters take 2 columns
|
|
97
|
+
* - Tab characters take 4 columns
|
|
98
|
+
* - Newlines and other control characters take 0 columns
|
|
99
|
+
* - Uses `Intl.Segmenter` to properly handle grapheme clusters (e.g., family emoji "👨👩👧👦")
|
|
100
|
+
*/
|
|
101
|
+
export const string_display_width = (str) => {
|
|
102
|
+
// Strip ANSI codes first (they have 0 display width)
|
|
103
|
+
const clean = strip_ansi(str);
|
|
104
|
+
let width = 0;
|
|
105
|
+
const segmenter = new Intl.Segmenter();
|
|
106
|
+
for (const { segment } of segmenter.segment(clean)) {
|
|
107
|
+
const code = segment.codePointAt(0);
|
|
108
|
+
// Handle control characters
|
|
109
|
+
if (code === 0x09) {
|
|
110
|
+
// Tab = 4 columns
|
|
111
|
+
width += 4;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (code < 0x20 || (code >= 0x7f && code < 0xa0)) {
|
|
115
|
+
// Other control characters (including newline) = 0 width
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
// Emoji and other wide characters (rough heuristic)
|
|
119
|
+
// - Most emoji are in range 0x1F300-0x1FAFF
|
|
120
|
+
// - Some are in 0x2600-0x27BF (misc symbols)
|
|
121
|
+
// - CJK characters 0x4E00-0x9FFF also double-width
|
|
122
|
+
// - Grapheme clusters with multiple code points (like ZWJ sequences) are typically emoji
|
|
123
|
+
if (segment.length > 1 || // Multi-codepoint graphemes (ZWJ sequences, etc.)
|
|
124
|
+
(code >= 0x1f300 && code <= 0x1faff) ||
|
|
125
|
+
(code >= 0x2600 && code <= 0x27bf) ||
|
|
126
|
+
(code >= 0x1f600 && code <= 0x1f64f) ||
|
|
127
|
+
(code >= 0x1f680 && code <= 0x1f6ff) ||
|
|
128
|
+
(code >= 0x4e00 && code <= 0x9fff) // CJK
|
|
129
|
+
) {
|
|
130
|
+
width += 2;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
width += 1;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return width;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Pad a string to a target display width (accounting for wide characters).
|
|
140
|
+
*/
|
|
141
|
+
export const pad_width = (str, target_width, align = 'left') => {
|
|
142
|
+
const current_width = string_display_width(str);
|
|
143
|
+
const padding = Math.max(0, target_width - current_width);
|
|
144
|
+
if (align === 'left') {
|
|
145
|
+
return str + ' '.repeat(padding);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
return ' '.repeat(padding) + str;
|
|
149
|
+
}
|
|
150
|
+
};
|
package/dist/time.d.ts
CHANGED
|
@@ -56,6 +56,10 @@ export declare const time_ns_to_sec: (ns: number) => number;
|
|
|
56
56
|
* Time unit for formatting.
|
|
57
57
|
*/
|
|
58
58
|
export type TimeUnit = 'ns' | 'us' | 'ms' | 's';
|
|
59
|
+
/**
|
|
60
|
+
* Display labels for time units (uses proper Unicode μ for microseconds).
|
|
61
|
+
*/
|
|
62
|
+
export declare const TIME_UNIT_DISPLAY: Record<TimeUnit, string>;
|
|
59
63
|
/**
|
|
60
64
|
* Detect the best time unit for a set of nanosecond values.
|
|
61
65
|
* Chooses the unit where most values fall in the range 1-9999.
|
package/dist/time.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/time.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,WAAW,KAAK;IACrB,sCAAsC;IACtC,GAAG,EAAE,MAAM,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,KAKxB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,EAAE,KAI3B,CAAC;AAmCF;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,OAAQ,CAAC;AACpC,eAAO,MAAM,cAAc,UAAY,CAAC;AACxC,eAAO,MAAM,eAAe,aAAgB,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,IAAI,MAAM,KAAG,MAA6B,CAAC;AAEzE;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,IAAI,MAAM,KAAG,MAA6B,CAAC;AAEzE;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,IAAI,MAAM,KAAG,MAA8B,CAAC;AAE3E;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,GAAG,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,WAAW,KAAK,CAAC,MAAM,CAAC,KAAG,QAqBhE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GAAI,IAAI,MAAM,EAAE,MAAM,QAAQ,EAAE,WAAU,MAAU,KAAG,MAa9E,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,GAAI,IAAI,MAAM,EAAE,WAAU,MAAU,KAAG,MAavE,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,UAAU;IAC1B,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,UAAU,GAAU,CAAC,EACjC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,QAAO,KAAqB,KAC1B,OAAO,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAC,CAgBzC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,EAC1B,IAAI,MAAM,CAAC,EACX,QAAO,KAAqB,KAC1B;IAAC,MAAM,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAgBhC,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,YAAY,GACxB,IAAI,MAAM,OAAO,EACjB,YAAY,MAAM,EAClB,QAAO,KAAqB,KAC1B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAWvB,CAAC"}
|
|
1
|
+
{"version":3,"file":"time.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/time.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,WAAW,KAAK;IACrB,sCAAsC;IACtC,GAAG,EAAE,MAAM,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,KAKxB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,EAAE,KAI3B,CAAC;AAmCF;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,OAAQ,CAAC;AACpC,eAAO,MAAM,cAAc,UAAY,CAAC;AACxC,eAAO,MAAM,eAAe,aAAgB,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,IAAI,MAAM,KAAG,MAA6B,CAAC;AAEzE;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,IAAI,MAAM,KAAG,MAA6B,CAAC;AAEzE;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,IAAI,MAAM,KAAG,MAA8B,CAAC;AAE3E;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,GAAG,CAAC;AAEhD;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAA0C,CAAC;AAElG;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,WAAW,KAAK,CAAC,MAAM,CAAC,KAAG,QAqBhE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GAAI,IAAI,MAAM,EAAE,MAAM,QAAQ,EAAE,WAAU,MAAU,KAAG,MAa9E,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,GAAI,IAAI,MAAM,EAAE,WAAU,MAAU,KAAG,MAavE,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,UAAU;IAC1B,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,UAAU,GAAU,CAAC,EACjC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,QAAO,KAAqB,KAC1B,OAAO,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAC,CAgBzC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,EAC1B,IAAI,MAAM,CAAC,EACX,QAAO,KAAqB,KAC1B;IAAC,MAAM,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAgBhC,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,YAAY,GACxB,IAAI,MAAM,OAAO,EACjB,YAAY,MAAM,EAClB,QAAO,KAAqB,KAC1B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAWvB,CAAC"}
|
package/dist/time.js
CHANGED
|
@@ -87,6 +87,10 @@ export const time_ns_to_ms = (ns) => ns / TIME_NS_PER_MS;
|
|
|
87
87
|
* Convert nanoseconds to seconds.
|
|
88
88
|
*/
|
|
89
89
|
export const time_ns_to_sec = (ns) => ns / TIME_NS_PER_SEC;
|
|
90
|
+
/**
|
|
91
|
+
* Display labels for time units (uses proper Unicode μ for microseconds).
|
|
92
|
+
*/
|
|
93
|
+
export const TIME_UNIT_DISPLAY = { ns: 'ns', us: 'μs', ms: 'ms', s: 's' };
|
|
90
94
|
/**
|
|
91
95
|
* Detect the best time unit for a set of nanosecond values.
|
|
92
96
|
* Chooses the unit where most values fall in the range 1-9999.
|
package/package.json
CHANGED
|
@@ -8,12 +8,14 @@ import {join} from 'node:path';
|
|
|
8
8
|
import {z} from 'zod';
|
|
9
9
|
|
|
10
10
|
import {fs_exists} from './fs.js';
|
|
11
|
+
import {git_info_get} from './git.js';
|
|
11
12
|
import type {BenchmarkResult} from './benchmark_types.js';
|
|
12
13
|
import {
|
|
13
14
|
benchmark_stats_compare,
|
|
14
15
|
type BenchmarkComparison,
|
|
15
16
|
type BenchmarkStatsComparable,
|
|
16
17
|
} from './benchmark_stats.js';
|
|
18
|
+
import {stats_confidence_interval_from_summary} from './stats.js';
|
|
17
19
|
|
|
18
20
|
// Version for forward compatibility - increment when schema changes
|
|
19
21
|
const BASELINE_VERSION = 1;
|
|
@@ -128,21 +130,6 @@ export interface BenchmarkBaselineTaskComparison {
|
|
|
128
130
|
const DEFAULT_BASELINE_PATH = '.gro/benchmarks';
|
|
129
131
|
const BASELINE_FILENAME = 'baseline.json';
|
|
130
132
|
|
|
131
|
-
/** Z-score for 95% confidence interval */
|
|
132
|
-
const Z_95 = 1.96;
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Calculate 95% confidence interval from mean, std_dev, and sample_size.
|
|
136
|
-
*/
|
|
137
|
-
const calculate_confidence_interval = (
|
|
138
|
-
mean: number,
|
|
139
|
-
std_dev: number,
|
|
140
|
-
sample_size: number,
|
|
141
|
-
): [number, number] => {
|
|
142
|
-
const margin = Z_95 * (std_dev / Math.sqrt(sample_size));
|
|
143
|
-
return [mean - margin, mean + margin];
|
|
144
|
-
};
|
|
145
|
-
|
|
146
133
|
/**
|
|
147
134
|
* Convert benchmark results to baseline entries.
|
|
148
135
|
*/
|
|
@@ -163,28 +150,6 @@ const results_to_entries = (results: Array<BenchmarkResult>): Array<BenchmarkBas
|
|
|
163
150
|
}));
|
|
164
151
|
};
|
|
165
152
|
|
|
166
|
-
/**
|
|
167
|
-
* Try to get git info from the environment or git commands.
|
|
168
|
-
*/
|
|
169
|
-
const get_git_info = async (): Promise<{commit: string | null; branch: string | null}> => {
|
|
170
|
-
try {
|
|
171
|
-
const {promisify} = await import('node:util');
|
|
172
|
-
const exec = promisify((await import('node:child_process')).exec);
|
|
173
|
-
|
|
174
|
-
const [commit_result, branch_result] = await Promise.all([
|
|
175
|
-
exec('git rev-parse HEAD').catch(() => ({stdout: ''})),
|
|
176
|
-
exec('git rev-parse --abbrev-ref HEAD').catch(() => ({stdout: ''})),
|
|
177
|
-
]);
|
|
178
|
-
|
|
179
|
-
return {
|
|
180
|
-
commit: commit_result.stdout.trim() || null,
|
|
181
|
-
branch: branch_result.stdout.trim() || null,
|
|
182
|
-
};
|
|
183
|
-
} catch {
|
|
184
|
-
return {commit: null, branch: null};
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
|
|
188
153
|
/**
|
|
189
154
|
* Save benchmark results as the current baseline.
|
|
190
155
|
*
|
|
@@ -209,7 +174,7 @@ export const benchmark_baseline_save = async (
|
|
|
209
174
|
let git_commit = options.git_commit;
|
|
210
175
|
let git_branch = options.git_branch;
|
|
211
176
|
if (git_commit === undefined || git_branch === undefined) {
|
|
212
|
-
const git_info = await
|
|
177
|
+
const git_info = await git_info_get();
|
|
213
178
|
git_commit ??= git_info.commit;
|
|
214
179
|
git_branch ??= git_info.branch;
|
|
215
180
|
}
|
|
@@ -360,7 +325,7 @@ export const benchmark_baseline_compare = async (
|
|
|
360
325
|
mean_ns: baseline_entry.mean_ns,
|
|
361
326
|
std_dev_ns: baseline_entry.std_dev_ns,
|
|
362
327
|
sample_size: baseline_entry.sample_size,
|
|
363
|
-
confidence_interval_ns:
|
|
328
|
+
confidence_interval_ns: stats_confidence_interval_from_summary(
|
|
364
329
|
baseline_entry.mean_ns,
|
|
365
330
|
baseline_entry.std_dev_ns,
|
|
366
331
|
baseline_entry.sample_size,
|
|
@@ -370,7 +335,7 @@ export const benchmark_baseline_compare = async (
|
|
|
370
335
|
mean_ns: current.mean_ns,
|
|
371
336
|
std_dev_ns: current.std_dev_ns,
|
|
372
337
|
sample_size: current.sample_size,
|
|
373
|
-
confidence_interval_ns:
|
|
338
|
+
confidence_interval_ns: stats_confidence_interval_from_summary(
|
|
374
339
|
current.mean_ns,
|
|
375
340
|
current.std_dev_ns,
|
|
376
341
|
current.sample_size,
|