@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,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The simple symmetric graph (the P11 plan's PD-4): triangle counting and label propagation are defined over an
|
|
3
|
+
* undirected graph with no parallel edges and no self-loops, and a snapshot may be directed, may carry parallel
|
|
4
|
+
* edges and may carry self-loops. This builds that graph on the device from the snapshot's edge list:
|
|
5
|
+
*
|
|
6
|
+
* 1. `coo-emit` writes two arcs per logical edge -- the edge as declared and its reverse -- and drops a self-loop
|
|
7
|
+
* by writing both of its arcs as `INVALID_INDEX`, which sorts last.
|
|
8
|
+
* 2. Two stable radix sorts order the arcs by (source, target): by target first, then by source, the second sort's
|
|
9
|
+
* stability keeping the first's order among equal sources. Between and after them `coo-emit` re-reads the edge
|
|
10
|
+
* list through the sorted permutation (INDEXED), so no gather kernel is needed.
|
|
11
|
+
* 3. `run-flags` marks the first arc of every run of equal pairs; the scan of the flags counts the runs, which is
|
|
12
|
+
* the number of distinct arcs `U` -- read back once, because every later size depends on it.
|
|
13
|
+
* 4. Three `compact`s keep the first arc of every run (its source, its target and its position), and a segmented
|
|
14
|
+
* sum over the runs merges the weights of parallel arcs in input order (so the merged weight is bitwise
|
|
15
|
+
* reproducible).
|
|
16
|
+
* 5. `cooToCsr` in its sorted-input mode builds the rows, which come out sorted by target.
|
|
17
|
+
*
|
|
18
|
+
* The first submit ends at step 3; steps 4 and 5 are recorded into a batch that is RETURNED OPEN, so the caller
|
|
19
|
+
* records its own first work into the same submit and saves a synchronisation. The caller must check the
|
|
20
|
+
* precondition flag of `cooToCsr` with `assertBuildSorted` after that submit.
|
|
21
|
+
*
|
|
22
|
+
* Every intermediate array is `2 x edgeCount` words and is bound whole, so a snapshot whose arcs exceed one storage
|
|
23
|
+
* binding is refused with `E_TOO_LARGE` before any upload. A weighted build refuses, with `E_UNSUPPORTED`, a pair
|
|
24
|
+
* joined by more than PARALLEL_MERGE_LIMIT parallel edges (see the constant).
|
|
25
|
+
*
|
|
26
|
+
* ponytail: about nine of the arrays are alive at the peak (72 bytes per logical edge); reuse buffers across the
|
|
27
|
+
* steps if a 1M-node / 10M-edge build needs the room.
|
|
28
|
+
*/
|
|
29
|
+
import { PARALLEL_MERGE_LIMIT } from "../constants.js";
|
|
30
|
+
import { WebGpuGraphError } from "../errors.js";
|
|
31
|
+
import { CommandBatch } from "../kernel/batch.js";
|
|
32
|
+
import { plan1d } from "../kernel/dispatch.js";
|
|
33
|
+
import { COO_PARAMS, FILL_PARAMS, kernelSpec } from "../kernels.js";
|
|
34
|
+
import { prepareCompact } from "../primitives/compact.js";
|
|
35
|
+
import { prepareCooToCsr } from "../primitives/coo-to-csr.js";
|
|
36
|
+
import { prepareRadixSort, radixHistBytes } from "../primitives/radix-sort.js";
|
|
37
|
+
import { prepareScan } from "../primitives/scan.js";
|
|
38
|
+
import { prepareSegmentedReduce } from "../primitives/segmented-reduce.js";
|
|
39
|
+
/**
|
|
40
|
+
* The key width that orders node indices below `n` with `INVALID_INDEX` after all of them: the low `bits` of
|
|
41
|
+
* `INVALID_INDEX` are all ones, so every node index must stay below `2^bits - 1`.
|
|
42
|
+
* @param n - the node count
|
|
43
|
+
* @returns 8, 16, 24 or 32
|
|
44
|
+
*/
|
|
45
|
+
function sortBitsFor(n) {
|
|
46
|
+
for (const bits of [8, 16, 24]) {
|
|
47
|
+
if (n < 2 ** bits) {
|
|
48
|
+
return bits;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return 32;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A whole-binding view of a scratch buffer of `words` u32 (at least one word, so a binding is never zero-length).
|
|
55
|
+
* @param scope - the scope the buffer comes from
|
|
56
|
+
* @param words - the words
|
|
57
|
+
* @param label - the scratch label
|
|
58
|
+
* @returns the binding
|
|
59
|
+
*/
|
|
60
|
+
function scratchWords(scope, words, label) {
|
|
61
|
+
const size = 4 * Math.max(1, words);
|
|
62
|
+
return { buffer: scope.scratch(size, label), offset: 0, size, window: null };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Throws `E_TOO_LARGE` when a buffer the caller binds whole is larger than one storage binding of the device.
|
|
66
|
+
* @param ctx - the context whose limit applies
|
|
67
|
+
* @param needed - the bytes of the largest whole binding
|
|
68
|
+
* @param path - what does not fit
|
|
69
|
+
* @param algorithm - the algorithm, for the error
|
|
70
|
+
*/
|
|
71
|
+
export function assertBindable(ctx, needed, path, algorithm) {
|
|
72
|
+
const limit = ctx.caps.limits.maxStorageBufferBindingSize;
|
|
73
|
+
if (needed > limit) {
|
|
74
|
+
throw new WebGpuGraphError("E_TOO_LARGE", `${algorithm}: ${path} needs ${needed} bytes in one binding, above the device limit of ${limit}`, { needed, limit, path, algorithm });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Throws `E_UNSUPPORTED` when a weighted build would merge more than PARALLEL_MERGE_LIMIT parallel arcs into one: the
|
|
79
|
+
* edges joining one pair, in either direction. Only a pair of two vertices that each touch more than the limit can,
|
|
80
|
+
* so the exact count runs over those pairs alone and costs nothing on an ordinary graph.
|
|
81
|
+
* @param n - the node count
|
|
82
|
+
* @param src - the edge sources
|
|
83
|
+
* @param dst - the edge targets
|
|
84
|
+
* @param algorithm - the algorithm, for the error
|
|
85
|
+
*/
|
|
86
|
+
function assertMergeable(n, src, dst, algorithm) {
|
|
87
|
+
const incident = new Uint32Array(n);
|
|
88
|
+
for (let e = 0; e < src.length; e++) {
|
|
89
|
+
if (src[e] !== dst[e]) {
|
|
90
|
+
incident[src[e]]++;
|
|
91
|
+
incident[dst[e]]++;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const heavy = new Map();
|
|
95
|
+
for (let v = 0; v < n; v++) {
|
|
96
|
+
if (incident[v] > PARALLEL_MERGE_LIMIT) {
|
|
97
|
+
heavy.set(v, heavy.size);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (heavy.size < 2) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const pairs = new Uint32Array(heavy.size * heavy.size);
|
|
104
|
+
for (let e = 0; e < src.length; e++) {
|
|
105
|
+
const a = heavy.get(src[e]);
|
|
106
|
+
const b = heavy.get(dst[e]);
|
|
107
|
+
if (a === undefined || b === undefined || a === b) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const key = Math.min(a, b) * heavy.size + Math.max(a, b);
|
|
111
|
+
if (++pairs[key] > PARALLEL_MERGE_LIMIT) {
|
|
112
|
+
throw new WebGpuGraphError("E_UNSUPPORTED", `${algorithm}: nodes ${src[e]} and ${dst[e]} are joined by more than ${PARALLEL_MERGE_LIMIT} parallel edges, more than one weighted merge sums`, { feature: `${algorithm}.parallelEdges`, hint: "run it unweighted, or merge the parallel edges first" });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Throws `E_VALIDATION` when the device found the build's arcs out of source order, which would mean a bug in the
|
|
118
|
+
* sorts: the rows would be scrambled and every intersection over them wrong.
|
|
119
|
+
* @param bytes - the batch's readback bytes
|
|
120
|
+
* @param build - the build whose flag was read
|
|
121
|
+
* @param label - the algorithm, for the error
|
|
122
|
+
*/
|
|
123
|
+
export function assertBuildSorted(bytes, build, label) {
|
|
124
|
+
if (new Uint32Array(bytes, build.flag.offset, 1)[0] !== 0) {
|
|
125
|
+
throw new WebGpuGraphError("E_VALIDATION", `${label}: the simple graph's arcs reached cooToCsr out of order`, {
|
|
126
|
+
label: `${label}/simple-graph`,
|
|
127
|
+
message: "the sorted-input precondition of cooToCsr failed on the device",
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Builds the simple symmetric graph of `s` (see the file header): submits the first batch and waits for its
|
|
133
|
+
* four-byte readback, then records the rest into a batch it returns open.
|
|
134
|
+
* @param ctx - the context
|
|
135
|
+
* @param s - the snapshot (its edge list is uploaded through the residency, or found there)
|
|
136
|
+
* @param scope - the caller's scope: every buffer of the graph is its scratch
|
|
137
|
+
* @param withWeights - merge and keep the weights (label propagation) or not (triangle counting)
|
|
138
|
+
* @param label - the batch label prefix
|
|
139
|
+
* @returns the graph and the open batch
|
|
140
|
+
*/
|
|
141
|
+
export async function buildSimpleSymmetric(ctx, s, scope, withWeights, label) {
|
|
142
|
+
const n = s.nodeCount;
|
|
143
|
+
const wg = ctx.workgroupSize;
|
|
144
|
+
const cooToCsr = await prepareCooToCsr(scope);
|
|
145
|
+
const flag = scratchWords(scope, 1, "simple/flag");
|
|
146
|
+
const rowPtr = scratchWords(scope, n + 1, "simple/rowPtr");
|
|
147
|
+
const { edgeCount } = s;
|
|
148
|
+
const list = s.edgeList();
|
|
149
|
+
let selfLoops = 0;
|
|
150
|
+
for (let e = 0; e < edgeCount; e++) {
|
|
151
|
+
if (list.src[e] === list.dst[e]) {
|
|
152
|
+
selfLoops++;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const valid = 2 * (edgeCount - selfLoops);
|
|
156
|
+
const empty = () => {
|
|
157
|
+
const batch = new CommandBatch(ctx, `${label}/simple-graph`);
|
|
158
|
+
cooToCsr.record(batch.pass("simple-graph"), {
|
|
159
|
+
src: flag,
|
|
160
|
+
dst: flag,
|
|
161
|
+
weights: null,
|
|
162
|
+
count: 0,
|
|
163
|
+
n,
|
|
164
|
+
sortedInput: true,
|
|
165
|
+
out: { rowPtr, colIdx: flag, weights: null, flag },
|
|
166
|
+
});
|
|
167
|
+
batch.endPass();
|
|
168
|
+
const graph = { n, arcCount: 0, rowPtr, colIdx: null, weights: null, src: null };
|
|
169
|
+
return { graph, batch, flag: batch.readback(flag.buffer, 0, 4) };
|
|
170
|
+
};
|
|
171
|
+
if (valid === 0) {
|
|
172
|
+
return empty();
|
|
173
|
+
}
|
|
174
|
+
const arcs = 2 * edgeCount;
|
|
175
|
+
const tableBytes = Math.max(4, radixHistBytes(arcs, wg));
|
|
176
|
+
assertBindable(ctx, Math.max(4 * (arcs + 1), tableBytes), "the simple graph's arc arrays", label);
|
|
177
|
+
if (withWeights) {
|
|
178
|
+
assertMergeable(n, list.src, list.dst, label);
|
|
179
|
+
}
|
|
180
|
+
// core() is what records (or re-records, after a release) the snapshot in the residency; the build reads only
|
|
181
|
+
// the edge list, so it asks for rowPtr alone
|
|
182
|
+
ctx.residency.core(s, ["rowPtr"]);
|
|
183
|
+
const edges = ctx.residency.view(s, "edgeList");
|
|
184
|
+
const edgeWeights = edges.bindings.weights ?? null;
|
|
185
|
+
const emitPlan = plan1d(arcs, wg, ctx.caps);
|
|
186
|
+
const emit = new Map();
|
|
187
|
+
for (const indexed of [false, true]) {
|
|
188
|
+
const spec = kernelSpec("coo-emit", { INDEXED: indexed, WEIGHTED: edgeWeights !== null });
|
|
189
|
+
emit.set(indexed, await ctx.pipelines.kernel(spec));
|
|
190
|
+
}
|
|
191
|
+
const fill = await ctx.pipelines.kernel(kernelSpec("fill"));
|
|
192
|
+
const runFlags = await ctx.pipelines.kernel(kernelSpec("run-flags"));
|
|
193
|
+
const sort = await prepareRadixSort(scope);
|
|
194
|
+
const scan = await prepareScan(scope);
|
|
195
|
+
const compact = await prepareCompact(scope);
|
|
196
|
+
const aSrc = scratchWords(scope, arcs, "simple/aSrc");
|
|
197
|
+
const aDst = scratchWords(scope, arcs, "simple/aDst");
|
|
198
|
+
const aW = scratchWords(scope, arcs, "simple/aW");
|
|
199
|
+
const vals = scratchWords(scope, arcs, "simple/vals");
|
|
200
|
+
const sKeys = scratchWords(scope, arcs, "simple/sortKeys");
|
|
201
|
+
const sVals = scratchWords(scope, arcs, "simple/sortVals");
|
|
202
|
+
const hist = {
|
|
203
|
+
buffer: scope.scratch(tableBytes, "simple/hist"),
|
|
204
|
+
offset: 0,
|
|
205
|
+
size: tableBytes,
|
|
206
|
+
window: null,
|
|
207
|
+
};
|
|
208
|
+
const offsets = {
|
|
209
|
+
buffer: scope.scratch(tableBytes, "simple/offsets"),
|
|
210
|
+
offset: 0,
|
|
211
|
+
size: tableBytes,
|
|
212
|
+
window: null,
|
|
213
|
+
};
|
|
214
|
+
const sortedSrc = scratchWords(scope, arcs, "simple/sortedSrc");
|
|
215
|
+
const sortedDst = scratchWords(scope, arcs, "simple/sortedDst");
|
|
216
|
+
const sortedW = scratchWords(scope, arcs, "simple/sortedW");
|
|
217
|
+
const flags = scratchWords(scope, arcs, "simple/flags");
|
|
218
|
+
const runIndex = scratchWords(scope, arcs, "simple/runIndex");
|
|
219
|
+
const dummy = scratchWords(scope, 1, "simple/dummy");
|
|
220
|
+
await ctx.allocator.check();
|
|
221
|
+
const recordEmit = (pass, order, out) => {
|
|
222
|
+
const kernel = emit.get(order !== null);
|
|
223
|
+
if (kernel === undefined) {
|
|
224
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", "buildSimpleSymmetric: no coo-emit variant", {
|
|
225
|
+
argument: "order",
|
|
226
|
+
value: order === null ? "null" : "present",
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
const params = scope.params(COO_PARAMS, { count: arcs, pad0: 0, pad1: 0, pad2: 0 });
|
|
230
|
+
const bound = kernel.bind({
|
|
231
|
+
edgeSrc: edges.bindings.src,
|
|
232
|
+
edgeDst: edges.bindings.dst,
|
|
233
|
+
edgeWeight: edgeWeights ?? edges.bindings.src,
|
|
234
|
+
order: order ?? dummy,
|
|
235
|
+
outSrc: out[0],
|
|
236
|
+
outDst: out[1],
|
|
237
|
+
outWeight: out[2],
|
|
238
|
+
P: params.binding,
|
|
239
|
+
});
|
|
240
|
+
kernel.dispatch(pass, bound, emitPlan, [params.offset]);
|
|
241
|
+
};
|
|
242
|
+
const recordIota = (pass, dst, words) => {
|
|
243
|
+
const params = scope.params(FILL_PARAMS, { count: words, value: 0, mode: 1, pad0: 0 });
|
|
244
|
+
fill.dispatch(pass, fill.bind({ dst, P: params.binding }), plan1d(words, wg, ctx.caps), [params.offset]);
|
|
245
|
+
};
|
|
246
|
+
// batch 1: emit, sort by target, re-emit in that order, sort by source, re-emit sorted, flag the runs, count them
|
|
247
|
+
const bits = sortBitsFor(n);
|
|
248
|
+
const first = new CommandBatch(ctx, `${label}/simple-sort`);
|
|
249
|
+
const pass = first.pass("simple-sort");
|
|
250
|
+
recordEmit(pass, null, [aSrc, aDst, aW]);
|
|
251
|
+
recordIota(pass, vals, arcs);
|
|
252
|
+
const byTarget = sort.record(pass, aDst, vals, arcs, bits, { keys: sKeys, vals: sVals, hist, offsets });
|
|
253
|
+
recordEmit(pass, byTarget.vals, [aSrc, aDst, aW]);
|
|
254
|
+
const free = byTarget.vals.buffer === vals.buffer ? sVals : vals;
|
|
255
|
+
const bySource = sort.record(pass, aSrc, byTarget.vals, arcs, bits, {
|
|
256
|
+
keys: byTarget.keys.buffer === aDst.buffer ? sKeys : aDst,
|
|
257
|
+
vals: free,
|
|
258
|
+
hist,
|
|
259
|
+
offsets,
|
|
260
|
+
});
|
|
261
|
+
recordEmit(pass, bySource.vals, [sortedSrc, sortedDst, sortedW]);
|
|
262
|
+
const params = scope.params(COO_PARAMS, { count: arcs, pad0: 0, pad1: 0, pad2: 0 });
|
|
263
|
+
runFlags.dispatch(pass, runFlags.bind({ keysA: sortedSrc, keysB: sortedDst, flags, P: params.binding }), emitPlan, [
|
|
264
|
+
params.offset,
|
|
265
|
+
]);
|
|
266
|
+
const total = scan.record(pass, flags, arcs, runIndex);
|
|
267
|
+
first.endPass();
|
|
268
|
+
const totalRequest = first.readback(total.binding.buffer, total.binding.offset + 4 * total.index, 4);
|
|
269
|
+
scope.flush();
|
|
270
|
+
const back = await first.submit().readback;
|
|
271
|
+
ctx.assertReady();
|
|
272
|
+
const unique = new Uint32Array(back, totalRequest.offset, 1)[0];
|
|
273
|
+
if (unique === 0 || unique > valid) {
|
|
274
|
+
throw new WebGpuGraphError("E_VALIDATION", `${label}: ${unique} distinct arcs from ${valid} valid ones`, {
|
|
275
|
+
label: `${label}/simple-graph`,
|
|
276
|
+
message: "the run count of the simple graph build is outside [1, valid arcs]",
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
// batch 2 (returned open): keep the first arc of every run, merge the weights, build the rows
|
|
280
|
+
const uSrc = scratchWords(scope, arcs, "simple/src");
|
|
281
|
+
const uDst = scratchWords(scope, arcs, "simple/dst");
|
|
282
|
+
const runStart = scratchWords(scope, arcs + 1, "simple/runStart");
|
|
283
|
+
const counts = scratchWords(scope, 1, "simple/count");
|
|
284
|
+
const colIdx = scratchWords(scope, unique, "simple/colIdx");
|
|
285
|
+
const weights = withWeights ? scratchWords(scope, unique, "simple/weights") : null;
|
|
286
|
+
const merged = withWeights ? scratchWords(scope, unique, "simple/merged") : null;
|
|
287
|
+
// the terminator of the last run: every valid arc precedes the dropped ones, so the runs end at `valid`
|
|
288
|
+
ctx.device.queue.writeBuffer(runStart.buffer, 4 * unique, Uint32Array.of(valid));
|
|
289
|
+
const reduce = merged === null
|
|
290
|
+
? null
|
|
291
|
+
: await prepareSegmentedReduce(scope, runCore(runStart, unique, sortedDst, sortedW, valid), {
|
|
292
|
+
op: "sum",
|
|
293
|
+
valueSnippet: "v = weight;",
|
|
294
|
+
tiers: null,
|
|
295
|
+
});
|
|
296
|
+
const second = new CommandBatch(ctx, `${label}/simple-graph`);
|
|
297
|
+
const pass2 = second.pass("simple-graph");
|
|
298
|
+
const positions = vals;
|
|
299
|
+
recordIota(pass2, positions, arcs);
|
|
300
|
+
for (const [queue, out] of [
|
|
301
|
+
[sortedSrc, uSrc],
|
|
302
|
+
[sortedDst, uDst],
|
|
303
|
+
[positions, runStart],
|
|
304
|
+
]) {
|
|
305
|
+
compact.record(pass2, { queue, flags, count: arcs, out, outCount: counts, outIndex: 0 });
|
|
306
|
+
}
|
|
307
|
+
if (reduce !== null && merged !== null) {
|
|
308
|
+
reduce.record(pass2, runCore(runStart, unique, sortedDst, sortedW, valid), merged);
|
|
309
|
+
}
|
|
310
|
+
cooToCsr.record(pass2, {
|
|
311
|
+
src: uSrc,
|
|
312
|
+
dst: uDst,
|
|
313
|
+
weights: merged,
|
|
314
|
+
count: unique,
|
|
315
|
+
n,
|
|
316
|
+
sortedInput: true,
|
|
317
|
+
out: { rowPtr, colIdx, weights, flag },
|
|
318
|
+
});
|
|
319
|
+
second.endPass();
|
|
320
|
+
const graph = { n, arcCount: unique, rowPtr, colIdx, weights, src: uSrc };
|
|
321
|
+
return { graph, batch: second, flag: second.readback(flag.buffer, 0, 4) };
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* The runs as a CSR the segmented sum walks: row r is run r, its arcs the sorted positions `[runStart[r],
|
|
325
|
+
* runStart[r + 1])`, its weights the sorted weights, so a row's sum is the merged weight in input order.
|
|
326
|
+
* @param runStart - the run starts plus the terminator
|
|
327
|
+
* @param runs - the run count
|
|
328
|
+
* @param sortedDst - the sorted targets (the fold reads a neighbour it ignores)
|
|
329
|
+
* @param sortedW - the sorted weights
|
|
330
|
+
* @param valid - the arcs the runs cover
|
|
331
|
+
* @returns the core binding
|
|
332
|
+
*/
|
|
333
|
+
function runCore(runStart, runs, sortedDst, sortedW, valid) {
|
|
334
|
+
return {
|
|
335
|
+
serial: -1,
|
|
336
|
+
plan: "perArray",
|
|
337
|
+
rowPtr: { ...runStart, size: 4 * (runs + 1) },
|
|
338
|
+
colIdx: { ...sortedDst, size: 4 * valid },
|
|
339
|
+
weights: { ...sortedW, size: 4 * valid },
|
|
340
|
+
arcToEdge: null,
|
|
341
|
+
edgeToArc: null,
|
|
342
|
+
windows: null,
|
|
343
|
+
arcBuffers: null,
|
|
344
|
+
hasWeights: true,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=simple-symmetric.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simple-symmetric.js","sourceRoot":"","sources":["../../../src/algorithms/simple-symmetric.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Triangle counting with the local clustering coefficient and the transitivity (design 8.5, 3.3 line 806, design 17
|
|
3
|
+
* line 5067; the P11 plan's P11-T8). Over the simple symmetric graph of the snapshot (`buildSimpleSymmetric`, so a
|
|
4
|
+
* directed snapshot, parallel edges and self-loops all give the answer of the underlying simple undirected graph):
|
|
5
|
+
*
|
|
6
|
+
* 1. `orient-flags` keeps arc (u, v) when v is above u in the (degree, id) order, one arc per undirected edge;
|
|
7
|
+
* 2. two `compact`s keep the oriented arcs' sources and targets -- in order, so the oriented rows stay sorted -- and
|
|
8
|
+
* `cooToCsr` in its sorted-input mode builds the oriented rows (there are exactly `arcs / 2` of them, so no count
|
|
9
|
+
* is read back);
|
|
10
|
+
* 3. `tri-intersect` intersects the two oriented rows of every oriented arc and adds each triangle to the counts of
|
|
11
|
+
* its three vertices with u32 atomics -- exact, and independent of the schedule.
|
|
12
|
+
*
|
|
13
|
+
* All of it rides in the build's second submit, so a call is two synchronisations whatever the graph.
|
|
14
|
+
*
|
|
15
|
+
* PLAN DECISION (the P11 plan's DEP-P11-C): the coefficient and the transitivity are computed on the host from the
|
|
16
|
+
* per-node counts and the simple graph's `rowPtr`, both read back in the same submit, not by a `tri-coefficient`
|
|
17
|
+
* kernel. f32 division on the device is not correctly rounded (2.5 ULP on the reference card), and the transitivity's
|
|
18
|
+
* denominator -- the sum of `d (d - 1) / 2` -- overflows a u32 at a single node of degree 92,682; in f64 on the host
|
|
19
|
+
* both are exact to the f32 the result stores, and the `rowPtr` read costs the same bytes as the coefficient array a
|
|
20
|
+
* device epilogue would have read back instead.
|
|
21
|
+
*/
|
|
22
|
+
import { type GraphSnapshot } from "@graphty/graph-format";
|
|
23
|
+
import { type GpuContext } from "../context.js";
|
|
24
|
+
import { type GpuRunOptions } from "../types/run.js";
|
|
25
|
+
import { type GpuTriangleResult } from "../types/structure.js";
|
|
26
|
+
/**
|
|
27
|
+
* Counts the triangles of the simple undirected graph underlying `s` on the device (see the file header).
|
|
28
|
+
* @param ctx - the context whose device runs the kernels
|
|
29
|
+
* @param s - the snapshot (its edge list is uploaded through ctx.residency, or found there)
|
|
30
|
+
* @param options - dest (the per-node counts), signal, onProgress
|
|
31
|
+
* @returns the per-node counts, the total, the clustering coefficients and the transitivity
|
|
32
|
+
*/
|
|
33
|
+
export declare function triangleCount(ctx: GpuContext, s: GraphSnapshot, options?: GpuRunOptions): Promise<GpuTriangleResult>;
|
|
34
|
+
//# sourceMappingURL=triangles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triangles.d.ts","sourceRoot":"","sources":["../../../src/algorithms/triangles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAY,KAAK,aAAa,EAAY,MAAM,uBAAuB,CAAC;AAE/E,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAQhD,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAwD/D;;;;;;GAMG;AACH,wBAAsB,aAAa,CAC/B,GAAG,EAAE,UAAU,EACf,CAAC,EAAE,aAAa,EAChB,OAAO,CAAC,EAAE,aAAa,GACxB,OAAO,CAAC,iBAAiB,CAAC,CAE5B"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Triangle counting with the local clustering coefficient and the transitivity (design 8.5, 3.3 line 806, design 17
|
|
3
|
+
* line 5067; the P11 plan's P11-T8). Over the simple symmetric graph of the snapshot (`buildSimpleSymmetric`, so a
|
|
4
|
+
* directed snapshot, parallel edges and self-loops all give the answer of the underlying simple undirected graph):
|
|
5
|
+
*
|
|
6
|
+
* 1. `orient-flags` keeps arc (u, v) when v is above u in the (degree, id) order, one arc per undirected edge;
|
|
7
|
+
* 2. two `compact`s keep the oriented arcs' sources and targets -- in order, so the oriented rows stay sorted -- and
|
|
8
|
+
* `cooToCsr` in its sorted-input mode builds the oriented rows (there are exactly `arcs / 2` of them, so no count
|
|
9
|
+
* is read back);
|
|
10
|
+
* 3. `tri-intersect` intersects the two oriented rows of every oriented arc and adds each triangle to the counts of
|
|
11
|
+
* its three vertices with u32 atomics -- exact, and independent of the schedule.
|
|
12
|
+
*
|
|
13
|
+
* All of it rides in the build's second submit, so a call is two synchronisations whatever the graph.
|
|
14
|
+
*
|
|
15
|
+
* PLAN DECISION (the P11 plan's DEP-P11-C): the coefficient and the transitivity are computed on the host from the
|
|
16
|
+
* per-node counts and the simple graph's `rowPtr`, both read back in the same submit, not by a `tri-coefficient`
|
|
17
|
+
* kernel. f32 division on the device is not correctly rounded (2.5 ULP on the reference card), and the transitivity's
|
|
18
|
+
* denominator -- the sum of `d (d - 1) / 2` -- overflows a u32 at a single node of degree 92,682; in f64 on the host
|
|
19
|
+
* both are exact to the f32 the result stores, and the `rowPtr` read costs the same bytes as the coefficient array a
|
|
20
|
+
* device epilogue would have read back instead.
|
|
21
|
+
*/
|
|
22
|
+
import { WebGpuGraphError } from "../errors.js";
|
|
23
|
+
import { plan1d } from "../kernel/dispatch.js";
|
|
24
|
+
import { COO_PARAMS, FILL_PARAMS, kernelSpec } from "../kernels.js";
|
|
25
|
+
import { prepareCompact } from "../primitives/compact.js";
|
|
26
|
+
import { prepareCooToCsr } from "../primitives/coo-to-csr.js";
|
|
27
|
+
import { assertDeviceComputes } from "../primitives/verify.js";
|
|
28
|
+
import { algorithmScope } from "./scope.js";
|
|
29
|
+
import { assertBuildSorted, buildSimpleSymmetric } from "./simple-symmetric.js";
|
|
30
|
+
const ALGORITHM = "triangleCount";
|
|
31
|
+
/** Params slots of the largest batch: the build's two sorts and scans plus the orientation's compactions and build. */
|
|
32
|
+
const RING_SLOTS = 1024;
|
|
33
|
+
/**
|
|
34
|
+
* Validates `options.dest` for the per-node counts.
|
|
35
|
+
* @param dest - the caller's destination array, if any
|
|
36
|
+
* @param n - the node count
|
|
37
|
+
* @returns the destination as a U32, or null when none was given
|
|
38
|
+
*/
|
|
39
|
+
function checkDest(dest, n) {
|
|
40
|
+
if (dest === undefined) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
if (dest instanceof Uint32Array && dest.length === n && dest.buffer instanceof ArrayBuffer) {
|
|
44
|
+
return dest;
|
|
45
|
+
}
|
|
46
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${ALGORITHM}: dest must be a Uint32Array of length ${n} over an ArrayBuffer`, {
|
|
47
|
+
argument: "dest",
|
|
48
|
+
value: `${dest.constructor.name}(${dest.length})`,
|
|
49
|
+
expected: `Uint32Array(${n}) over an ArrayBuffer`,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The coefficient, the total and the transitivity from the per-node counts and the simple graph's rows, in f64.
|
|
54
|
+
* @param perNode - the triangles of every node
|
|
55
|
+
* @param rowPtr - the simple graph's `n + 1` row offsets
|
|
56
|
+
* @returns the result
|
|
57
|
+
*/
|
|
58
|
+
function epilogue(perNode, rowPtr) {
|
|
59
|
+
const n = perNode.length;
|
|
60
|
+
const coefficient = new Float32Array(n);
|
|
61
|
+
let sum = 0;
|
|
62
|
+
let triples = 0;
|
|
63
|
+
for (let v = 0; v < n; v++) {
|
|
64
|
+
const d = rowPtr[v + 1] - rowPtr[v];
|
|
65
|
+
const t = perNode[v];
|
|
66
|
+
sum += t;
|
|
67
|
+
if (d >= 2) {
|
|
68
|
+
const pairs = (d * (d - 1)) / 2;
|
|
69
|
+
triples += pairs;
|
|
70
|
+
coefficient[v] = t / pairs;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { perNode, total: sum / 3, coefficient, transitivity: triples === 0 ? 0 : sum / triples };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Counts the triangles of the simple undirected graph underlying `s` on the device (see the file header).
|
|
77
|
+
* @param ctx - the context whose device runs the kernels
|
|
78
|
+
* @param s - the snapshot (its edge list is uploaded through ctx.residency, or found there)
|
|
79
|
+
* @param options - dest (the per-node counts), signal, onProgress
|
|
80
|
+
* @returns the per-node counts, the total, the clustering coefficients and the transitivity
|
|
81
|
+
*/
|
|
82
|
+
export async function triangleCount(ctx, s, options) {
|
|
83
|
+
return await triangleCountWithSearch(ctx, s, 0, options);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* `triangleCount` with the intersection path forced (the tier-agreement tests' seam): 0 chooses per arc, 1 always
|
|
87
|
+
* merges, 2 always binary-searches.
|
|
88
|
+
* @internal
|
|
89
|
+
* @param ctx - the context
|
|
90
|
+
* @param s - the snapshot
|
|
91
|
+
* @param search - the `SEARCH` override of `tri-intersect`
|
|
92
|
+
* @param options - dest, signal, onProgress
|
|
93
|
+
* @returns the result
|
|
94
|
+
*/
|
|
95
|
+
export async function triangleCountWithSearch(ctx, s, search, options) {
|
|
96
|
+
ctx.assertReady();
|
|
97
|
+
await assertDeviceComputes(ctx);
|
|
98
|
+
const n = s.nodeCount;
|
|
99
|
+
const dest = checkDest(options?.dest, n);
|
|
100
|
+
if (options?.signal?.aborted) {
|
|
101
|
+
throw new WebGpuGraphError("E_ABORTED", `${ALGORITHM}: the signal was aborted before any work started`, {});
|
|
102
|
+
}
|
|
103
|
+
if (n === 0) {
|
|
104
|
+
options?.onProgress?.(1, 1);
|
|
105
|
+
return epilogue(dest ?? new Uint32Array(0), new Uint32Array(1));
|
|
106
|
+
}
|
|
107
|
+
const scope = algorithmScope(ctx, ALGORITHM, RING_SLOTS);
|
|
108
|
+
try {
|
|
109
|
+
const build = await buildSimpleSymmetric(ctx, s, scope, false, ALGORITHM);
|
|
110
|
+
const { graph, batch } = build;
|
|
111
|
+
const wg = ctx.workgroupSize;
|
|
112
|
+
const countsBytes = 4 * n;
|
|
113
|
+
const counts = {
|
|
114
|
+
buffer: scope.scratch(countsBytes, "counts"),
|
|
115
|
+
offset: 0,
|
|
116
|
+
size: countsBytes,
|
|
117
|
+
window: null,
|
|
118
|
+
};
|
|
119
|
+
const fill = await ctx.pipelines.kernel(kernelSpec("fill"));
|
|
120
|
+
const pass = batch.pass("triangles");
|
|
121
|
+
let orientedFlag = null;
|
|
122
|
+
const zero = scope.params(FILL_PARAMS, { count: n, value: 0, mode: 0, pad0: 0 });
|
|
123
|
+
fill.dispatch(pass, fill.bind({ dst: counts, P: zero.binding }), plan1d(n, wg, ctx.caps), [zero.offset]);
|
|
124
|
+
if (graph.arcCount > 0 && graph.colIdx !== null && graph.src !== null) {
|
|
125
|
+
const oriented = graph.arcCount / 2;
|
|
126
|
+
const orient = await ctx.pipelines.kernel(kernelSpec("orient-flags"));
|
|
127
|
+
const intersect = await ctx.pipelines.kernel(kernelSpec("tri-intersect", { SEARCH: search }));
|
|
128
|
+
const compact = await prepareCompact(scope);
|
|
129
|
+
const cooToCsr = await prepareCooToCsr(scope);
|
|
130
|
+
const words = (count, label) => ({
|
|
131
|
+
buffer: scope.scratch(4 * count, label),
|
|
132
|
+
offset: 0,
|
|
133
|
+
size: 4 * count,
|
|
134
|
+
window: null,
|
|
135
|
+
});
|
|
136
|
+
const flags = words(graph.arcCount, "orient/flags");
|
|
137
|
+
const oSrc = words(graph.arcCount, "orient/src");
|
|
138
|
+
const oDst = words(graph.arcCount, "orient/dst");
|
|
139
|
+
const oRowPtr = words(n + 1, "orient/rowPtr");
|
|
140
|
+
const oColIdx = words(oriented, "orient/colIdx");
|
|
141
|
+
const scratch = words(1, "orient/count");
|
|
142
|
+
const oFlag = words(1, "orient/flag");
|
|
143
|
+
const arcPlan = plan1d(graph.arcCount, wg, ctx.caps);
|
|
144
|
+
const p1 = scope.params(COO_PARAMS, { count: graph.arcCount, pad0: 0, pad1: 0, pad2: 0 });
|
|
145
|
+
orient.dispatch(pass, orient.bind({ rowPtr: graph.rowPtr, colIdx: graph.colIdx, src: graph.src, flags, P: p1.binding }), arcPlan, [p1.offset]);
|
|
146
|
+
compact.record(pass, {
|
|
147
|
+
queue: graph.src,
|
|
148
|
+
flags,
|
|
149
|
+
count: graph.arcCount,
|
|
150
|
+
out: oSrc,
|
|
151
|
+
outCount: scratch,
|
|
152
|
+
outIndex: 0,
|
|
153
|
+
});
|
|
154
|
+
compact.record(pass, {
|
|
155
|
+
queue: graph.colIdx,
|
|
156
|
+
flags,
|
|
157
|
+
count: graph.arcCount,
|
|
158
|
+
out: oDst,
|
|
159
|
+
outCount: scratch,
|
|
160
|
+
outIndex: 0,
|
|
161
|
+
});
|
|
162
|
+
cooToCsr.record(pass, {
|
|
163
|
+
src: oSrc,
|
|
164
|
+
dst: oDst,
|
|
165
|
+
weights: null,
|
|
166
|
+
count: oriented,
|
|
167
|
+
n,
|
|
168
|
+
sortedInput: true,
|
|
169
|
+
out: { rowPtr: oRowPtr, colIdx: oColIdx, weights: null, flag: oFlag },
|
|
170
|
+
});
|
|
171
|
+
orientedFlag = oFlag;
|
|
172
|
+
const p2 = scope.params(COO_PARAMS, { count: oriented, pad0: 0, pad1: 0, pad2: 0 });
|
|
173
|
+
intersect.dispatch(pass, intersect.bind({ rowPtr: oRowPtr, colIdx: oColIdx, src: oSrc, counts, P: p2.binding }), plan1d(oriented, wg, ctx.caps), [p2.offset]);
|
|
174
|
+
}
|
|
175
|
+
batch.endPass();
|
|
176
|
+
const countsRequest = batch.readback(counts.buffer, 0, countsBytes);
|
|
177
|
+
const rowsRequest = batch.readback(graph.rowPtr.buffer, 0, 4 * (n + 1));
|
|
178
|
+
const orientedRequest = orientedFlag === null ? null : batch.readback(orientedFlag.buffer, 0, 4);
|
|
179
|
+
scope.flush();
|
|
180
|
+
const submitted = batch.submit();
|
|
181
|
+
const bytes = await submitted.readback;
|
|
182
|
+
ctx.assertReady();
|
|
183
|
+
if (options?.signal?.aborted) {
|
|
184
|
+
throw new WebGpuGraphError("E_ABORTED", `${ALGORITHM}: the signal was aborted`, { batchId: submitted.id });
|
|
185
|
+
}
|
|
186
|
+
assertBuildSorted(bytes, build, ALGORITHM);
|
|
187
|
+
if (orientedRequest !== null && new Uint32Array(bytes, orientedRequest.offset, 1)[0] !== 0) {
|
|
188
|
+
throw new WebGpuGraphError("E_VALIDATION", `${ALGORITHM}: the oriented arcs reached cooToCsr out of order`, {
|
|
189
|
+
label: `${ALGORITHM}/oriented`,
|
|
190
|
+
message: "the sorted-input precondition of cooToCsr failed on the device",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
const perNode = dest ?? new Uint32Array(n);
|
|
194
|
+
perNode.set(new Uint32Array(bytes, countsRequest.offset, n));
|
|
195
|
+
const rowPtr = new Uint32Array(bytes, rowsRequest.offset, n + 1);
|
|
196
|
+
options?.onProgress?.(1, 1);
|
|
197
|
+
return epilogue(perNode, rowPtr);
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
scope.dispose();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=triangles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triangles.js","sourceRoot":"","sources":["../../../src/algorithms/triangles.ts"],"names":[],"mappings":"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"}
|