@graphty/webgpu-graph-algorithms 0.6.14 → 0.6.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 +52 -52
- package/dist/browser.js +1 -1
- package/dist/chunks/{context-Bi6AhScG.js → context-VIvatQOo.js} +69 -34
- package/dist/chunks/context-VIvatQOo.js.map +1 -0
- package/dist/node.js +1 -1
- package/dist/src/accelerator.d.ts +5 -3
- package/dist/src/accelerator.d.ts.map +1 -1
- package/dist/src/accelerator.js +101 -5
- package/dist/src/accelerator.js.map +1 -1
- package/dist/src/algorithms/all-pairs.d.ts +41 -0
- package/dist/src/algorithms/all-pairs.d.ts.map +1 -0
- package/dist/src/algorithms/all-pairs.js +181 -0
- package/dist/src/algorithms/all-pairs.js.map +1 -0
- package/dist/src/algorithms/betweenness.d.ts +70 -0
- package/dist/src/algorithms/betweenness.d.ts.map +1 -0
- package/dist/src/algorithms/betweenness.js +538 -0
- package/dist/src/algorithms/betweenness.js.map +1 -0
- package/dist/src/algorithms/closeness.d.ts +15 -5
- package/dist/src/algorithms/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/closeness.js +112 -26
- package/dist/src/algorithms/closeness.js.map +1 -1
- package/dist/src/algorithms/components.d.ts +9 -1
- package/dist/src/algorithms/components.d.ts.map +1 -1
- package/dist/src/algorithms/components.js +2 -2
- package/dist/src/algorithms/components.js.map +1 -1
- package/dist/src/algorithms/label-propagation.d.ts +31 -0
- package/dist/src/algorithms/label-propagation.d.ts.map +1 -0
- package/dist/src/algorithms/label-propagation.js +254 -0
- package/dist/src/algorithms/label-propagation.js.map +1 -0
- package/dist/src/algorithms/simple-symmetric.d.ts +88 -0
- package/dist/src/algorithms/simple-symmetric.d.ts.map +1 -0
- package/dist/src/algorithms/simple-symmetric.js +347 -0
- package/dist/src/algorithms/simple-symmetric.js.map +1 -0
- package/dist/src/algorithms/triangles.d.ts +34 -0
- package/dist/src/algorithms/triangles.d.ts.map +1 -0
- package/dist/src/algorithms/triangles.js +203 -0
- package/dist/src/algorithms/triangles.js.map +1 -0
- package/dist/src/constants.d.ts +53 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +53 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +12 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/kernel/prelude.d.ts.map +1 -1
- package/dist/src/kernel/prelude.js +4 -1
- package/dist/src/kernel/prelude.js.map +1 -1
- package/dist/src/kernels.d.ts +24 -6
- package/dist/src/kernels.d.ts.map +1 -1
- package/dist/src/kernels.js +373 -7
- package/dist/src/kernels.js.map +1 -1
- package/dist/src/memory/residency.js +15 -4
- package/dist/src/memory/residency.js.map +1 -1
- package/dist/src/primitives/coo-to-csr.d.ts +73 -0
- package/dist/src/primitives/coo-to-csr.d.ts.map +1 -0
- package/dist/src/primitives/coo-to-csr.js +183 -0
- package/dist/src/primitives/coo-to-csr.js.map +1 -0
- package/dist/src/primitives/frontier.d.ts +2 -0
- package/dist/src/primitives/frontier.d.ts.map +1 -1
- package/dist/src/primitives/frontier.js +2 -0
- package/dist/src/primitives/frontier.js.map +1 -1
- package/dist/src/primitives/group-by-key.d.ts +82 -0
- package/dist/src/primitives/group-by-key.d.ts.map +1 -0
- package/dist/src/primitives/group-by-key.js +147 -0
- package/dist/src/primitives/group-by-key.js.map +1 -0
- package/dist/src/types/accelerator.d.ts +19 -7
- package/dist/src/types/accelerator.d.ts.map +1 -1
- package/dist/src/types/algorithms.d.ts +4 -0
- package/dist/src/types/algorithms.d.ts.map +1 -1
- package/dist/src/types/all-pairs.d.ts +35 -0
- package/dist/src/types/all-pairs.d.ts.map +1 -0
- package/dist/src/types/all-pairs.js +8 -0
- package/dist/src/types/all-pairs.js.map +1 -0
- package/dist/src/types/betweenness.d.ts +35 -0
- package/dist/src/types/betweenness.d.ts.map +1 -0
- package/dist/src/types/betweenness.js +7 -0
- package/dist/src/types/betweenness.js.map +1 -0
- package/dist/src/types/community.d.ts +18 -0
- package/dist/src/types/community.d.ts.map +1 -0
- package/dist/src/types/community.js +5 -0
- package/dist/src/types/community.js.map +1 -0
- package/dist/src/types/structure.d.ts +27 -0
- package/dist/src/types/structure.d.ts.map +1 -0
- package/dist/src/types/structure.js +8 -0
- package/dist/src/types/structure.js.map +1 -0
- package/dist/src/wgsl/apsp-fw.wgsl.d.ts +25 -0
- package/dist/src/wgsl/apsp-fw.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/apsp-fw.wgsl.js +113 -0
- package/dist/src/wgsl/apsp-fw.wgsl.js.map +1 -0
- package/dist/src/wgsl/apsp-init.wgsl.d.ts +12 -0
- package/dist/src/wgsl/apsp-init.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/apsp-init.wgsl.js +26 -0
- package/dist/src/wgsl/apsp-init.wgsl.js.map +1 -0
- package/dist/src/wgsl/bc-backward.wgsl.d.ts +15 -0
- package/dist/src/wgsl/bc-backward.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bc-backward.wgsl.js +34 -0
- package/dist/src/wgsl/bc-backward.wgsl.js.map +1 -0
- package/dist/src/wgsl/bc-edge-gather.wgsl.d.ts +12 -0
- package/dist/src/wgsl/bc-edge-gather.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bc-edge-gather.wgsl.js +36 -0
- package/dist/src/wgsl/bc-edge-gather.wgsl.js.map +1 -0
- package/dist/src/wgsl/bc-finalize.wgsl.d.ts +21 -0
- package/dist/src/wgsl/bc-finalize.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bc-finalize.wgsl.js +47 -0
- package/dist/src/wgsl/bc-finalize.wgsl.js.map +1 -0
- package/dist/src/wgsl/bc-forward-edge.wgsl.d.ts +15 -0
- package/dist/src/wgsl/bc-forward-edge.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bc-forward-edge.wgsl.js +76 -0
- package/dist/src/wgsl/bc-forward-edge.wgsl.js.map +1 -0
- package/dist/src/wgsl/bc-forward.wgsl.d.ts +23 -0
- package/dist/src/wgsl/bc-forward.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bc-forward.wgsl.js +106 -0
- package/dist/src/wgsl/bc-forward.wgsl.js.map +1 -0
- package/dist/src/wgsl/bc-gather.wgsl.d.ts +9 -0
- package/dist/src/wgsl/bc-gather.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bc-gather.wgsl.js +20 -0
- package/dist/src/wgsl/bc-gather.wgsl.js.map +1 -0
- package/dist/src/wgsl/closeness-reduce.wgsl.d.ts +4 -1
- package/dist/src/wgsl/closeness-reduce.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/closeness-reduce.wgsl.js +8 -4
- package/dist/src/wgsl/closeness-reduce.wgsl.js.map +1 -1
- package/dist/src/wgsl/closeness-sweep.wgsl.d.ts +4 -2
- package/dist/src/wgsl/closeness-sweep.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/closeness-sweep.wgsl.js +12 -2
- package/dist/src/wgsl/closeness-sweep.wgsl.js.map +1 -1
- package/dist/src/wgsl/coo-emit.wgsl.d.ts +10 -0
- package/dist/src/wgsl/coo-emit.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/coo-emit.wgsl.js +33 -0
- package/dist/src/wgsl/coo-emit.wgsl.js.map +1 -0
- package/dist/src/wgsl/coo-scatter.wgsl.d.ts +15 -0
- package/dist/src/wgsl/coo-scatter.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/coo-scatter.wgsl.js +32 -0
- package/dist/src/wgsl/coo-scatter.wgsl.js.map +1 -0
- package/dist/src/wgsl/group-by-key-row.wgsl.d.ts +26 -0
- package/dist/src/wgsl/group-by-key-row.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/group-by-key-row.wgsl.js +146 -0
- package/dist/src/wgsl/group-by-key-row.wgsl.js.map +1 -0
- package/dist/src/wgsl/lpa-step.wgsl.d.ts +10 -0
- package/dist/src/wgsl/lpa-step.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/lpa-step.wgsl.js +35 -0
- package/dist/src/wgsl/lpa-step.wgsl.js.map +1 -0
- package/dist/src/wgsl/orient-flags.wgsl.d.ts +9 -0
- package/dist/src/wgsl/orient-flags.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/orient-flags.wgsl.js +21 -0
- package/dist/src/wgsl/orient-flags.wgsl.js.map +1 -0
- package/dist/src/wgsl/run-flags.wgsl.d.ts +8 -0
- package/dist/src/wgsl/run-flags.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/run-flags.wgsl.js +18 -0
- package/dist/src/wgsl/run-flags.wgsl.js.map +1 -0
- package/dist/src/wgsl/tri-intersect.wgsl.d.ts +11 -0
- package/dist/src/wgsl/tri-intersect.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/tri-intersect.wgsl.js +64 -0
- package/dist/src/wgsl/tri-intersect.wgsl.js.map +1 -0
- package/dist/webgpu-graph-algorithms.js +2828 -321
- package/dist/webgpu-graph-algorithms.js.map +1 -1
- package/package.json +5 -5
- package/src/accelerator.ts +130 -7
- package/src/algorithms/all-pairs.ts +228 -0
- package/src/algorithms/betweenness.ts +739 -0
- package/src/algorithms/closeness.ts +124 -32
- package/src/algorithms/components.ts +2 -2
- package/src/algorithms/label-propagation.ts +280 -0
- package/src/algorithms/simple-symmetric.ts +409 -0
- package/src/algorithms/triangles.ts +240 -0
- package/src/constants.ts +53 -0
- package/src/index.ts +20 -1
- package/src/kernel/prelude.ts +6 -0
- package/src/kernels.ts +411 -10
- package/src/memory/residency.ts +15 -4
- package/src/primitives/coo-to-csr.ts +251 -0
- package/src/primitives/frontier.ts +4 -0
- package/src/primitives/group-by-key.ts +209 -0
- package/src/types/accelerator.ts +26 -6
- package/src/types/algorithms.ts +5 -0
- package/src/types/all-pairs.ts +37 -0
- package/src/types/betweenness.ts +38 -0
- package/src/types/community.ts +18 -0
- package/src/types/structure.ts +28 -0
- package/src/wgsl/apsp-fw.wgsl.ts +112 -0
- package/src/wgsl/apsp-init.wgsl.ts +25 -0
- package/src/wgsl/bc-backward.wgsl.ts +33 -0
- package/src/wgsl/bc-edge-gather.wgsl.ts +35 -0
- package/src/wgsl/bc-finalize.wgsl.ts +46 -0
- package/src/wgsl/bc-forward-edge.wgsl.ts +75 -0
- package/src/wgsl/bc-forward.wgsl.ts +105 -0
- package/src/wgsl/bc-gather.wgsl.ts +19 -0
- package/src/wgsl/closeness-reduce.wgsl.ts +8 -4
- package/src/wgsl/closeness-sweep.wgsl.ts +12 -2
- package/src/wgsl/coo-emit.wgsl.ts +32 -0
- package/src/wgsl/coo-scatter.wgsl.ts +31 -0
- package/src/wgsl/group-by-key-row.wgsl.ts +145 -0
- package/src/wgsl/lpa-step.wgsl.ts +34 -0
- package/src/wgsl/orient-flags.wgsl.ts +20 -0
- package/src/wgsl/run-flags.wgsl.ts +17 -0
- package/src/wgsl/tri-intersect.wgsl.ts +63 -0
- package/dist/chunks/context-Bi6AhScG.js.map +0 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The all-pairs shortest-path result and option records (design 3.3 lines 813 and 835, 8.7, 9.7). The result is the
|
|
3
|
+
* design's shape verbatim; every sentinel is spelled on its field, because a consumer who reads a `0` off the diagonal
|
|
4
|
+
* or an `Infinity` off the matrix and guesses what it means is the failure this file prevents. Types only: this file
|
|
5
|
+
* imports nothing at runtime.
|
|
6
|
+
*/
|
|
7
|
+
import type { F32 } from "@graphty/graph-format";
|
|
8
|
+
/**
|
|
9
|
+
* Design 3.3 line 835: what `allPairsShortestPath` returns. Satisfies the seam's `ApspResultLike` (`dist:
|
|
10
|
+
* NumericVector` admits `F32`).
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export interface GpuApspResult {
|
|
14
|
+
/**
|
|
15
|
+
* The `n * n` distances, row-major: `dist[i * n + j]` is the shortest distance FROM `i` TO `j` (the i-to-j
|
|
16
|
+
* direction on a directed snapshot). `+Infinity` when `j` is unreachable from `i`. The diagonal is `0` even when
|
|
17
|
+
* a self-loop carries a weight. f32 throughout; hop counts are exact integers.
|
|
18
|
+
*/
|
|
19
|
+
readonly dist: F32;
|
|
20
|
+
/** The node count; `dist.length === n * n`. */
|
|
21
|
+
readonly n: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The options of `allPairsShortestPath` beyond `GpuRunOptions`. Nothing else: a cutoff would change the meaning of
|
|
25
|
+
* `+Infinity`, and the design asks for none.
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
export interface ApspOptions {
|
|
29
|
+
/**
|
|
30
|
+
* Use the snapshot's weight column. Default: true when the snapshot has weights. `false` on a weighted snapshot
|
|
31
|
+
* computes HOP COUNTS (every arc costs 1), not distances.
|
|
32
|
+
*/
|
|
33
|
+
readonly weighted?: boolean | undefined;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=all-pairs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"all-pairs.d.ts","sourceRoot":"","sources":["../../../src/types/all-pairs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC;IACnB,+CAA+C;IAC/C,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IACxB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC3C"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The all-pairs shortest-path result and option records (design 3.3 lines 813 and 835, 8.7, 9.7). The result is the
|
|
3
|
+
* design's shape verbatim; every sentinel is spelled on its field, because a consumer who reads a `0` off the diagonal
|
|
4
|
+
* or an `Infinity` off the matrix and guesses what it means is the failure this file prevents. Types only: this file
|
|
5
|
+
* imports nothing at runtime.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=all-pairs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"all-pairs.js","sourceRoot":"","sources":["../../../src/types/all-pairs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The betweenness result records (spec 3.3 lines 833-834). Types only: this file imports nothing at runtime. The
|
|
3
|
+
* options are the CPU seam's own `BetweennessAcceleratorOptions` (`normalized`, `endpoints`, `sources`, `k`), as the
|
|
4
|
+
* traversals take the seam's option types.
|
|
5
|
+
*/
|
|
6
|
+
import type { F32 } from "@graphty/graph-format";
|
|
7
|
+
import type { GpuScoresResult } from "./algorithms.js";
|
|
8
|
+
/**
|
|
9
|
+
* Vertex betweenness (spec 3.3 line 833). A SAMPLED run (`sources` or `k`) returns the UNSCALED sum over the sources
|
|
10
|
+
* actually run -- never extrapolated by `n / k` -- and `sourcesUsed` says how many that was; a caller who wants the
|
|
11
|
+
* estimator of the full sum multiplies by `n / sourcesUsed`.
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
export interface GpuBetweennessResult extends GpuScoresResult {
|
|
15
|
+
/** How many sources the scores sum over: `n` for an exact run, the sample size for a sampled one. */
|
|
16
|
+
readonly sourcesUsed: number;
|
|
17
|
+
/**
|
|
18
|
+
* True when some pair of vertices is joined by more than 2^32 shortest paths: the u32 path counts wrapped and the
|
|
19
|
+
* scores are WRONG, not approximate. Never clamped, never silent.
|
|
20
|
+
*/
|
|
21
|
+
readonly sigmaOverflow: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Edge betweenness (spec 3.3 line 834): one score per logical edge (`edgeCount`), the per-arc scores folded with
|
|
25
|
+
* `foldArcs(s, perArc, "sum")` and halved on an undirected snapshot (the two arcs carry the pairs crossing the edge
|
|
26
|
+
* in each direction). `sourcesUsed` and `sigmaOverflow` mean what they mean on `GpuBetweennessResult`.
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
export interface GpuEdgeScoresResult {
|
|
30
|
+
readonly scores: F32;
|
|
31
|
+
readonly precision: "f32";
|
|
32
|
+
readonly sourcesUsed: number;
|
|
33
|
+
readonly sigmaOverflow: boolean;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=betweenness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"betweenness.d.ts","sourceRoot":"","sources":["../../../src/types/betweenness.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAEjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IACzD,qGAAqG;IACrG,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAChC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACnC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The betweenness result records (spec 3.3 lines 833-834). Types only: this file imports nothing at runtime. The
|
|
3
|
+
* options are the CPU seam's own `BetweennessAcceleratorOptions` (`normalized`, `endpoints`, `sources`, `k`), as the
|
|
4
|
+
* traversals take the seam's option types.
|
|
5
|
+
*/
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=betweenness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"betweenness.js","sourceRoot":"","sources":["../../../src/types/betweenness.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The option record of label propagation (design 3.3 line 807, 8.6). Types only.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Label propagation's options. Ties between neighbour labels are broken by the LOWEST label, never at random, so
|
|
6
|
+
* the result is bitwise reproducible on one device; that is also why there is no `randomSeed`.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export interface LabelPropagationOptions {
|
|
10
|
+
/** The largest number of passes (default 100, as in `@graphty/algorithms`); a non-negative integer. */
|
|
11
|
+
readonly maxIterations?: number | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Sum the weights of the edges to each neighbour label (default true; an unweighted snapshot's edges weigh 1
|
|
14
|
+
* each, so a parallel edge counts once per copy); false counts every distinct neighbour once.
|
|
15
|
+
*/
|
|
16
|
+
readonly weighted?: boolean | undefined;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=community.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"community.d.ts","sourceRoot":"","sources":["../../../src/types/community.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACpC,uGAAuG;IACvG,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC3C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"community.js","sourceRoot":"","sources":["../../../src/types/community.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The result record of triangle counting (design 3.3 line 828, 8.5; design 17 line 5067). Design 3.3 declares
|
|
3
|
+
* `{ perNode, total }`; this package also returns the clustering coefficient and the transitivity, because they are
|
|
4
|
+
* an epilogue over the counts and degrees the call already holds and nothing else in the monorepo computes them.
|
|
5
|
+
* Types only.
|
|
6
|
+
*/
|
|
7
|
+
import type { F32, U32 } from "@graphty/graph-format";
|
|
8
|
+
/**
|
|
9
|
+
* Triangle counting over the simple undirected graph underlying the snapshot: arc directions are ignored, parallel
|
|
10
|
+
* edges count once and self-loops not at all, so a directed snapshot and its undirected twin give the same answer.
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export interface GpuTriangleResult {
|
|
14
|
+
/** The triangles each node lies in. */
|
|
15
|
+
readonly perNode: U32;
|
|
16
|
+
/** The triangles of the graph (each counted once). */
|
|
17
|
+
readonly total: number;
|
|
18
|
+
/**
|
|
19
|
+
* The local clustering coefficient of every node, `2 T(v) / (d(v) (d(v) - 1))` with `d` the node's number of
|
|
20
|
+
* distinct neighbours. It is 0 -- a defined value, not a missing one -- for a node with fewer than two
|
|
21
|
+
* neighbours, so a star graph returns all zeros.
|
|
22
|
+
*/
|
|
23
|
+
readonly coefficient: F32;
|
|
24
|
+
/** The graph's transitivity, `3 x triangles / connected triples`; 0 when the graph has no connected triple. */
|
|
25
|
+
readonly transitivity: number;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=structure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structure.d.ts","sourceRoot":"","sources":["../../../src/types/structure.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAC9B,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC;IACtB,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC;IAC1B,+GAA+G;IAC/G,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CACjC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The result record of triangle counting (design 3.3 line 828, 8.5; design 17 line 5067). Design 3.3 declares
|
|
3
|
+
* `{ perNode, total }`; this package also returns the clustering coefficient and the transitivity, because they are
|
|
4
|
+
* an epilogue over the counts and degrees the call already holds and nothing else in the monorepo computes them.
|
|
5
|
+
* Types only.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=structure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structure.js","sourceRoot":"","sources":["../../../src/types/structure.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `apsp-fw` kernel body (design 8.7): one phase of one round of blocked Floyd-Warshall over `APSP_TILE x
|
|
3
|
+
* APSP_TILE` blocks of the row-major `n x n` matrix `dist`. Round `r` (`P.round`) runs three dispatches in order,
|
|
4
|
+
* the `PHASE` override choosing which:
|
|
5
|
+
*
|
|
6
|
+
* - PHASE 0, one workgroup: the pivot block `(r, r)`, staged in `tileA` and updated in place.
|
|
7
|
+
* - PHASE 1, `2 (B - 1)` workgroups (`B` = `P.blocks`): every other block of block row `r` (the first `B - 1`
|
|
8
|
+
* workgroups) and of block column `r` (the rest). The pivot block is staged in `tileA`, the block itself in
|
|
9
|
+
* `tileB`, updated in place.
|
|
10
|
+
* - PHASE 2, `(B - 1)^2` workgroups: every block `(i, j)` off the pivot row and column. Its two operands are the
|
|
11
|
+
* pivot-COLUMN block `(i, r)` in `tileA` and the pivot-ROW block `(r, j)` in `tileB`; its own cells are read,
|
|
12
|
+
* minimised over the 32 steps and written by one lane each, never shared, so they stay in registers.
|
|
13
|
+
*
|
|
14
|
+
* In-place updates are race-free because a cell is written only when the candidate is STRICTLY smaller: the cells
|
|
15
|
+
* every lane reads in step `k` (column `k` and row `k` of the tile) would be updated with `d + d[k][k]`, and the
|
|
16
|
+
* diagonal is `0` (weights are non-negative, which the driver checks) or `+Infinity` outside the matrix, so they are
|
|
17
|
+
* never written in step `k`. Every barrier is reached in uniform control flow: the early return keys on the workgroup
|
|
18
|
+
* id and uniforms only, the per-lane loops hold no barrier, and the lanes of an edge tile load `+Infinity` for a cell
|
|
19
|
+
* outside `n x n` (it offers no path; read from `P.infBits` because Tint refuses `+Infinity` as a constant) and
|
|
20
|
+
* store nothing there -- the matrix is exactly `n * n`, never padded, so the
|
|
21
|
+
* ceiling is `floor(sqrt(maxStorageBufferBindingSize / 4))`. Body only (spec 3.5, D9); the text is normative: the
|
|
22
|
+
* sabotage rows of test/helpers/sabotage.ts are textual edits of it.
|
|
23
|
+
*/
|
|
24
|
+
export declare const apspFwWgsl = "\nvar<workgroup> tileA: array<f32, APSP_TILE * APSP_TILE>;\nvar<workgroup> tileB: array<f32, APSP_TILE * APSP_TILE>;\n\nfn tile_row(block: vec2<u32>, c: u32) -> u32 { return block.x * APSP_TILE + c / APSP_TILE; }\nfn tile_col(block: vec2<u32>, c: u32) -> u32 { return block.y * APSP_TILE + c % APSP_TILE; }\n\nfn load_cell(block: vec2<u32>, c: u32) -> f32 {\n let i = tile_row(block, c);\n let j = tile_col(block, c);\n if (i < P.n && j < P.n) { return dist[i * P.n + j]; }\n return bitcast<f32>(P.infBits); // outside the matrix: no path through it\n}\n\nfn store_cell(block: vec2<u32>, c: u32, v: f32) {\n let i = tile_row(block, c);\n let j = tile_col(block, c);\n if (i >= P.n || j >= P.n) { return; } // an edge tile stores nothing outside n x n\n dist[i * P.n + j] = v;\n}\n\n@compute @workgroup_size(WG)\nfn apsp_fw(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let g = group_id(wid);\n let r = P.round;\n let others = max(P.blocks, 2u) - 1u; // the blocks of a strip, the pivot excluded\n let cells = APSP_TILE * APSP_TILE;\n var count = 1u;\n var own = vec2<u32>(r, r); // the block this workgroup updates\n var a = vec2<u32>(r, r); // staged in tileA\n var b = vec2<u32>(r, r); // staged in tileB\n if (PHASE == 1u) {\n count = 2u * others;\n let s = g % others;\n let o = select(s, s + 1u, s >= r); // a strip skips the pivot block\n own = select(vec2<u32>(o, r), vec2<u32>(r, o), g < others); // block row r first, then block column r\n b = own;\n }\n if (PHASE == 2u) {\n count = others * others;\n let i = g / others;\n let j = g % others;\n own = vec2<u32>(select(i, i + 1u, i >= r), select(j, j + 1u, j >= r));\n a = vec2<u32>(own.x, r); // the pivot-column block (i, r)\n b = vec2<u32>(r, own.y); // the pivot-row block (r, j)\n }\n if (g >= count) { return; } // uniform: the workgroup id and uniforms only\n\n for (var c = lid.x; c < cells; c = c + WG) {\n tileA[c] = load_cell(a, c);\n if (PHASE != 0u) { tileB[c] = load_cell(b, c); }\n }\n workgroupBarrier(); // every staged cell is visible\n\n if (PHASE == 2u) {\n for (var c = lid.x; c < cells; c = c + WG) {\n let x = c / APSP_TILE;\n let y = c % APSP_TILE;\n var v = load_cell(own, c);\n for (var kr = 0u; kr < APSP_TILE; kr = kr + 1u) {\n v = min(v, tileA[x * APSP_TILE + kr] + tileB[kr * APSP_TILE + y]);\n }\n store_cell(own, c, v);\n }\n return;\n }\n\n let pivotRow = PHASE == 1u && own.x == r; // block row r reads d[x][k] from the pivot\n for (var k = 0u; k < APSP_TILE; k = k + 1u) {\n for (var c = lid.x; c < cells; c = c + WG) {\n let x = c / APSP_TILE;\n let y = c % APSP_TILE;\n if (PHASE == 0u) {\n let via = tileA[x * APSP_TILE + k] + tileA[k * APSP_TILE + y];\n if (via < tileA[c]) { tileA[c] = via; }\n } else {\n let left = select(tileB[x * APSP_TILE + k], tileA[x * APSP_TILE + k], pivotRow);\n let right = select(tileA[k * APSP_TILE + y], tileB[k * APSP_TILE + y], pivotRow);\n let via = left + right;\n if (via < tileB[c]) { tileB[c] = via; }\n }\n }\n workgroupBarrier(); // step k is complete before step k + 1 reads\n }\n for (var c = lid.x; c < cells; c = c + WG) {\n store_cell(own, c, select(tileB[c], tileA[c], PHASE == 0u));\n }\n}\n";
|
|
25
|
+
//# sourceMappingURL=apsp-fw.wgsl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apsp-fw.wgsl.d.ts","sourceRoot":"","sources":["../../../src/wgsl/apsp-fw.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,UAAU,4gIAwFtB,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `apsp-fw` kernel body (design 8.7): one phase of one round of blocked Floyd-Warshall over `APSP_TILE x
|
|
3
|
+
* APSP_TILE` blocks of the row-major `n x n` matrix `dist`. Round `r` (`P.round`) runs three dispatches in order,
|
|
4
|
+
* the `PHASE` override choosing which:
|
|
5
|
+
*
|
|
6
|
+
* - PHASE 0, one workgroup: the pivot block `(r, r)`, staged in `tileA` and updated in place.
|
|
7
|
+
* - PHASE 1, `2 (B - 1)` workgroups (`B` = `P.blocks`): every other block of block row `r` (the first `B - 1`
|
|
8
|
+
* workgroups) and of block column `r` (the rest). The pivot block is staged in `tileA`, the block itself in
|
|
9
|
+
* `tileB`, updated in place.
|
|
10
|
+
* - PHASE 2, `(B - 1)^2` workgroups: every block `(i, j)` off the pivot row and column. Its two operands are the
|
|
11
|
+
* pivot-COLUMN block `(i, r)` in `tileA` and the pivot-ROW block `(r, j)` in `tileB`; its own cells are read,
|
|
12
|
+
* minimised over the 32 steps and written by one lane each, never shared, so they stay in registers.
|
|
13
|
+
*
|
|
14
|
+
* In-place updates are race-free because a cell is written only when the candidate is STRICTLY smaller: the cells
|
|
15
|
+
* every lane reads in step `k` (column `k` and row `k` of the tile) would be updated with `d + d[k][k]`, and the
|
|
16
|
+
* diagonal is `0` (weights are non-negative, which the driver checks) or `+Infinity` outside the matrix, so they are
|
|
17
|
+
* never written in step `k`. Every barrier is reached in uniform control flow: the early return keys on the workgroup
|
|
18
|
+
* id and uniforms only, the per-lane loops hold no barrier, and the lanes of an edge tile load `+Infinity` for a cell
|
|
19
|
+
* outside `n x n` (it offers no path; read from `P.infBits` because Tint refuses `+Infinity` as a constant) and
|
|
20
|
+
* store nothing there -- the matrix is exactly `n * n`, never padded, so the
|
|
21
|
+
* ceiling is `floor(sqrt(maxStorageBufferBindingSize / 4))`. Body only (spec 3.5, D9); the text is normative: the
|
|
22
|
+
* sabotage rows of test/helpers/sabotage.ts are textual edits of it.
|
|
23
|
+
*/
|
|
24
|
+
export const apspFwWgsl = /* wgsl */ `
|
|
25
|
+
var<workgroup> tileA: array<f32, APSP_TILE * APSP_TILE>;
|
|
26
|
+
var<workgroup> tileB: array<f32, APSP_TILE * APSP_TILE>;
|
|
27
|
+
|
|
28
|
+
fn tile_row(block: vec2<u32>, c: u32) -> u32 { return block.x * APSP_TILE + c / APSP_TILE; }
|
|
29
|
+
fn tile_col(block: vec2<u32>, c: u32) -> u32 { return block.y * APSP_TILE + c % APSP_TILE; }
|
|
30
|
+
|
|
31
|
+
fn load_cell(block: vec2<u32>, c: u32) -> f32 {
|
|
32
|
+
let i = tile_row(block, c);
|
|
33
|
+
let j = tile_col(block, c);
|
|
34
|
+
if (i < P.n && j < P.n) { return dist[i * P.n + j]; }
|
|
35
|
+
return bitcast<f32>(P.infBits); // outside the matrix: no path through it
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
fn store_cell(block: vec2<u32>, c: u32, v: f32) {
|
|
39
|
+
let i = tile_row(block, c);
|
|
40
|
+
let j = tile_col(block, c);
|
|
41
|
+
if (i >= P.n || j >= P.n) { return; } // an edge tile stores nothing outside n x n
|
|
42
|
+
dist[i * P.n + j] = v;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@compute @workgroup_size(WG)
|
|
46
|
+
fn apsp_fw(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
|
47
|
+
let g = group_id(wid);
|
|
48
|
+
let r = P.round;
|
|
49
|
+
let others = max(P.blocks, 2u) - 1u; // the blocks of a strip, the pivot excluded
|
|
50
|
+
let cells = APSP_TILE * APSP_TILE;
|
|
51
|
+
var count = 1u;
|
|
52
|
+
var own = vec2<u32>(r, r); // the block this workgroup updates
|
|
53
|
+
var a = vec2<u32>(r, r); // staged in tileA
|
|
54
|
+
var b = vec2<u32>(r, r); // staged in tileB
|
|
55
|
+
if (PHASE == 1u) {
|
|
56
|
+
count = 2u * others;
|
|
57
|
+
let s = g % others;
|
|
58
|
+
let o = select(s, s + 1u, s >= r); // a strip skips the pivot block
|
|
59
|
+
own = select(vec2<u32>(o, r), vec2<u32>(r, o), g < others); // block row r first, then block column r
|
|
60
|
+
b = own;
|
|
61
|
+
}
|
|
62
|
+
if (PHASE == 2u) {
|
|
63
|
+
count = others * others;
|
|
64
|
+
let i = g / others;
|
|
65
|
+
let j = g % others;
|
|
66
|
+
own = vec2<u32>(select(i, i + 1u, i >= r), select(j, j + 1u, j >= r));
|
|
67
|
+
a = vec2<u32>(own.x, r); // the pivot-column block (i, r)
|
|
68
|
+
b = vec2<u32>(r, own.y); // the pivot-row block (r, j)
|
|
69
|
+
}
|
|
70
|
+
if (g >= count) { return; } // uniform: the workgroup id and uniforms only
|
|
71
|
+
|
|
72
|
+
for (var c = lid.x; c < cells; c = c + WG) {
|
|
73
|
+
tileA[c] = load_cell(a, c);
|
|
74
|
+
if (PHASE != 0u) { tileB[c] = load_cell(b, c); }
|
|
75
|
+
}
|
|
76
|
+
workgroupBarrier(); // every staged cell is visible
|
|
77
|
+
|
|
78
|
+
if (PHASE == 2u) {
|
|
79
|
+
for (var c = lid.x; c < cells; c = c + WG) {
|
|
80
|
+
let x = c / APSP_TILE;
|
|
81
|
+
let y = c % APSP_TILE;
|
|
82
|
+
var v = load_cell(own, c);
|
|
83
|
+
for (var kr = 0u; kr < APSP_TILE; kr = kr + 1u) {
|
|
84
|
+
v = min(v, tileA[x * APSP_TILE + kr] + tileB[kr * APSP_TILE + y]);
|
|
85
|
+
}
|
|
86
|
+
store_cell(own, c, v);
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let pivotRow = PHASE == 1u && own.x == r; // block row r reads d[x][k] from the pivot
|
|
92
|
+
for (var k = 0u; k < APSP_TILE; k = k + 1u) {
|
|
93
|
+
for (var c = lid.x; c < cells; c = c + WG) {
|
|
94
|
+
let x = c / APSP_TILE;
|
|
95
|
+
let y = c % APSP_TILE;
|
|
96
|
+
if (PHASE == 0u) {
|
|
97
|
+
let via = tileA[x * APSP_TILE + k] + tileA[k * APSP_TILE + y];
|
|
98
|
+
if (via < tileA[c]) { tileA[c] = via; }
|
|
99
|
+
} else {
|
|
100
|
+
let left = select(tileB[x * APSP_TILE + k], tileA[x * APSP_TILE + k], pivotRow);
|
|
101
|
+
let right = select(tileA[k * APSP_TILE + y], tileB[k * APSP_TILE + y], pivotRow);
|
|
102
|
+
let via = left + right;
|
|
103
|
+
if (via < tileB[c]) { tileB[c] = via; }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
workgroupBarrier(); // step k is complete before step k + 1 reads
|
|
107
|
+
}
|
|
108
|
+
for (var c = lid.x; c < cells; c = c + WG) {
|
|
109
|
+
store_cell(own, c, select(tileB[c], tileA[c], PHASE == 0u));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
`;
|
|
113
|
+
//# sourceMappingURL=apsp-fw.wgsl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apsp-fw.wgsl.js","sourceRoot":"","sources":["../../../src/wgsl/apsp-fw.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwFpC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `apsp-init` kernel body (design 8.7): writes the arcs into the `n x n` distance matrix after `fill` has set
|
|
3
|
+
* every entry to `+Infinity`. One lane per ROW `u`: it walks `u`'s arcs and keeps the cheapest weight per target
|
|
4
|
+
* (`min`), so parallel arcs collapse to the cheapest one, then writes the diagonal zero LAST, so a self-loop never
|
|
5
|
+
* displaces it. Every arc of row `u` lands in row `u` of the matrix and only this lane writes that row, so there is
|
|
6
|
+
* no race and no atomic. Unweighted (`HAS_WEIGHTS` false) every arc costs 1. A directed snapshot writes its one
|
|
7
|
+
* direction; an undirected one stores both arcs of every edge, so both halves are written. The driver refuses
|
|
8
|
+
* negative and non-finite weights before any dispatch. Body only (spec 3.5, D9); the text is normative: the
|
|
9
|
+
* sabotage rows of test/helpers/sabotage.ts are textual edits of it.
|
|
10
|
+
*/
|
|
11
|
+
export declare const apspInitWgsl = "\n@compute @workgroup_size(WG)\nfn apsp_init(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n let u = linear_id(wid, lid.x);\n if (u >= P.n) { return; }\n let rowBase = u * P.n;\n let end = rowPtr[u + 1u];\n for (var a = rowPtr[u]; a < end; a = a + 1u) {\n let v = colIdx[a];\n let w = select(1.0, weights[a], HAS_WEIGHTS);\n dist[rowBase + v] = min(dist[rowBase + v], w); // parallel arcs collapse to the cheapest\n }\n dist[rowBase + u] = 0.0; // last: a self-loop never displaces the zero\n}\n";
|
|
12
|
+
//# sourceMappingURL=apsp-init.wgsl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apsp-init.wgsl.d.ts","sourceRoot":"","sources":["../../../src/wgsl/apsp-init.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,8nBAcxB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `apsp-init` kernel body (design 8.7): writes the arcs into the `n x n` distance matrix after `fill` has set
|
|
3
|
+
* every entry to `+Infinity`. One lane per ROW `u`: it walks `u`'s arcs and keeps the cheapest weight per target
|
|
4
|
+
* (`min`), so parallel arcs collapse to the cheapest one, then writes the diagonal zero LAST, so a self-loop never
|
|
5
|
+
* displaces it. Every arc of row `u` lands in row `u` of the matrix and only this lane writes that row, so there is
|
|
6
|
+
* no race and no atomic. Unweighted (`HAS_WEIGHTS` false) every arc costs 1. A directed snapshot writes its one
|
|
7
|
+
* direction; an undirected one stores both arcs of every edge, so both halves are written. The driver refuses
|
|
8
|
+
* negative and non-finite weights before any dispatch. Body only (spec 3.5, D9); the text is normative: the
|
|
9
|
+
* sabotage rows of test/helpers/sabotage.ts are textual edits of it.
|
|
10
|
+
*/
|
|
11
|
+
export const apspInitWgsl = /* wgsl */ `
|
|
12
|
+
@compute @workgroup_size(WG)
|
|
13
|
+
fn apsp_init(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
|
14
|
+
let u = linear_id(wid, lid.x);
|
|
15
|
+
if (u >= P.n) { return; }
|
|
16
|
+
let rowBase = u * P.n;
|
|
17
|
+
let end = rowPtr[u + 1u];
|
|
18
|
+
for (var a = rowPtr[u]; a < end; a = a + 1u) {
|
|
19
|
+
let v = colIdx[a];
|
|
20
|
+
let w = select(1.0, weights[a], HAS_WEIGHTS);
|
|
21
|
+
dist[rowBase + v] = min(dist[rowBase + v], w); // parallel arcs collapse to the cheapest
|
|
22
|
+
}
|
|
23
|
+
dist[rowBase + u] = 0.0; // last: a self-loop never displaces the zero
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
//# sourceMappingURL=apsp-init.wgsl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apsp-init.wgsl.js","sourceRoot":"","sources":["../../../src/wgsl/apsp-init.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;;;;;;;;;;;;;;CActC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `bc-backward` kernel body (design 8.4 "each (w, s) PULLS over its successors", 8.10 "BC backward (successor
|
|
3
|
+
* pull)"): one level of a betweenness batch's dependency accumulation, one invocation per log entry `(w, s)` of the
|
|
4
|
+
* level's range `S[P.start .. P.start + P.count)`, which the host planned from the `ends` it read back. Each entry
|
|
5
|
+
* walks the out-arcs of `w` -- the rows the forward pass expanded -- and sums `sigma[s][w] / sigma[s][v] * (1 +
|
|
6
|
+
* delta[s][v])` over the successors `v` (`depth[s][v] == depth[s][w] + 1`), whose dependencies the previous (deeper)
|
|
7
|
+
* dispatch wrote, then writes `delta[s][w]` ONCE. No float is ever accumulated through an atomic, so the result is
|
|
8
|
+
* bitwise reproducible. The sources (depth 0) are never dispatched: their dependency stays 0, which is what keeps a
|
|
9
|
+
* source's own dependency out of its score. Grid-stride loop (`P.stride`). ponytail: one lane walks one row, so a
|
|
10
|
+
* vertex of degree above 65,535 exceeds llvmpipe's per-invocation loop cap (CLAUDE.md, Verified Platform Facts) and
|
|
11
|
+
* would need a workgroup-per-row form there; hardware adapters have no such cap. Body only; the sabotage rows of
|
|
12
|
+
* test/helpers/sabotage.ts are textual edits of it.
|
|
13
|
+
*/
|
|
14
|
+
export declare const bcBackwardWgsl = "\n@compute @workgroup_size(WG)\nfn bc_backward(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n for (var i = linear_id(wid, lid.x); i < P.count; i = i + P.stride) {\n let t = S[P.start + i]; // s * n + w\n let w = t % P.n;\n let base = t - w; // s * n\n let succ = depthK[t] + 1u;\n let sw = f32(sigmaK[t]);\n var acc = 0.0;\n for (var a = rowPtr[w]; a < rowPtr[w + 1u]; a = a + 1u) {\n let v = base + colIdx[a];\n if (depthK[v] == succ) { // v is a successor of w for source s\n acc = acc + (sw / f32(sigmaK[v])) * (1.0 + deltaK[v]);\n }\n }\n deltaK[t] = acc; // written once per (w, s)\n }\n}\n";
|
|
15
|
+
//# sourceMappingURL=bc-backward.wgsl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bc-backward.wgsl.d.ts","sourceRoot":"","sources":["../../../src/wgsl/bc-backward.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,m5BAmB1B,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `bc-backward` kernel body (design 8.4 "each (w, s) PULLS over its successors", 8.10 "BC backward (successor
|
|
3
|
+
* pull)"): one level of a betweenness batch's dependency accumulation, one invocation per log entry `(w, s)` of the
|
|
4
|
+
* level's range `S[P.start .. P.start + P.count)`, which the host planned from the `ends` it read back. Each entry
|
|
5
|
+
* walks the out-arcs of `w` -- the rows the forward pass expanded -- and sums `sigma[s][w] / sigma[s][v] * (1 +
|
|
6
|
+
* delta[s][v])` over the successors `v` (`depth[s][v] == depth[s][w] + 1`), whose dependencies the previous (deeper)
|
|
7
|
+
* dispatch wrote, then writes `delta[s][w]` ONCE. No float is ever accumulated through an atomic, so the result is
|
|
8
|
+
* bitwise reproducible. The sources (depth 0) are never dispatched: their dependency stays 0, which is what keeps a
|
|
9
|
+
* source's own dependency out of its score. Grid-stride loop (`P.stride`). ponytail: one lane walks one row, so a
|
|
10
|
+
* vertex of degree above 65,535 exceeds llvmpipe's per-invocation loop cap (CLAUDE.md, Verified Platform Facts) and
|
|
11
|
+
* would need a workgroup-per-row form there; hardware adapters have no such cap. Body only; the sabotage rows of
|
|
12
|
+
* test/helpers/sabotage.ts are textual edits of it.
|
|
13
|
+
*/
|
|
14
|
+
export const bcBackwardWgsl = /* wgsl */ `
|
|
15
|
+
@compute @workgroup_size(WG)
|
|
16
|
+
fn bc_backward(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
|
17
|
+
for (var i = linear_id(wid, lid.x); i < P.count; i = i + P.stride) {
|
|
18
|
+
let t = S[P.start + i]; // s * n + w
|
|
19
|
+
let w = t % P.n;
|
|
20
|
+
let base = t - w; // s * n
|
|
21
|
+
let succ = depthK[t] + 1u;
|
|
22
|
+
let sw = f32(sigmaK[t]);
|
|
23
|
+
var acc = 0.0;
|
|
24
|
+
for (var a = rowPtr[w]; a < rowPtr[w + 1u]; a = a + 1u) {
|
|
25
|
+
let v = base + colIdx[a];
|
|
26
|
+
if (depthK[v] == succ) { // v is a successor of w for source s
|
|
27
|
+
acc = acc + (sw / f32(sigmaK[v])) * (1.0 + deltaK[v]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
deltaK[t] = acc; // written once per (w, s)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
34
|
+
//# sourceMappingURL=bc-backward.wgsl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bc-backward.wgsl.js","sourceRoot":"","sources":["../../../src/wgsl/bc-backward.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;CAmBxC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `bc-edge-gather` kernel body (design 8.4 "edge BC accumulates per arc from the same n x k deltas"): the per-arc
|
|
3
|
+
* twin of `bc-gather`, run once per batch after the backward sweep. One invocation per ARC (`P.count` arcs,
|
|
4
|
+
* grid-stride): it finds the row `w` that owns the arc by an upper-bound search over `rowPtr`, then adds over the
|
|
5
|
+
* batch's sources in order the term the backward pass summed -- `sigma[s][w] / sigma[s][v] * (1 + delta[s][v])`
|
|
6
|
+
* whenever `w` was reached and `depth[s][v] == depth[s][w] + 1` -- into `arcScores[arc]`. Each arc is written by one
|
|
7
|
+
* invocation: no atomic, a fixed order. Arc-parallel rather than row-parallel so a hub row is not one lane's loop
|
|
8
|
+
* (llvmpipe caps a shader loop at 65,535 iterations, and a 1,000-arc hub times 64 sources passed it). Body only;
|
|
9
|
+
* the sabotage rows of test/helpers/sabotage.ts are textual edits of it.
|
|
10
|
+
*/
|
|
11
|
+
export declare const bcEdgeGatherWgsl = "\n@compute @workgroup_size(WG)\nfn bc_edge_gather(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\n for (var a = linear_id(wid, lid.x); a < P.count; a = a + P.stride) {\n var lo = 0u; // the row w with rowPtr[w] <= a < rowPtr[w + 1]\n var hi = P.n;\n loop {\n if (lo >= hi) { break; }\n let mid = (lo + hi) / 2u;\n if (rowPtr[mid + 1u] <= a) { lo = mid + 1u; } else { hi = mid; }\n }\n let w = lo;\n let nbr = colIdx[a];\n var acc = arcScores[a];\n for (var s = 0u; s < P.k; s = s + 1u) {\n let base = s * P.n;\n let dw = depthK[base + w];\n if (dw != INVALID_INDEX && depthK[base + nbr] == dw + 1u) { // (w, nbr) is on a shortest path from s\n acc = acc + (f32(sigmaK[base + w]) / f32(sigmaK[base + nbr])) * (1.0 + deltaK[base + nbr]);\n }\n }\n arcScores[a] = acc;\n }\n}\n";
|
|
12
|
+
//# sourceMappingURL=bc-edge-gather.wgsl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bc-edge-gather.wgsl.d.ts","sourceRoot":"","sources":["../../../src/wgsl/bc-edge-gather.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,6gCAwB5B,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `bc-edge-gather` kernel body (design 8.4 "edge BC accumulates per arc from the same n x k deltas"): the per-arc
|
|
3
|
+
* twin of `bc-gather`, run once per batch after the backward sweep. One invocation per ARC (`P.count` arcs,
|
|
4
|
+
* grid-stride): it finds the row `w` that owns the arc by an upper-bound search over `rowPtr`, then adds over the
|
|
5
|
+
* batch's sources in order the term the backward pass summed -- `sigma[s][w] / sigma[s][v] * (1 + delta[s][v])`
|
|
6
|
+
* whenever `w` was reached and `depth[s][v] == depth[s][w] + 1` -- into `arcScores[arc]`. Each arc is written by one
|
|
7
|
+
* invocation: no atomic, a fixed order. Arc-parallel rather than row-parallel so a hub row is not one lane's loop
|
|
8
|
+
* (llvmpipe caps a shader loop at 65,535 iterations, and a 1,000-arc hub times 64 sources passed it). Body only;
|
|
9
|
+
* the sabotage rows of test/helpers/sabotage.ts are textual edits of it.
|
|
10
|
+
*/
|
|
11
|
+
export const bcEdgeGatherWgsl = /* wgsl */ `
|
|
12
|
+
@compute @workgroup_size(WG)
|
|
13
|
+
fn bc_edge_gather(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
|
14
|
+
for (var a = linear_id(wid, lid.x); a < P.count; a = a + P.stride) {
|
|
15
|
+
var lo = 0u; // the row w with rowPtr[w] <= a < rowPtr[w + 1]
|
|
16
|
+
var hi = P.n;
|
|
17
|
+
loop {
|
|
18
|
+
if (lo >= hi) { break; }
|
|
19
|
+
let mid = (lo + hi) / 2u;
|
|
20
|
+
if (rowPtr[mid + 1u] <= a) { lo = mid + 1u; } else { hi = mid; }
|
|
21
|
+
}
|
|
22
|
+
let w = lo;
|
|
23
|
+
let nbr = colIdx[a];
|
|
24
|
+
var acc = arcScores[a];
|
|
25
|
+
for (var s = 0u; s < P.k; s = s + 1u) {
|
|
26
|
+
let base = s * P.n;
|
|
27
|
+
let dw = depthK[base + w];
|
|
28
|
+
if (dw != INVALID_INDEX && depthK[base + nbr] == dw + 1u) { // (w, nbr) is on a shortest path from s
|
|
29
|
+
acc = acc + (f32(sigmaK[base + w]) / f32(sigmaK[base + nbr])) * (1.0 + deltaK[base + nbr]);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
arcScores[a] = acc;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
//# sourceMappingURL=bc-edge-gather.wgsl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bc-edge-gather.wgsl.js","sourceRoot":"","sources":["../../../src/wgsl/bc-edge-gather.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;CAwB1C,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `bc-finalize` kernel body (design 8.4, 5.4): the one-lane bookkeeping of a betweenness source batch, two roles
|
|
3
|
+
* by `P.role`. The batch keeps ONE append-only claim log `S` -- every `(vertex, source)` pair the forward pass
|
|
4
|
+
* claims, packed as the index `s * n + v` into the `n x k` arrays -- and `ends`, the level boundaries into it: the
|
|
5
|
+
* entries at depth `L` are `S[ends[L] .. ends[L + 1])`. That log is Brandes' stack, so the backward pass walks the
|
|
6
|
+
* same ranges from the deepest level up and nothing is ever copied between levels.
|
|
7
|
+
*
|
|
8
|
+
* Role 1 seeds the batch: the k seed entries the host wrote into `S[0 .. k)` get depth 0 and one shortest path,
|
|
9
|
+
* `ends[0] = 0`, the append cursor `stackTop` (counters word 26) starts at k, the overflow flag (word 27) is cleared,
|
|
10
|
+
* `level` (word 11) is U32_MAX so the first boundary lands on 0, and `done` (word 15) is cleared.
|
|
11
|
+
*
|
|
12
|
+
* Role 0 is the level boundary, recorded before every forward level: it advances `level`, closes the level just
|
|
13
|
+
* claimed by writing `ends[level + 1] = stackTop`, publishes the new level's size in `frontierCount` (word 0) and sets
|
|
14
|
+
* `done` when that level is empty. A boundary that finds `done` set moves nothing, so the levels the host records
|
|
15
|
+
* past the end are no-ops. The forward kernels dispatch directly and read their range from `ends` (no indirect
|
|
16
|
+
* dispatch: design/decisions/2026-09-25-frontier-kernels-dispatch-directly.md). One lane; no barrier follows the
|
|
17
|
+
* early return of the others (spec 3.5 rule 1). Body only; the sabotage rows of test/helpers/sabotage.ts are
|
|
18
|
+
* textual edits of it.
|
|
19
|
+
*/
|
|
20
|
+
export declare const bcFinalizeWgsl = "\n@compute @workgroup_size(WG)\nfn bc_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {\n if (lid.x != 0u) { return; } // one lane; no barrier follows (3.5 rule 1)\n if (P.role == 1u) { // the seed of a batch\n for (var i = 0u; i < P.k; i = i + 1u) {\n let t = S[i];\n depthK[t] = 0u; // the source is at depth 0\n sigmaK[t] = 1u; // with one shortest path, itself\n }\n ends[0] = 0u;\n atomicStore(&counters[26], P.k); // stackTop: the seeds are the log's first k entries\n atomicStore(&counters[27], 0u); // sigmaOverflow\n atomicStore(&counters[11], U32_MAX); // level: the first boundary brings it to 0\n atomicStore(&counters[15], 0u); // done\n return;\n }\n if (atomicLoad(&counters[15]) != 0u) { return; } // done: a no-op level the host recorded past the end\n let level = atomicLoad(&counters[11]) + 1u;\n let top = atomicLoad(&counters[26]);\n ends[level + 1u] = top; // the level's entries end where the log ends now\n let count = top - ends[level];\n atomicStore(&counters[0], count); // frontierCount (the inspect seam reads it)\n atomicStore(&counters[11], level);\n atomicStore(&counters[15], select(0u, 1u, count == 0u)); // an empty level ends the batch\n}\n";
|
|
21
|
+
//# sourceMappingURL=bc-finalize.wgsl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bc-finalize.wgsl.d.ts","sourceRoot":"","sources":["../../../src/wgsl/bc-finalize.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,cAAc,+oDA0B1B,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `bc-finalize` kernel body (design 8.4, 5.4): the one-lane bookkeeping of a betweenness source batch, two roles
|
|
3
|
+
* by `P.role`. The batch keeps ONE append-only claim log `S` -- every `(vertex, source)` pair the forward pass
|
|
4
|
+
* claims, packed as the index `s * n + v` into the `n x k` arrays -- and `ends`, the level boundaries into it: the
|
|
5
|
+
* entries at depth `L` are `S[ends[L] .. ends[L + 1])`. That log is Brandes' stack, so the backward pass walks the
|
|
6
|
+
* same ranges from the deepest level up and nothing is ever copied between levels.
|
|
7
|
+
*
|
|
8
|
+
* Role 1 seeds the batch: the k seed entries the host wrote into `S[0 .. k)` get depth 0 and one shortest path,
|
|
9
|
+
* `ends[0] = 0`, the append cursor `stackTop` (counters word 26) starts at k, the overflow flag (word 27) is cleared,
|
|
10
|
+
* `level` (word 11) is U32_MAX so the first boundary lands on 0, and `done` (word 15) is cleared.
|
|
11
|
+
*
|
|
12
|
+
* Role 0 is the level boundary, recorded before every forward level: it advances `level`, closes the level just
|
|
13
|
+
* claimed by writing `ends[level + 1] = stackTop`, publishes the new level's size in `frontierCount` (word 0) and sets
|
|
14
|
+
* `done` when that level is empty. A boundary that finds `done` set moves nothing, so the levels the host records
|
|
15
|
+
* past the end are no-ops. The forward kernels dispatch directly and read their range from `ends` (no indirect
|
|
16
|
+
* dispatch: design/decisions/2026-09-25-frontier-kernels-dispatch-directly.md). One lane; no barrier follows the
|
|
17
|
+
* early return of the others (spec 3.5 rule 1). Body only; the sabotage rows of test/helpers/sabotage.ts are
|
|
18
|
+
* textual edits of it.
|
|
19
|
+
*/
|
|
20
|
+
export const bcFinalizeWgsl = /* wgsl */ `
|
|
21
|
+
@compute @workgroup_size(WG)
|
|
22
|
+
fn bc_finalize(@builtin(local_invocation_id) lid: vec3<u32>) {
|
|
23
|
+
if (lid.x != 0u) { return; } // one lane; no barrier follows (3.5 rule 1)
|
|
24
|
+
if (P.role == 1u) { // the seed of a batch
|
|
25
|
+
for (var i = 0u; i < P.k; i = i + 1u) {
|
|
26
|
+
let t = S[i];
|
|
27
|
+
depthK[t] = 0u; // the source is at depth 0
|
|
28
|
+
sigmaK[t] = 1u; // with one shortest path, itself
|
|
29
|
+
}
|
|
30
|
+
ends[0] = 0u;
|
|
31
|
+
atomicStore(&counters[26], P.k); // stackTop: the seeds are the log's first k entries
|
|
32
|
+
atomicStore(&counters[27], 0u); // sigmaOverflow
|
|
33
|
+
atomicStore(&counters[11], U32_MAX); // level: the first boundary brings it to 0
|
|
34
|
+
atomicStore(&counters[15], 0u); // done
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (atomicLoad(&counters[15]) != 0u) { return; } // done: a no-op level the host recorded past the end
|
|
38
|
+
let level = atomicLoad(&counters[11]) + 1u;
|
|
39
|
+
let top = atomicLoad(&counters[26]);
|
|
40
|
+
ends[level + 1u] = top; // the level's entries end where the log ends now
|
|
41
|
+
let count = top - ends[level];
|
|
42
|
+
atomicStore(&counters[0], count); // frontierCount (the inspect seam reads it)
|
|
43
|
+
atomicStore(&counters[11], level);
|
|
44
|
+
atomicStore(&counters[15], select(0u, 1u, count == 0u)); // an empty level ends the batch
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
//# sourceMappingURL=bc-finalize.wgsl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bc-finalize.wgsl.js","sourceRoot":"","sources":["../../../src/wgsl/bc-finalize.wgsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BxC,CAAC"}
|