@danielsimonjr/mathts-parallel 0.2.2 → 0.3.1
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/index.d.ts +34 -6
- package/dist/index.js +181 -18
- package/package.json +57 -57
package/dist/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export { Transfer } from '@danielsimonjr/mathts-workerpool';
|
|
|
24
24
|
* - Special / distribution functions (`erfc`, `besselJ`, `normalCDF`)
|
|
25
25
|
* - Additional ops exposed via the typed functions layer
|
|
26
26
|
*/
|
|
27
|
-
type OpName = 'add' | 'subtract' | 'multiply' | 'divide' | 'pow' | 'scale' | 'abs' | 'negate' | 'sqrt' | 'square' | 'exp' | 'log' | 'sin' | 'cos' | 'tan' | 'sign' | 'tensordot' | 'sum' | 'mean' | 'variance' | 'norm' | 'histogram' | 'dot' | 'distance' | 'parallelStatProd' | 'matmul' | 'outer' | 'matvec' | 'transpose' | 'matrixPower' | 'characteristicPolynomial' | 'parallelFFT' | 'parallelConv' | 'spectrogram' | 'fft2d' | 'distanceMatrix' | 'erfc' | 'besselJ' | 'normalCDF' | 'chiSquareTest' | 'kolmogorovSmirnovTest' | 'mannWhitneyTest' | 'shapiroWilkTest' | 'integrateChunk' | 'sampleChunk';
|
|
27
|
+
type OpName = 'add' | 'subtract' | 'multiply' | 'divide' | 'pow' | 'scale' | 'abs' | 'negate' | 'sqrt' | 'square' | 'exp' | 'log' | 'sin' | 'cos' | 'tan' | 'sign' | 'tensordot' | 'sum' | 'mean' | 'min' | 'max' | 'minMax' | 'variance' | 'std' | 'norm' | 'histogram' | 'dot' | 'prod' | 'distance' | 'parallelStatProd' | 'matmul' | 'outer' | 'matvec' | 'transpose' | 'matrixPower' | 'characteristicPolynomial' | 'parallelFFT' | 'parallelConv' | 'spectrogram' | 'fft2d' | 'distanceMatrix' | 'erfc' | 'besselJ' | 'normalCDF' | 'chiSquareTest' | 'kolmogorovSmirnovTest' | 'mannWhitneyTest' | 'shapiroWilkTest' | 'integrateChunk' | 'sampleChunk';
|
|
28
28
|
/**
|
|
29
29
|
* Per-op threshold override. The value is the minimum element count required
|
|
30
30
|
* before parallelizing the named operation. Special string aliases:
|
|
@@ -72,6 +72,22 @@ interface ComputePoolConfig {
|
|
|
72
72
|
/** Default task timeout in milliseconds */
|
|
73
73
|
taskTimeout: number;
|
|
74
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Default per-op thresholds derived from benchmark data (tools/benchmark/parallel/run.ts,
|
|
77
|
+
* 2026-05-23). Values measured on a noisy CI container — re-run on target hardware to retune.
|
|
78
|
+
*
|
|
79
|
+
* 'never' → Number.MAX_SAFE_INTEGER (benchmark showed no reliable speedup)
|
|
80
|
+
* 'always' → 0 (always parallelize when pool is ready)
|
|
81
|
+
* number → minimum element count before dispatching to workers
|
|
82
|
+
*/
|
|
83
|
+
/**
|
|
84
|
+
* Canonical, benchmark-tuned per-op parallelization thresholds. This is the
|
|
85
|
+
* single source of truth consulted by `ComputePool.shouldParallelize` — the
|
|
86
|
+
* authority the typed functions actually dispatch through. The coarser
|
|
87
|
+
* category-level {@link ThresholdDispatcher} derives its overlapping values
|
|
88
|
+
* (e.g. matmul) from here so the two cannot silently diverge.
|
|
89
|
+
*/
|
|
90
|
+
declare const DEFAULT_THRESHOLD_BY_OP: Partial<Record<OpName, OpThreshold>>;
|
|
75
91
|
/**
|
|
76
92
|
* Default ComputePool configuration
|
|
77
93
|
*/
|
|
@@ -132,6 +148,15 @@ declare class ComputePool {
|
|
|
132
148
|
* backward-compatibility with existing callers that don't know the op name).
|
|
133
149
|
*/
|
|
134
150
|
shouldParallelize(elementCount: number, op?: OpName): boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Wrap a sequentially-computed reduction result in the `ParallelResult`
|
|
153
|
+
* envelope. Used by the reduction methods below so that ops whose threshold
|
|
154
|
+
* says "don't parallelize at this size" (notably the memory-bound reductions
|
|
155
|
+
* pinned to `'never'`) compute inline instead of paying a worker round-trip —
|
|
156
|
+
* previously every reduction dispatched to the pool unconditionally, ignoring
|
|
157
|
+
* its threshold.
|
|
158
|
+
*/
|
|
159
|
+
private seqResult;
|
|
135
160
|
/**
|
|
136
161
|
* Execute a method in the worker pool
|
|
137
162
|
*/
|
|
@@ -1179,11 +1204,14 @@ interface ThresholdConfig {
|
|
|
1179
1204
|
general: number;
|
|
1180
1205
|
}
|
|
1181
1206
|
/**
|
|
1182
|
-
* Default thresholds
|
|
1207
|
+
* Default category-level thresholds.
|
|
1183
1208
|
*
|
|
1184
|
-
*
|
|
1185
|
-
*
|
|
1186
|
-
*
|
|
1209
|
+
* NOTE: `ComputePool.shouldParallelize` (op-level, {@link DEFAULT_THRESHOLD_BY_OP})
|
|
1210
|
+
* is the authority the typed functions dispatch through. This category map is a
|
|
1211
|
+
* coarser helper; where a category overlaps a tuned op (matmul) its value is
|
|
1212
|
+
* derived from the canonical const so the two cannot diverge. The remaining
|
|
1213
|
+
* categories (no single ComputePool op equivalent — many are 'never') keep
|
|
1214
|
+
* heuristic defaults for compute-vs-memory-bound work.
|
|
1187
1215
|
*/
|
|
1188
1216
|
declare const DEFAULT_THRESHOLDS: ThresholdConfig;
|
|
1189
1217
|
/**
|
|
@@ -1283,4 +1311,4 @@ interface PoolStats {
|
|
|
1283
1311
|
activeTasks: number;
|
|
1284
1312
|
}
|
|
1285
1313
|
|
|
1286
|
-
export { type BitwiseBinaryOp, type ChunkInfo, type ChunkOptions, type ChunkResult, ComputePool, type ComputePoolConfig, DEFAULT_POOL_CONFIG, DEFAULT_THRESHOLDS, type DispatchResult, type ElementwiseOptions, type ExecOptions, type ExecutionMode, type MapOptions, type MatmulOptions, type OpName, type OpThreshold, type OperationCategory, type ParallelResult, type PoolOptions, type PoolStats, type ReduceOptions, type ThresholdConfig, ThresholdDispatcher, bitAnd, bitNot, bitOr, bitXor, calculateChunks, calculateOptimalChunks, chunkArray, chunkFloat64Array, computePool, dispatch, leftShift, mergeArrayChunks, mergeFloat64Chunks, parallelAbs, parallelAdd, parallelCos, parallelCount, parallelDistance, parallelDivide, parallelDot, parallelElementwise, parallelEvery, parallelExp, parallelFilter, parallelFind, parallelForEach, parallelHistogram, parallelLog, parallelMap, parallelMatmul, parallelMatvec, parallelMax, parallelMean, parallelMin, parallelMinMax, parallelMultiply, parallelNegate, parallelNorm, parallelOuter, parallelReduce, parallelScale, parallelSin, parallelSome, parallelSort, parallelSqrt, parallelSquare, parallelStd, parallelSubtract, parallelSum, parallelTan, parallelTranspose, parallelUnary, parallelVariance, partition2D, partitionRange, resolveOpThreshold, rightArithShift, rightLogShift, shouldParallelize$1 as shouldChunkParallelize, shouldParallelize, thresholdDispatcher };
|
|
1314
|
+
export { type BitwiseBinaryOp, type ChunkInfo, type ChunkOptions, type ChunkResult, ComputePool, type ComputePoolConfig, DEFAULT_POOL_CONFIG, DEFAULT_THRESHOLDS, DEFAULT_THRESHOLD_BY_OP, type DispatchResult, type ElementwiseOptions, type ExecOptions, type ExecutionMode, type MapOptions, type MatmulOptions, type OpName, type OpThreshold, type OperationCategory, type ParallelResult, type PoolOptions, type PoolStats, type ReduceOptions, type ThresholdConfig, ThresholdDispatcher, bitAnd, bitNot, bitOr, bitXor, calculateChunks, calculateOptimalChunks, chunkArray, chunkFloat64Array, computePool, dispatch, leftShift, mergeArrayChunks, mergeFloat64Chunks, parallelAbs, parallelAdd, parallelCos, parallelCount, parallelDistance, parallelDivide, parallelDot, parallelElementwise, parallelEvery, parallelExp, parallelFilter, parallelFind, parallelForEach, parallelHistogram, parallelLog, parallelMap, parallelMatmul, parallelMatvec, parallelMax, parallelMean, parallelMin, parallelMinMax, parallelMultiply, parallelNegate, parallelNorm, parallelOuter, parallelReduce, parallelScale, parallelSin, parallelSome, parallelSort, parallelSqrt, parallelSquare, parallelStd, parallelSubtract, parallelSum, parallelTan, parallelTranspose, parallelUnary, parallelVariance, partition2D, partitionRange, resolveOpThreshold, rightArithShift, rightLogShift, shouldParallelize$1 as shouldChunkParallelize, shouldParallelize, thresholdDispatcher };
|
package/dist/index.js
CHANGED
|
@@ -346,6 +346,13 @@ var DEFAULT_THRESHOLD_BY_OP = {
|
|
|
346
346
|
cos: "never",
|
|
347
347
|
tan: "never",
|
|
348
348
|
sign: "never",
|
|
349
|
+
// Added 2026-07-02 (WS-2): these element-wise ops were absent from the map and
|
|
350
|
+
// silently defaulted to the 50 000 global threshold — an inconsistency with their
|
|
351
|
+
// siblings above (surfaced by parallel-pairing.md). Benchmarked (tools/benchmark/
|
|
352
|
+
// parallel/run.ts sqrt square) — memory-bound, speedup 0.12–0.65×, no persistent
|
|
353
|
+
// break-even → 'never', matching the class.
|
|
354
|
+
sqrt: "never",
|
|
355
|
+
square: "never",
|
|
349
356
|
// tensor contraction: parallelize when contracted-axis volume >= 8K
|
|
350
357
|
tensordot: 8192,
|
|
351
358
|
// reductions: overhead dominates
|
|
@@ -354,6 +361,46 @@ var DEFAULT_THRESHOLD_BY_OP = {
|
|
|
354
361
|
variance: "never",
|
|
355
362
|
parallelStatProd: "never",
|
|
356
363
|
normalCDF: "never",
|
|
364
|
+
// Added 2026-07-02 (WS-2): reductions that were absent from the map and defaulted
|
|
365
|
+
// to the global threshold; benchmarked memory-bound (0.09–1.19×, occasional noise
|
|
366
|
+
// spikes but no persistent win) → 'never'.
|
|
367
|
+
norm: "never",
|
|
368
|
+
dot: "never",
|
|
369
|
+
// Added 2026-07-02 (WS-2): `min`/`max` are now `OpName`s (added to the union) so
|
|
370
|
+
// they're tunable. Same memory-bound reduction profile as sum/mean/norm above →
|
|
371
|
+
// 'never'. Their `functions/` call sites previously dispatched to the worker pool
|
|
372
|
+
// unconditionally (no `shouldParallelize` gate), paying dispatch overhead on every
|
|
373
|
+
// call; they now respect this threshold (sequential) with a `shouldParallelize` gate.
|
|
374
|
+
min: "never",
|
|
375
|
+
max: "never",
|
|
376
|
+
// Added 2026-07-03 (WS-2, DGT sweep): the remaining memory-bound reductions that
|
|
377
|
+
// defaulted to the 50 000 global threshold and dispatched unconditionally at every
|
|
378
|
+
// `functions/` call site. Same class as sum/mean/min/max/norm/dot → 'never'. Now
|
|
379
|
+
// gated INSIDE the ComputePool reduction methods (inline sequential fallback), so
|
|
380
|
+
// ALL call sites honor the threshold without per-site edits. `std` derives from
|
|
381
|
+
// `variance`; `min`/`max` derive from `minMax`.
|
|
382
|
+
minMax: "never",
|
|
383
|
+
std: "never",
|
|
384
|
+
prod: "never",
|
|
385
|
+
distance: "never",
|
|
386
|
+
// Added 2026-07-04 (WS-2 completion): the five OpNames that were absent from
|
|
387
|
+
// this map and silently rode the untested 50 000 global default. Benchmarked
|
|
388
|
+
// (tools/benchmarks/ws2-missing-ops.mjs, medians of 9 interleaved reps):
|
|
389
|
+
// histogram 0.23-0.56x, transpose 0.01-0.28x, matvec 0.00-0.05x, outer
|
|
390
|
+
// 0.01-0.50x at every size up to 4.2M elements - memory-bound / copy-dominated,
|
|
391
|
+
// no break-even -> 'never'. Their ComputePool methods previously dispatched to
|
|
392
|
+
// the worker pool UNCONDITIONALLY (no shouldParallelize gate); they now gate
|
|
393
|
+
// with an inline sequential fallback like the reductions above.
|
|
394
|
+
histogram: "never",
|
|
395
|
+
transpose: "never",
|
|
396
|
+
matvec: "never",
|
|
397
|
+
outer: "never",
|
|
398
|
+
// integrateFanOut loses ~50-100x for cheap integrands (0.01-0.02x at 128-32768
|
|
399
|
+
// evals). The fan-out is CALLER-OPT-IN (integration.ts dispatches only when the
|
|
400
|
+
// caller passes workerCount > 1), so this entry documents the default posture;
|
|
401
|
+
// no shouldParallelize call consults it. Expensive (ms-scale) integrands are the
|
|
402
|
+
// one case where the fan-out pays off.
|
|
403
|
+
integrateChunk: "never",
|
|
357
404
|
// signal: overhead dominates or break-even never reached
|
|
358
405
|
parallelFFT: "never",
|
|
359
406
|
parallelConv: "never",
|
|
@@ -525,6 +572,17 @@ var ComputePool = class {
|
|
|
525
572
|
}
|
|
526
573
|
return this.workerPool.shouldParallelize(elementCount);
|
|
527
574
|
}
|
|
575
|
+
/**
|
|
576
|
+
* Wrap a sequentially-computed reduction result in the `ParallelResult`
|
|
577
|
+
* envelope. Used by the reduction methods below so that ops whose threshold
|
|
578
|
+
* says "don't parallelize at this size" (notably the memory-bound reductions
|
|
579
|
+
* pinned to `'never'`) compute inline instead of paying a worker round-trip —
|
|
580
|
+
* previously every reduction dispatched to the pool unconditionally, ignoring
|
|
581
|
+
* its threshold.
|
|
582
|
+
*/
|
|
583
|
+
seqResult(result) {
|
|
584
|
+
return { result, duration: 0, chunks: 1, parallelized: false };
|
|
585
|
+
}
|
|
528
586
|
/**
|
|
529
587
|
* Execute a method in the worker pool
|
|
530
588
|
*/
|
|
@@ -541,22 +599,35 @@ var ComputePool = class {
|
|
|
541
599
|
* Parallel sum of array elements
|
|
542
600
|
*/
|
|
543
601
|
async sum(data) {
|
|
544
|
-
|
|
545
|
-
|
|
602
|
+
if (!this.shouldParallelize(data.length, "sum")) {
|
|
603
|
+
let s = 0;
|
|
604
|
+
for (let i = 0; i < data.length; i++) s += data[i];
|
|
605
|
+
return this.seqResult(s);
|
|
606
|
+
}
|
|
607
|
+
return toParallelResult(await this.workerPool.sum(data));
|
|
546
608
|
}
|
|
547
609
|
/**
|
|
548
610
|
* Parallel product of array elements
|
|
549
611
|
*/
|
|
550
612
|
async prod(data) {
|
|
551
|
-
|
|
552
|
-
|
|
613
|
+
if (!this.shouldParallelize(data.length, "prod")) {
|
|
614
|
+
let p = 1;
|
|
615
|
+
for (let i = 0; i < data.length; i++) p *= data[i];
|
|
616
|
+
return this.seqResult(p);
|
|
617
|
+
}
|
|
618
|
+
return toParallelResult(await this.workerPool.prod(data));
|
|
553
619
|
}
|
|
554
620
|
/**
|
|
555
621
|
* Parallel dot product
|
|
556
622
|
*/
|
|
557
623
|
async dot(a, b) {
|
|
558
|
-
|
|
559
|
-
|
|
624
|
+
if (!this.shouldParallelize(a.length, "dot")) {
|
|
625
|
+
if (a.length !== b.length) throw new Error("dot: vectors must have the same length");
|
|
626
|
+
let s = 0;
|
|
627
|
+
for (let i = 0; i < a.length; i++) s += a[i] * b[i];
|
|
628
|
+
return this.seqResult(s);
|
|
629
|
+
}
|
|
630
|
+
return toParallelResult(await this.workerPool.dot(a, b));
|
|
560
631
|
}
|
|
561
632
|
/**
|
|
562
633
|
* Parallel element-wise operation
|
|
@@ -589,6 +660,16 @@ var ComputePool = class {
|
|
|
589
660
|
* Parallel matrix transpose
|
|
590
661
|
*/
|
|
591
662
|
async transpose(data, rows, cols) {
|
|
663
|
+
if (!this.shouldParallelize(data.length, "transpose")) {
|
|
664
|
+
if (data.length !== rows * cols) {
|
|
665
|
+
throw new Error(`transpose: data length ${data.length} !== rows*cols (${rows * cols})`);
|
|
666
|
+
}
|
|
667
|
+
const out = new Float64Array(rows * cols);
|
|
668
|
+
for (let i = 0; i < rows; i++) {
|
|
669
|
+
for (let j = 0; j < cols; j++) out[j * rows + i] = data[i * cols + j];
|
|
670
|
+
}
|
|
671
|
+
return this.seqResult(out);
|
|
672
|
+
}
|
|
592
673
|
const result = await this.workerPool.transpose(data, rows, cols);
|
|
593
674
|
return toParallelResult(result);
|
|
594
675
|
}
|
|
@@ -620,34 +701,89 @@ var ComputePool = class {
|
|
|
620
701
|
* Find min and max values in parallel
|
|
621
702
|
*/
|
|
622
703
|
async minMax(data) {
|
|
623
|
-
|
|
624
|
-
|
|
704
|
+
if (!this.shouldParallelize(data.length, "minMax") && !this.shouldParallelize(data.length, "min")) {
|
|
705
|
+
let min = Infinity;
|
|
706
|
+
let max = -Infinity;
|
|
707
|
+
let minIdx = -1;
|
|
708
|
+
let maxIdx = -1;
|
|
709
|
+
for (let i = 0; i < data.length; i++) {
|
|
710
|
+
if (data[i] < min) {
|
|
711
|
+
min = data[i];
|
|
712
|
+
minIdx = i;
|
|
713
|
+
}
|
|
714
|
+
if (data[i] > max) {
|
|
715
|
+
max = data[i];
|
|
716
|
+
maxIdx = i;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return this.seqResult({ min, max, minIdx, maxIdx });
|
|
720
|
+
}
|
|
721
|
+
return toParallelResult(await this.workerPool.minMax(data));
|
|
625
722
|
}
|
|
626
723
|
/**
|
|
627
724
|
* Compute variance, mean, and standard deviation in parallel
|
|
628
725
|
*/
|
|
629
726
|
async variance(data) {
|
|
630
|
-
|
|
631
|
-
|
|
727
|
+
if (!this.shouldParallelize(data.length, "variance")) {
|
|
728
|
+
const n = data.length;
|
|
729
|
+
let mean = 0;
|
|
730
|
+
for (let i = 0; i < n; i++) mean += data[i];
|
|
731
|
+
mean = n > 0 ? mean / n : 0;
|
|
732
|
+
let acc = 0;
|
|
733
|
+
for (let i = 0; i < n; i++) acc += (data[i] - mean) ** 2;
|
|
734
|
+
const variance = n > 0 ? acc / n : 0;
|
|
735
|
+
return this.seqResult({ mean, variance, std: Math.sqrt(variance) });
|
|
736
|
+
}
|
|
737
|
+
return toParallelResult(await this.workerPool.variance(data));
|
|
632
738
|
}
|
|
633
739
|
/**
|
|
634
740
|
* Compute norm (Euclidean length) in parallel
|
|
635
741
|
*/
|
|
636
742
|
async norm(data) {
|
|
637
|
-
|
|
638
|
-
|
|
743
|
+
if (!this.shouldParallelize(data.length, "norm")) {
|
|
744
|
+
let s = 0;
|
|
745
|
+
for (let i = 0; i < data.length; i++) s += data[i] * data[i];
|
|
746
|
+
return this.seqResult(Math.sqrt(s));
|
|
747
|
+
}
|
|
748
|
+
return toParallelResult(await this.workerPool.norm(data));
|
|
639
749
|
}
|
|
640
750
|
/**
|
|
641
751
|
* Compute Euclidean distance in parallel
|
|
642
752
|
*/
|
|
643
753
|
async distance(a, b) {
|
|
644
|
-
|
|
645
|
-
|
|
754
|
+
if (!this.shouldParallelize(a.length, "distance")) {
|
|
755
|
+
if (a.length !== b.length) throw new Error("distance: vectors must have the same length");
|
|
756
|
+
let s = 0;
|
|
757
|
+
for (let i = 0; i < a.length; i++) s += (a[i] - b[i]) ** 2;
|
|
758
|
+
return this.seqResult(Math.sqrt(s));
|
|
759
|
+
}
|
|
760
|
+
return toParallelResult(await this.workerPool.distance(a, b));
|
|
646
761
|
}
|
|
647
762
|
/**
|
|
648
763
|
* Compute histogram in parallel
|
|
649
764
|
*/
|
|
650
765
|
async histogram(data, bins, min, max) {
|
|
766
|
+
if (!this.shouldParallelize(data.length, "histogram")) {
|
|
767
|
+
let lo = min;
|
|
768
|
+
let hi = max;
|
|
769
|
+
if (lo === void 0 || hi === void 0) {
|
|
770
|
+
lo = Infinity;
|
|
771
|
+
hi = -Infinity;
|
|
772
|
+
for (let i = 0; i < data.length; i++) {
|
|
773
|
+
if (data[i] < lo) lo = data[i];
|
|
774
|
+
if (data[i] > hi) hi = data[i];
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
const counts = new Array(bins).fill(0);
|
|
778
|
+
const width = (hi - lo) / bins || 1;
|
|
779
|
+
for (let i = 0; i < data.length; i++) {
|
|
780
|
+
let b = Math.floor((data[i] - lo) / width);
|
|
781
|
+
if (b >= bins) b = bins - 1;
|
|
782
|
+
if (b < 0) b = 0;
|
|
783
|
+
counts[b]++;
|
|
784
|
+
}
|
|
785
|
+
return this.seqResult(counts);
|
|
786
|
+
}
|
|
651
787
|
const result = await this.workerPool.histogram(data, bins, min, max);
|
|
652
788
|
return toParallelResult(result);
|
|
653
789
|
}
|
|
@@ -857,6 +993,21 @@ var ComputePool = class {
|
|
|
857
993
|
* Parallel matrix-vector multiplication
|
|
858
994
|
*/
|
|
859
995
|
async matvec(matrix, rows, cols, vector) {
|
|
996
|
+
if (!this.shouldParallelize(matrix.length, "matvec")) {
|
|
997
|
+
if (matrix.length !== rows * cols) {
|
|
998
|
+
throw new Error(`matvec: matrix length ${matrix.length} !== rows*cols (${rows * cols})`);
|
|
999
|
+
}
|
|
1000
|
+
if (vector.length !== cols) {
|
|
1001
|
+
throw new Error(`matvec: vector length ${vector.length} !== cols (${cols})`);
|
|
1002
|
+
}
|
|
1003
|
+
const out = new Float64Array(rows);
|
|
1004
|
+
for (let i = 0; i < rows; i++) {
|
|
1005
|
+
let s = 0;
|
|
1006
|
+
for (let j = 0; j < cols; j++) s += matrix[i * cols + j] * vector[j];
|
|
1007
|
+
out[i] = s;
|
|
1008
|
+
}
|
|
1009
|
+
return this.seqResult(out);
|
|
1010
|
+
}
|
|
860
1011
|
const result = await this.workerPool.matvec(matrix, rows, cols, vector);
|
|
861
1012
|
return toParallelResult(result);
|
|
862
1013
|
}
|
|
@@ -864,6 +1015,13 @@ var ComputePool = class {
|
|
|
864
1015
|
* Parallel outer product
|
|
865
1016
|
*/
|
|
866
1017
|
async outer(a, b) {
|
|
1018
|
+
if (!this.shouldParallelize(a.length * b.length, "outer")) {
|
|
1019
|
+
const out = new Float64Array(a.length * b.length);
|
|
1020
|
+
for (let i = 0; i < a.length; i++) {
|
|
1021
|
+
for (let j = 0; j < b.length; j++) out[i * b.length + j] = a[i] * b[j];
|
|
1022
|
+
}
|
|
1023
|
+
return this.seqResult(out);
|
|
1024
|
+
}
|
|
867
1025
|
const result = await this.workerPool.outer(a, b);
|
|
868
1026
|
return toParallelResult(result);
|
|
869
1027
|
}
|
|
@@ -1483,11 +1641,15 @@ async function parallelCount(data, predicate, options = {}) {
|
|
|
1483
1641
|
}
|
|
1484
1642
|
|
|
1485
1643
|
// src/strategies/threshold.ts
|
|
1644
|
+
function opThreshold(op, fallback) {
|
|
1645
|
+
const raw = DEFAULT_THRESHOLD_BY_OP[op];
|
|
1646
|
+
return typeof raw === "number" ? raw : fallback;
|
|
1647
|
+
}
|
|
1486
1648
|
var DEFAULT_THRESHOLDS = {
|
|
1487
|
-
matmul:
|
|
1488
|
-
//
|
|
1649
|
+
matmul: opThreshold("matmul", 4096),
|
|
1650
|
+
// canonical: DEFAULT_THRESHOLD_BY_OP.matmul
|
|
1489
1651
|
elementwise: 5e4,
|
|
1490
|
-
// ~50K elements
|
|
1652
|
+
// ~50K elements (memory-bound; ComputePool ops mostly 'never')
|
|
1491
1653
|
reduce: 1e5,
|
|
1492
1654
|
// ~100K elements
|
|
1493
1655
|
map: 1e4,
|
|
@@ -1495,7 +1657,7 @@ var DEFAULT_THRESHOLDS = {
|
|
|
1495
1657
|
sort: 5e3,
|
|
1496
1658
|
// ~5K elements
|
|
1497
1659
|
decomposition: 2500,
|
|
1498
|
-
// ~50x50 matrix
|
|
1660
|
+
// ~50x50 matrix (no single canonical op; heuristic)
|
|
1499
1661
|
general: 5e4
|
|
1500
1662
|
// Default ~50K
|
|
1501
1663
|
};
|
|
@@ -1608,6 +1770,7 @@ export {
|
|
|
1608
1770
|
ComputePool,
|
|
1609
1771
|
DEFAULT_POOL_CONFIG,
|
|
1610
1772
|
DEFAULT_THRESHOLDS,
|
|
1773
|
+
DEFAULT_THRESHOLD_BY_OP,
|
|
1611
1774
|
ThresholdDispatcher,
|
|
1612
1775
|
Transfer,
|
|
1613
1776
|
bitAnd,
|
package/package.json
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@danielsimonjr/mathts-parallel",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "WebWorker parallelization for MathTS computations",
|
|
5
|
-
"author": "Daniel Simon Jr.",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"main": "./dist/index.js",
|
|
9
|
-
"module": "./dist/index.js",
|
|
10
|
-
"types": "./dist/index.d.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"import": "./dist/index.js",
|
|
14
|
-
"types": "./dist/index.d.ts"
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"dist",
|
|
19
|
-
"README.md"
|
|
20
|
-
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "tsup src/index.ts src/matrix.worker.ts --format esm --dts --clean",
|
|
23
|
-
"dev": "tsup src/index.ts src/matrix.worker.ts --format esm --dts --watch",
|
|
24
|
-
"test": "vitest run",
|
|
25
|
-
"test:watch": "vitest",
|
|
26
|
-
"test:coverage": "vitest run --coverage",
|
|
27
|
-
"typecheck": "tsc --noEmit",
|
|
28
|
-
"lint": "eslint src --ext .ts",
|
|
29
|
-
"lint:fix": "eslint src --ext .ts --fix",
|
|
30
|
-
"clean": "rm -rf dist",
|
|
31
|
-
"build:prod": "tsup src/index.ts src/matrix.worker.ts --format esm --dts --clean --minify --treeshake"
|
|
32
|
-
},
|
|
33
|
-
"dependencies": {
|
|
34
|
-
"@danielsimonjr/mathts-workerpool": "^0.2.0"
|
|
35
|
-
},
|
|
36
|
-
"devDependencies": {
|
|
37
|
-
"@types/node": "^25.5.2",
|
|
38
|
-
"tsup": "^8.0.0",
|
|
39
|
-
"typescript": "^5.3.0",
|
|
40
|
-
"vitest": "^4.1.5"
|
|
41
|
-
},
|
|
42
|
-
"publishConfig": {
|
|
43
|
-
"access": "public"
|
|
44
|
-
},
|
|
45
|
-
"repository": {
|
|
46
|
-
"type": "git",
|
|
47
|
-
"url": "https://github.com/danielsimonjr/mathts",
|
|
48
|
-
"directory": "parallel"
|
|
49
|
-
},
|
|
50
|
-
"keywords": [
|
|
51
|
-
"math",
|
|
52
|
-
"typescript",
|
|
53
|
-
"parallel",
|
|
54
|
-
"webworker",
|
|
55
|
-
"worker-pool"
|
|
56
|
-
]
|
|
57
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@danielsimonjr/mathts-parallel",
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "WebWorker parallelization for MathTS computations",
|
|
5
|
+
"author": "Daniel Simon Jr.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup src/index.ts src/matrix.worker.ts --format esm --dts --clean",
|
|
23
|
+
"dev": "tsup src/index.ts src/matrix.worker.ts --format esm --dts --watch",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"test:coverage": "vitest run --coverage",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"lint": "eslint src --ext .ts",
|
|
29
|
+
"lint:fix": "eslint src --ext .ts --fix",
|
|
30
|
+
"clean": "rm -rf dist",
|
|
31
|
+
"build:prod": "tsup src/index.ts src/matrix.worker.ts --format esm --dts --clean --minify --treeshake"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@danielsimonjr/mathts-workerpool": "^0.2.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^25.5.2",
|
|
38
|
+
"tsup": "^8.0.0",
|
|
39
|
+
"typescript": "^5.3.0",
|
|
40
|
+
"vitest": "^4.1.5"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/danielsimonjr/mathts",
|
|
48
|
+
"directory": "parallel"
|
|
49
|
+
},
|
|
50
|
+
"keywords": [
|
|
51
|
+
"math",
|
|
52
|
+
"typescript",
|
|
53
|
+
"parallel",
|
|
54
|
+
"webworker",
|
|
55
|
+
"worker-pool"
|
|
56
|
+
]
|
|
57
|
+
}
|