graphwise 1.9.1 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/dist/async/index.cjs +98 -1
  2. package/dist/async/index.cjs.map +1 -0
  3. package/dist/async/index.d.ts +1 -0
  4. package/dist/async/index.d.ts.map +1 -1
  5. package/dist/async/index.js +96 -2
  6. package/dist/async/index.js.map +1 -0
  7. package/dist/async/ops.d.ts +2 -0
  8. package/dist/async/ops.d.ts.map +1 -1
  9. package/dist/async/protocol.d.ts +14 -0
  10. package/dist/async/protocol.d.ts.map +1 -1
  11. package/dist/async/runner-batched.d.ts +21 -0
  12. package/dist/async/runner-batched.d.ts.map +1 -0
  13. package/dist/async/runner-batched.unit.test.d.ts +2 -0
  14. package/dist/async/runner-batched.unit.test.d.ts.map +1 -0
  15. package/dist/async/runners.d.ts.map +1 -1
  16. package/dist/expansion/base-core.d.ts.map +1 -1
  17. package/dist/expansion/fuse.d.ts +24 -1
  18. package/dist/expansion/fuse.d.ts.map +1 -1
  19. package/dist/expansion/index.cjs +9 -1
  20. package/dist/expansion/index.js +2 -2
  21. package/dist/expansion/lace.d.ts +23 -2
  22. package/dist/expansion/lace.d.ts.map +1 -1
  23. package/dist/expansion/priority-helpers.d.ts +20 -1
  24. package/dist/expansion/priority-helpers.d.ts.map +1 -1
  25. package/dist/expansion/sift.d.ts +24 -1
  26. package/dist/expansion/sift.d.ts.map +1 -1
  27. package/dist/expansion/types.d.ts +30 -0
  28. package/dist/expansion/types.d.ts.map +1 -1
  29. package/dist/{expansion-DaTroIyv.cjs → expansion--UuRowv-.cjs} +267 -4
  30. package/dist/expansion--UuRowv-.cjs.map +1 -0
  31. package/dist/{expansion-ClDhlMK8.js → expansion-CZLNK6Pr.js} +220 -5
  32. package/dist/expansion-CZLNK6Pr.js.map +1 -0
  33. package/dist/gpu/csr-graph.d.ts +68 -0
  34. package/dist/gpu/csr-graph.d.ts.map +1 -0
  35. package/dist/gpu/csr-graph.unit.test.d.ts +2 -0
  36. package/dist/gpu/csr-graph.unit.test.d.ts.map +1 -0
  37. package/dist/gpu/index.cjs +220 -15
  38. package/dist/gpu/index.cjs.map +1 -0
  39. package/dist/gpu/index.d.ts +1 -0
  40. package/dist/gpu/index.d.ts.map +1 -1
  41. package/dist/gpu/index.js +204 -2
  42. package/dist/gpu/index.js.map +1 -0
  43. package/dist/gpu/kernels/adamic-adar/kernel.d.ts +39 -0
  44. package/dist/gpu/kernels/adamic-adar/kernel.d.ts.map +1 -0
  45. package/dist/gpu/kernels/intersection/kernel.d.ts +50 -0
  46. package/dist/gpu/kernels/intersection/kernel.d.ts.map +1 -0
  47. package/dist/gpu/kernels/intersection/logic.d.ts +87 -0
  48. package/dist/gpu/kernels/intersection/logic.d.ts.map +1 -0
  49. package/dist/gpu/kernels/intersection/logic.unit.test.d.ts +2 -0
  50. package/dist/gpu/kernels/intersection/logic.unit.test.d.ts.map +1 -0
  51. package/dist/gpu/kernels/kmeans/index.d.ts +6 -0
  52. package/dist/gpu/kernels/kmeans/index.d.ts.map +1 -0
  53. package/dist/gpu/kernels/kmeans/kernel.d.ts +34 -0
  54. package/dist/gpu/kernels/kmeans/kernel.d.ts.map +1 -0
  55. package/dist/gpu/kernels/kmeans/logic.d.ts +111 -0
  56. package/dist/gpu/kernels/kmeans/logic.d.ts.map +1 -0
  57. package/dist/gpu/kernels/kmeans/logic.unit.test.d.ts +5 -0
  58. package/dist/gpu/kernels/kmeans/logic.unit.test.d.ts.map +1 -0
  59. package/dist/gpu/operations.d.ts +52 -0
  60. package/dist/gpu/operations.d.ts.map +1 -1
  61. package/dist/index/index.cjs +42 -19
  62. package/dist/index/index.js +11 -9
  63. package/dist/{jaccard-Bys9_dGW.cjs → jaccard-Bdw4B0i4.cjs} +1 -1
  64. package/dist/{jaccard-Bys9_dGW.cjs.map → jaccard-Bdw4B0i4.cjs.map} +1 -1
  65. package/dist/{jaccard-3rCdilwm.js → jaccard-BwC_NuQu.js} +1 -1
  66. package/dist/{jaccard-3rCdilwm.js.map → jaccard-BwC_NuQu.js.map} +1 -1
  67. package/dist/kernel-2oH4Cn32.cjs +1001 -0
  68. package/dist/kernel-2oH4Cn32.cjs.map +1 -0
  69. package/dist/kernel-6deK9fh1.js +724 -0
  70. package/dist/kernel-6deK9fh1.js.map +1 -0
  71. package/dist/kernel-CXeGBH3s.cjs +467 -0
  72. package/dist/kernel-CXeGBH3s.cjs.map +1 -0
  73. package/dist/kernel-CigCjrts.js +467 -0
  74. package/dist/kernel-CigCjrts.js.map +1 -0
  75. package/dist/kernel-CvnRsF7E.js +1001 -0
  76. package/dist/kernel-CvnRsF7E.js.map +1 -0
  77. package/dist/kernel-DukrXtVb.cjs +724 -0
  78. package/dist/kernel-DukrXtVb.cjs.map +1 -0
  79. package/dist/{kmeans-B8x9D1kt.cjs → kmeans-CZ7tJFYw.cjs} +1 -1
  80. package/dist/{kmeans-B8x9D1kt.cjs.map → kmeans-CZ7tJFYw.cjs.map} +1 -1
  81. package/dist/{kmeans-DKkL9rAN.js → kmeans-DLrlrp6i.js} +1 -1
  82. package/dist/{kmeans-DKkL9rAN.js.map → kmeans-DLrlrp6i.js.map} +1 -1
  83. package/dist/logic-Dbyfb_-7.cjs +289 -0
  84. package/dist/logic-Dbyfb_-7.cjs.map +1 -0
  85. package/dist/logic-DyBzRg1A.js +242 -0
  86. package/dist/logic-DyBzRg1A.js.map +1 -0
  87. package/dist/operations-D-RB67WP.cjs +2269 -0
  88. package/dist/operations-D-RB67WP.cjs.map +1 -0
  89. package/dist/operations-D9otVlIH.js +2198 -0
  90. package/dist/operations-D9otVlIH.js.map +1 -0
  91. package/dist/{ops-upIi6JIi.js → ops-D5xZr4fV.js} +60 -2
  92. package/dist/ops-D5xZr4fV.js.map +1 -0
  93. package/dist/{ops-djAsQQSh.cjs → ops-paa1Nvlf.cjs} +71 -1
  94. package/dist/ops-paa1Nvlf.cjs.map +1 -0
  95. package/dist/ranking/baselines/communicability.d.ts +12 -0
  96. package/dist/ranking/baselines/communicability.d.ts.map +1 -1
  97. package/dist/ranking/baselines/katz.d.ts +12 -0
  98. package/dist/ranking/baselines/katz.d.ts.map +1 -1
  99. package/dist/ranking/baselines/pagerank.d.ts +15 -0
  100. package/dist/ranking/baselines/pagerank.d.ts.map +1 -1
  101. package/dist/ranking/baselines/types.d.ts +3 -0
  102. package/dist/ranking/baselines/types.d.ts.map +1 -1
  103. package/dist/ranking/index.cjs +5 -2
  104. package/dist/ranking/index.js +3 -3
  105. package/dist/ranking/mi/index.cjs +1 -1
  106. package/dist/ranking/mi/index.js +1 -1
  107. package/dist/ranking/parse-gpu.d.ts +31 -0
  108. package/dist/ranking/parse-gpu.d.ts.map +1 -0
  109. package/dist/ranking/parse-gpu.unit.test.d.ts +5 -0
  110. package/dist/ranking/parse-gpu.unit.test.d.ts.map +1 -0
  111. package/dist/ranking/parse.d.ts.map +1 -1
  112. package/dist/{ranking-3ez5m67U.js → ranking-DOKDBcIR.js} +237 -11
  113. package/dist/ranking-DOKDBcIR.js.map +1 -0
  114. package/dist/{ranking-DVvajgUZ.cjs → ranking-pe5UaxKg.cjs} +254 -10
  115. package/dist/ranking-pe5UaxKg.cjs.map +1 -0
  116. package/dist/schemas/graph.d.ts +1 -1
  117. package/dist/seeds/crest.d.ts +48 -0
  118. package/dist/seeds/crest.d.ts.map +1 -0
  119. package/dist/seeds/crest.unit.test.d.ts +2 -0
  120. package/dist/seeds/crest.unit.test.d.ts.map +1 -0
  121. package/dist/seeds/crisp.d.ts +57 -0
  122. package/dist/seeds/crisp.d.ts.map +1 -0
  123. package/dist/seeds/crisp.unit.test.d.ts +2 -0
  124. package/dist/seeds/crisp.unit.test.d.ts.map +1 -0
  125. package/dist/seeds/grasp-gpu.d.ts +40 -0
  126. package/dist/seeds/grasp-gpu.d.ts.map +1 -0
  127. package/dist/seeds/index.cjs +715 -5
  128. package/dist/seeds/index.cjs.map +1 -1
  129. package/dist/seeds/index.d.ts +4 -0
  130. package/dist/seeds/index.d.ts.map +1 -1
  131. package/dist/seeds/index.js +712 -6
  132. package/dist/seeds/index.js.map +1 -1
  133. package/dist/seeds/spine.d.ts +50 -0
  134. package/dist/seeds/spine.d.ts.map +1 -0
  135. package/dist/seeds/spine.unit.test.d.ts +2 -0
  136. package/dist/seeds/spine.unit.test.d.ts.map +1 -0
  137. package/dist/seeds/stride.d.ts +55 -0
  138. package/dist/seeds/stride.d.ts.map +1 -0
  139. package/dist/seeds/stride.unit.test.d.ts +2 -0
  140. package/dist/seeds/stride.unit.test.d.ts.map +1 -0
  141. package/dist/{gpu-CHiCN0wa.js → typegpu-Dq5FfUB8.cjs} +16 -2041
  142. package/dist/typegpu-Dq5FfUB8.cjs.map +1 -0
  143. package/dist/{gpu-Y6owRVMi.cjs → typegpu-DwnJf28i.js} +2 -2127
  144. package/dist/typegpu-DwnJf28i.js.map +1 -0
  145. package/dist/utils/index.cjs +1 -1
  146. package/dist/utils/index.js +1 -1
  147. package/package.json +1 -1
  148. package/dist/expansion-ClDhlMK8.js.map +0 -1
  149. package/dist/expansion-DaTroIyv.cjs.map +0 -1
  150. package/dist/gpu-CHiCN0wa.js.map +0 -1
  151. package/dist/gpu-Y6owRVMi.cjs.map +0 -1
  152. package/dist/ops-djAsQQSh.cjs.map +0 -1
  153. package/dist/ops-upIi6JIi.js.map +0 -1
  154. package/dist/ranking-3ez5m67U.js.map +0 -1
  155. package/dist/ranking-DVvajgUZ.cjs.map +0 -1
@@ -0,0 +1,2198 @@
1
+ import { n as data_exports, t as src_default } from "./typegpu-DwnJf28i.js";
2
+ import { a as overlapFromIntersection, c as graphToCSR, i as jaccardFromIntersection, n as hubPromotedFromIntersection, o as sorensenDiceFromIntersection, r as intersectionBatch, s as csrToTypedBuffers, t as cosineFromIntersection } from "./logic-DyBzRg1A.js";
3
+ //#region src/gpu/detect.ts
4
+ /**
5
+ * Detect WebGPU availability in the current environment.
6
+ *
7
+ * Checks for:
8
+ * - Browser: navigator.gpu
9
+ * - Node.js: global GPU constructor (Node.js 21+ with --experimental-webgpu)
10
+ * - Deno: global GPU constructor
11
+ *
12
+ * @returns Detection result with availability status and reason
13
+ */
14
+ function detectWebGPU() {
15
+ if (typeof navigator !== "undefined" && "gpu" in navigator) return { available: true };
16
+ if (typeof globalThis !== "undefined" && "GPU" in globalThis) return { available: true };
17
+ const reasons = [];
18
+ if (typeof navigator === "undefined" && typeof globalThis === "undefined") reasons.push("no global scope detected");
19
+ else if (typeof navigator !== "undefined" && !("gpu" in navigator)) reasons.push("navigator.gpu not present (browser may not support WebGPU)");
20
+ else if (typeof globalThis !== "undefined" && !("GPU" in globalThis)) reasons.push("global GPU not present (Node.js requires v21+ with --experimental-webgpu flag)");
21
+ return {
22
+ available: false,
23
+ reason: reasons.length > 0 ? reasons.join("; ") : "unknown environment"
24
+ };
25
+ }
26
+ /**
27
+ * Check if WebGPU is available (convenience function).
28
+ *
29
+ * @returns true if WebGPU is available, false otherwise
30
+ */
31
+ function isWebGPUAvailable() {
32
+ return detectWebGPU().available;
33
+ }
34
+ /**
35
+ * Assert that WebGPU is available, throwing an error if not.
36
+ *
37
+ * @throws Error if WebGPU is not available
38
+ */
39
+ function assertWebGPUAvailable() {
40
+ const result = detectWebGPU();
41
+ if (!result.available) throw new Error(`WebGPU required but not available: ${result.reason ?? "unknown reason"}`);
42
+ }
43
+ //#endregion
44
+ //#region src/gpu/types.ts
45
+ /**
46
+ * Error thrown when GPU backend is requested but unavailable.
47
+ */
48
+ var GPUNotAvailableError = class extends Error {
49
+ constructor(reason) {
50
+ super(`WebGPU not available: ${reason}`);
51
+ this.name = "GPUNotAvailableError";
52
+ }
53
+ };
54
+ //#endregion
55
+ //#region src/gpu/dispatch.ts
56
+ /**
57
+ * Backend selection and dispatch utilities for GPU compute operations.
58
+ *
59
+ * Provides the `withBackend` function that handles auto/gpu/cpu backend
60
+ * selection with timing and fallback logic.
61
+ *
62
+ * @module gpu/dispatch
63
+ */
64
+ /**
65
+ * Execute a compute operation with automatic backend selection.
66
+ *
67
+ * @param options - Backend selection and cancellation options
68
+ * @param cpuFn - CPU fallback implementation
69
+ * @param gpuFn - GPU implementation (receives TypeGPU root)
70
+ * @returns Compute result with backend used and timing
71
+ */
72
+ async function withBackend(options, cpuFn, gpuFn) {
73
+ const backend = options.backend ?? "auto";
74
+ if (options.signal?.aborted === true) throw new DOMException("Operation aborted", "AbortError");
75
+ if (backend === "cpu") {
76
+ const start = performance.now();
77
+ return {
78
+ value: cpuFn(),
79
+ backend: "cpu",
80
+ elapsedMs: performance.now() - start
81
+ };
82
+ }
83
+ if (backend === "gpu") {
84
+ const detection = detectWebGPU();
85
+ if (!detection.available) throw new GPUNotAvailableError(detection.reason ?? "Unknown reason");
86
+ const root = options.root;
87
+ if (root === void 0) throw new Error("GPU backend requires a GraphwiseGPURoot. Pass one via options.root or use backend: 'auto'.");
88
+ const start = performance.now();
89
+ return {
90
+ value: await gpuFn(root),
91
+ backend: "gpu",
92
+ elapsedMs: performance.now() - start
93
+ };
94
+ }
95
+ if (!detectWebGPU().available) {
96
+ const start = performance.now();
97
+ return {
98
+ value: cpuFn(),
99
+ backend: "cpu",
100
+ elapsedMs: performance.now() - start
101
+ };
102
+ }
103
+ const root = options.root;
104
+ if (root === void 0) {
105
+ const start = performance.now();
106
+ return {
107
+ value: cpuFn(),
108
+ backend: "cpu",
109
+ elapsedMs: performance.now() - start
110
+ };
111
+ }
112
+ const start = performance.now();
113
+ return {
114
+ value: await gpuFn(root),
115
+ backend: "gpu",
116
+ elapsedMs: performance.now() - start
117
+ };
118
+ }
119
+ //#endregion
120
+ //#region src/gpu/kernels/spmv/kernel.ts
121
+ /**
122
+ * TypeGPU compute kernel for Sparse Matrix-Vector Multiplication (SpMV).
123
+ *
124
+ * Computes y = A * x where A is a sparse matrix in CSR format.
125
+ * Uses TypeGPU's compute pipeline for parallel GPU execution.
126
+ *
127
+ * @module gpu/kernels/spmv/kernel
128
+ */
129
+ /**
130
+ * Bind group layout for SpMV kernel.
131
+ */
132
+ var SpMVLayout = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(src_default.bindGroupLayout({
133
+ rowOffsets: { storage: data_exports.arrayOf(data_exports.u32) },
134
+ colIndices: { storage: data_exports.arrayOf(data_exports.u32) },
135
+ values: { storage: data_exports.arrayOf(data_exports.f32) },
136
+ x: { storage: data_exports.arrayOf(data_exports.f32) },
137
+ y: {
138
+ storage: data_exports.arrayOf(data_exports.f32),
139
+ access: "mutable"
140
+ },
141
+ nodeCount: { uniform: data_exports.u32 },
142
+ hasValues: { uniform: data_exports.u32 }
143
+ }), "SpMVLayout");
144
+ /**
145
+ * SpMV compute pipeline: y[row] = sum(A[row,col] * x[col]).
146
+ *
147
+ * Each thread computes one row of the output vector using the CSR format:
148
+ * - rowOffsets: start/end indices for each row
149
+ * - colIndices: column index for each non-zero entry
150
+ * - values: edge weights (optional, defaults to 1.0)
151
+ */
152
+ var spmvPipeline = (($) => (globalThis.__TYPEGPU_META__ ??= /* @__PURE__ */ new WeakMap()).set($.f = ((row) => {
153
+ "use gpu";
154
+ const start = SpMVLayout.$.rowOffsets[row] ?? 0;
155
+ const end = SpMVLayout.$.rowOffsets[__tsover_add(row, 1)] ?? 0;
156
+ let sum = 0;
157
+ for (let i = start; i < end; i = __tsover_add(i, 1)) {
158
+ const col = SpMVLayout.$.colIndices[i] ?? 0;
159
+ const weight = SpMVLayout.$.hasValues !== 0 ? SpMVLayout.$.values[i] ?? 1 : 1;
160
+ sum = __tsover_add(sum, __tsover_mul(weight, SpMVLayout.$.x[col] ?? 0));
161
+ }
162
+ SpMVLayout.$.y[row] = sum;
163
+ }), {
164
+ v: 1,
165
+ name: "spmvPipeline",
166
+ ast: {
167
+ "params": [{
168
+ "type": "i",
169
+ "name": "row"
170
+ }],
171
+ "body": [0, [
172
+ [
173
+ 13,
174
+ "start",
175
+ [
176
+ 3,
177
+ [
178
+ 8,
179
+ [
180
+ 7,
181
+ [
182
+ 7,
183
+ "SpMVLayout",
184
+ "$"
185
+ ],
186
+ "rowOffsets"
187
+ ],
188
+ "row"
189
+ ],
190
+ "??",
191
+ [5, "0"]
192
+ ]
193
+ ],
194
+ [
195
+ 13,
196
+ "end",
197
+ [
198
+ 3,
199
+ [
200
+ 8,
201
+ [
202
+ 7,
203
+ [
204
+ 7,
205
+ "SpMVLayout",
206
+ "$"
207
+ ],
208
+ "rowOffsets"
209
+ ],
210
+ [
211
+ 1,
212
+ "row",
213
+ "+",
214
+ [5, "1"]
215
+ ]
216
+ ],
217
+ "??",
218
+ [5, "0"]
219
+ ]
220
+ ],
221
+ [
222
+ 12,
223
+ "sum",
224
+ [5, "0"]
225
+ ],
226
+ [
227
+ 14,
228
+ [
229
+ 12,
230
+ "i",
231
+ "start"
232
+ ],
233
+ [
234
+ 1,
235
+ "i",
236
+ "<",
237
+ "end"
238
+ ],
239
+ [
240
+ 2,
241
+ "i",
242
+ "=",
243
+ [
244
+ 1,
245
+ "i",
246
+ "+",
247
+ [5, "1"]
248
+ ]
249
+ ],
250
+ [0, [
251
+ [
252
+ 13,
253
+ "col",
254
+ [
255
+ 3,
256
+ [
257
+ 8,
258
+ [
259
+ 7,
260
+ [
261
+ 7,
262
+ "SpMVLayout",
263
+ "$"
264
+ ],
265
+ "colIndices"
266
+ ],
267
+ "i"
268
+ ],
269
+ "??",
270
+ [5, "0"]
271
+ ]
272
+ ],
273
+ [
274
+ 13,
275
+ "weight",
276
+ [
277
+ 105,
278
+ [
279
+ 1,
280
+ [
281
+ 7,
282
+ [
283
+ 7,
284
+ "SpMVLayout",
285
+ "$"
286
+ ],
287
+ "hasValues"
288
+ ],
289
+ "!==",
290
+ [5, "0"]
291
+ ],
292
+ [
293
+ 3,
294
+ [
295
+ 8,
296
+ [
297
+ 7,
298
+ [
299
+ 7,
300
+ "SpMVLayout",
301
+ "$"
302
+ ],
303
+ "values"
304
+ ],
305
+ "i"
306
+ ],
307
+ "??",
308
+ [5, "1"]
309
+ ],
310
+ [5, "1"]
311
+ ]
312
+ ],
313
+ [
314
+ 2,
315
+ "sum",
316
+ "=",
317
+ [
318
+ 1,
319
+ "sum",
320
+ "+",
321
+ [
322
+ 1,
323
+ "weight",
324
+ "*",
325
+ [
326
+ 3,
327
+ [
328
+ 8,
329
+ [
330
+ 7,
331
+ [
332
+ 7,
333
+ "SpMVLayout",
334
+ "$"
335
+ ],
336
+ "x"
337
+ ],
338
+ "col"
339
+ ],
340
+ "??",
341
+ [5, "0"]
342
+ ]
343
+ ]
344
+ ]
345
+ ]
346
+ ]]
347
+ ],
348
+ [
349
+ 2,
350
+ [
351
+ 8,
352
+ [
353
+ 7,
354
+ [
355
+ 7,
356
+ "SpMVLayout",
357
+ "$"
358
+ ],
359
+ "y"
360
+ ],
361
+ "row"
362
+ ],
363
+ "=",
364
+ "sum"
365
+ ]
366
+ ]],
367
+ "externalNames": ["SpMVLayout"]
368
+ },
369
+ externals: () => ({ SpMVLayout })
370
+ }) && $.f)({});
371
+ /**
372
+ * Dispatch SpMV on GPU.
373
+ *
374
+ * @param root - TypeGPU root instance
375
+ * @param csrBuffers - CSR matrix as typed buffers
376
+ * @param x - Input vector buffer
377
+ * @param y - Output vector buffer (mutable)
378
+ * @param nodeCount - Number of nodes/rows
379
+ * @param hasValues - Whether edge weights are present
380
+ */
381
+ function dispatchSpmv(root, csrBuffers, x, y, nodeCount, hasValues) {
382
+ const pipeline = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createGuardedComputePipeline(spmvPipeline), "pipeline");
383
+ const valuesBuffer = csrBuffers.values ?? root.createBuffer(data_exports.arrayOf(data_exports.f32, csrBuffers.edgeCount), new Array(csrBuffers.edgeCount).fill(1)).$usage("storage");
384
+ const nodeCountBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.u32, nodeCount).$usage("uniform"), "nodeCountBuffer");
385
+ const hasValuesBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.u32, hasValues ? 1 : 0).$usage("uniform"), "hasValuesBuffer");
386
+ const bindGroup = root.createBindGroup(SpMVLayout, {
387
+ rowOffsets: csrBuffers.rowOffsets,
388
+ colIndices: csrBuffers.colIndices,
389
+ values: valuesBuffer,
390
+ x,
391
+ y,
392
+ nodeCount: nodeCountBuffer,
393
+ hasValues: hasValuesBuffer
394
+ });
395
+ pipeline.with(bindGroup).dispatchThreads(nodeCount);
396
+ }
397
+ //#endregion
398
+ //#region src/gpu/kernels/pagerank/kernel.ts
399
+ /**
400
+ * TypeGPU compute kernel for PageRank power iteration.
401
+ *
402
+ * Computes one iteration of PageRank:
403
+ * r(v) = (1 - d)/N + d * sum(r(u) / deg_out(u)) for u -> v
404
+ *
405
+ * Uses TypeGPU's compute pipeline for parallel GPU execution.
406
+ *
407
+ * @module gpu/kernels/pagerank/kernel
408
+ */
409
+ /**
410
+ * Bind group layout for PageRank kernel.
411
+ */
412
+ var PageRankLayout = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(src_default.bindGroupLayout({
413
+ rowOffsets: { storage: data_exports.arrayOf(data_exports.u32) },
414
+ colIndices: { storage: data_exports.arrayOf(data_exports.u32) },
415
+ ranks: { storage: data_exports.arrayOf(data_exports.f32) },
416
+ outDegrees: { storage: data_exports.arrayOf(data_exports.u32) },
417
+ newRanks: {
418
+ storage: data_exports.arrayOf(data_exports.f32),
419
+ access: "mutable"
420
+ },
421
+ nodeCount: { uniform: data_exports.u32 },
422
+ damping: { uniform: data_exports.f32 }
423
+ }), "PageRankLayout");
424
+ /**
425
+ * PageRank compute pipeline: one power iteration per dispatch.
426
+ *
427
+ * Each thread computes one node's new rank from incoming neighbours:
428
+ * newRank[v] = (1 - damping) / N + damping * sum(rank[u] / outDegree[u])
429
+ */
430
+ var pagerankPipeline = (($) => (globalThis.__TYPEGPU_META__ ??= /* @__PURE__ */ new WeakMap()).set($.f = ((node) => {
431
+ "use gpu";
432
+ const n = PageRankLayout.$.nodeCount ?? 0;
433
+ const damp = PageRankLayout.$.damping ?? .85;
434
+ const start = PageRankLayout.$.rowOffsets[node] ?? 0;
435
+ const end = PageRankLayout.$.rowOffsets[__tsover_add(node, 1)] ?? 0;
436
+ let contribution = 0;
437
+ for (let i = start; i < end; i = __tsover_add(i, 1)) {
438
+ const source = PageRankLayout.$.colIndices[i] ?? 0;
439
+ const deg = PageRankLayout.$.outDegrees[source] ?? 0;
440
+ if (deg > 0) {
441
+ const rank = PageRankLayout.$.ranks[source] ?? 0;
442
+ contribution = __tsover_add(contribution, __tsover_div(rank, deg));
443
+ }
444
+ }
445
+ const teleport = __tsover_div(__tsover_sub(1, damp), n);
446
+ PageRankLayout.$.newRanks[node] = __tsover_add(teleport, __tsover_mul(damp, contribution));
447
+ }), {
448
+ v: 1,
449
+ name: "pagerankPipeline",
450
+ ast: {
451
+ "params": [{
452
+ "type": "i",
453
+ "name": "node"
454
+ }],
455
+ "body": [0, [
456
+ [
457
+ 13,
458
+ "n",
459
+ [
460
+ 3,
461
+ [
462
+ 7,
463
+ [
464
+ 7,
465
+ "PageRankLayout",
466
+ "$"
467
+ ],
468
+ "nodeCount"
469
+ ],
470
+ "??",
471
+ [5, "0"]
472
+ ]
473
+ ],
474
+ [
475
+ 13,
476
+ "damp",
477
+ [
478
+ 3,
479
+ [
480
+ 7,
481
+ [
482
+ 7,
483
+ "PageRankLayout",
484
+ "$"
485
+ ],
486
+ "damping"
487
+ ],
488
+ "??",
489
+ [5, "0.85"]
490
+ ]
491
+ ],
492
+ [
493
+ 13,
494
+ "start",
495
+ [
496
+ 3,
497
+ [
498
+ 8,
499
+ [
500
+ 7,
501
+ [
502
+ 7,
503
+ "PageRankLayout",
504
+ "$"
505
+ ],
506
+ "rowOffsets"
507
+ ],
508
+ "node"
509
+ ],
510
+ "??",
511
+ [5, "0"]
512
+ ]
513
+ ],
514
+ [
515
+ 13,
516
+ "end",
517
+ [
518
+ 3,
519
+ [
520
+ 8,
521
+ [
522
+ 7,
523
+ [
524
+ 7,
525
+ "PageRankLayout",
526
+ "$"
527
+ ],
528
+ "rowOffsets"
529
+ ],
530
+ [
531
+ 1,
532
+ "node",
533
+ "+",
534
+ [5, "1"]
535
+ ]
536
+ ],
537
+ "??",
538
+ [5, "0"]
539
+ ]
540
+ ],
541
+ [
542
+ 12,
543
+ "contribution",
544
+ [5, "0"]
545
+ ],
546
+ [
547
+ 14,
548
+ [
549
+ 12,
550
+ "i",
551
+ "start"
552
+ ],
553
+ [
554
+ 1,
555
+ "i",
556
+ "<",
557
+ "end"
558
+ ],
559
+ [
560
+ 2,
561
+ "i",
562
+ "=",
563
+ [
564
+ 1,
565
+ "i",
566
+ "+",
567
+ [5, "1"]
568
+ ]
569
+ ],
570
+ [0, [
571
+ [
572
+ 13,
573
+ "source",
574
+ [
575
+ 3,
576
+ [
577
+ 8,
578
+ [
579
+ 7,
580
+ [
581
+ 7,
582
+ "PageRankLayout",
583
+ "$"
584
+ ],
585
+ "colIndices"
586
+ ],
587
+ "i"
588
+ ],
589
+ "??",
590
+ [5, "0"]
591
+ ]
592
+ ],
593
+ [
594
+ 13,
595
+ "deg",
596
+ [
597
+ 3,
598
+ [
599
+ 8,
600
+ [
601
+ 7,
602
+ [
603
+ 7,
604
+ "PageRankLayout",
605
+ "$"
606
+ ],
607
+ "outDegrees"
608
+ ],
609
+ "source"
610
+ ],
611
+ "??",
612
+ [5, "0"]
613
+ ]
614
+ ],
615
+ [
616
+ 11,
617
+ [
618
+ 1,
619
+ "deg",
620
+ ">",
621
+ [5, "0"]
622
+ ],
623
+ [0, [[
624
+ 13,
625
+ "rank",
626
+ [
627
+ 3,
628
+ [
629
+ 8,
630
+ [
631
+ 7,
632
+ [
633
+ 7,
634
+ "PageRankLayout",
635
+ "$"
636
+ ],
637
+ "ranks"
638
+ ],
639
+ "source"
640
+ ],
641
+ "??",
642
+ [5, "0"]
643
+ ]
644
+ ], [
645
+ 2,
646
+ "contribution",
647
+ "=",
648
+ [
649
+ 1,
650
+ "contribution",
651
+ "+",
652
+ [
653
+ 1,
654
+ "rank",
655
+ "/",
656
+ "deg"
657
+ ]
658
+ ]
659
+ ]]]
660
+ ]
661
+ ]]
662
+ ],
663
+ [
664
+ 13,
665
+ "teleport",
666
+ [
667
+ 1,
668
+ [
669
+ 1,
670
+ [5, "1"],
671
+ "-",
672
+ "damp"
673
+ ],
674
+ "/",
675
+ "n"
676
+ ]
677
+ ],
678
+ [
679
+ 2,
680
+ [
681
+ 8,
682
+ [
683
+ 7,
684
+ [
685
+ 7,
686
+ "PageRankLayout",
687
+ "$"
688
+ ],
689
+ "newRanks"
690
+ ],
691
+ "node"
692
+ ],
693
+ "=",
694
+ [
695
+ 1,
696
+ "teleport",
697
+ "+",
698
+ [
699
+ 1,
700
+ "damp",
701
+ "*",
702
+ "contribution"
703
+ ]
704
+ ]
705
+ ]
706
+ ]],
707
+ "externalNames": ["PageRankLayout"]
708
+ },
709
+ externals: () => ({ PageRankLayout })
710
+ }) && $.f)({});
711
+ /**
712
+ * Dispatch one PageRank iteration on GPU.
713
+ *
714
+ * @param root - TypeGPU root instance
715
+ * @param csrBuffers - CSR matrix as typed buffers (transpose graph: in-edges)
716
+ * @param ranks - Current rank values buffer
717
+ * @param outDegrees - Out-degree buffer for each node
718
+ * @param newRanks - Output buffer for new rank values (mutable)
719
+ * @param nodeCount - Number of nodes
720
+ * @param damping - Damping factor (typically 0.85)
721
+ */
722
+ function dispatchPagerank(root, csrBuffers, ranks, outDegrees, newRanks, nodeCount, damping) {
723
+ const pipeline = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createGuardedComputePipeline(pagerankPipeline), "pipeline");
724
+ const nodeCountBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.u32, nodeCount).$usage("uniform"), "nodeCountBuffer");
725
+ const dampingBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.f32, damping).$usage("uniform"), "dampingBuffer");
726
+ const bindGroup = root.createBindGroup(PageRankLayout, {
727
+ rowOffsets: csrBuffers.rowOffsets,
728
+ colIndices: csrBuffers.colIndices,
729
+ ranks,
730
+ outDegrees,
731
+ newRanks,
732
+ nodeCount: nodeCountBuffer,
733
+ damping: dampingBuffer
734
+ });
735
+ pipeline.with(bindGroup).dispatchThreads(nodeCount);
736
+ }
737
+ //#endregion
738
+ //#region src/gpu/kernels/jaccard/kernel.ts
739
+ /**
740
+ * TypeGPU compute kernel for batch Jaccard similarity.
741
+ *
742
+ * Computes Jaccard coefficient for multiple node pairs in parallel:
743
+ * J(u, v) = |N(u) ∩ N(v)| / |N(u) ∪ N(v)|
744
+ *
745
+ * Uses binary search optimisation: iterate smaller neighbourhood, search in larger.
746
+ *
747
+ * @module gpu/kernels/jaccard/kernel
748
+ */
749
+ /**
750
+ * Bind group layout for Jaccard kernel.
751
+ */
752
+ var JaccardLayout = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(src_default.bindGroupLayout({
753
+ rowOffsets: { storage: data_exports.arrayOf(data_exports.u32) },
754
+ colIndices: { storage: data_exports.arrayOf(data_exports.u32) },
755
+ pairsU: { storage: data_exports.arrayOf(data_exports.u32) },
756
+ pairsV: { storage: data_exports.arrayOf(data_exports.u32) },
757
+ results: {
758
+ storage: data_exports.arrayOf(data_exports.f32),
759
+ access: "mutable"
760
+ },
761
+ pairCount: { uniform: data_exports.u32 }
762
+ }), "JaccardLayout");
763
+ /**
764
+ * Jaccard compute pipeline: one thread per pair.
765
+ *
766
+ * For each pair (u, v):
767
+ * - Count intersection by iterating smaller neighbourhood
768
+ * - Binary search in larger neighbourhood
769
+ * - Jaccard = intersection / (degU + degV - intersection)
770
+ */
771
+ var jaccardPipeline = (($) => (globalThis.__TYPEGPU_META__ ??= /* @__PURE__ */ new WeakMap()).set($.f = ((pairIdx) => {
772
+ "use gpu";
773
+ const u = JaccardLayout.$.pairsU[pairIdx] ?? 0;
774
+ const v = JaccardLayout.$.pairsV[pairIdx] ?? 0;
775
+ const uStart = JaccardLayout.$.rowOffsets[u] ?? 0;
776
+ const uEnd = JaccardLayout.$.rowOffsets[__tsover_add(u, 1)] ?? 0;
777
+ const vStart = JaccardLayout.$.rowOffsets[v] ?? 0;
778
+ const vEnd = JaccardLayout.$.rowOffsets[__tsover_add(v, 1)] ?? 0;
779
+ const degU = __tsover_sub(uEnd, uStart);
780
+ const degV = __tsover_sub(vEnd, vStart);
781
+ if (degU === 0 || degV === 0) {
782
+ JaccardLayout.$.results[pairIdx] = 0;
783
+ return;
784
+ }
785
+ let intersection = 0;
786
+ if (degU <= degV) for (let i = uStart; i < uEnd; i = __tsover_add(i, 1)) {
787
+ const neighbour = JaccardLayout.$.colIndices[i] ?? 0;
788
+ let lo = vStart;
789
+ let hi = vEnd;
790
+ while (lo < hi) {
791
+ const mid = __tsover_add(lo, __tsover_div(__tsover_sub(hi, lo), 2));
792
+ const midVal = JaccardLayout.$.colIndices[mid] ?? 0;
793
+ if (midVal === neighbour) {
794
+ intersection = __tsover_add(intersection, 1);
795
+ lo = hi;
796
+ } else if (midVal < neighbour) lo = __tsover_add(mid, 1);
797
+ else hi = mid;
798
+ }
799
+ }
800
+ else for (let i = vStart; i < vEnd; i = __tsover_add(i, 1)) {
801
+ const neighbour = JaccardLayout.$.colIndices[i] ?? 0;
802
+ let lo = uStart;
803
+ let hi = uEnd;
804
+ while (lo < hi) {
805
+ const mid = __tsover_add(lo, __tsover_div(__tsover_sub(hi, lo), 2));
806
+ const midVal = JaccardLayout.$.colIndices[mid] ?? 0;
807
+ if (midVal === neighbour) {
808
+ intersection = __tsover_add(intersection, 1);
809
+ lo = hi;
810
+ } else if (midVal < neighbour) lo = __tsover_add(mid, 1);
811
+ else hi = mid;
812
+ }
813
+ }
814
+ const unionSize = __tsover_sub(__tsover_add(degU, degV), intersection);
815
+ JaccardLayout.$.results[pairIdx] = __tsover_div(intersection, unionSize);
816
+ }), {
817
+ v: 1,
818
+ name: "jaccardPipeline",
819
+ ast: {
820
+ "params": [{
821
+ "type": "i",
822
+ "name": "pairIdx"
823
+ }],
824
+ "body": [0, [
825
+ [
826
+ 13,
827
+ "u",
828
+ [
829
+ 3,
830
+ [
831
+ 8,
832
+ [
833
+ 7,
834
+ [
835
+ 7,
836
+ "JaccardLayout",
837
+ "$"
838
+ ],
839
+ "pairsU"
840
+ ],
841
+ "pairIdx"
842
+ ],
843
+ "??",
844
+ [5, "0"]
845
+ ]
846
+ ],
847
+ [
848
+ 13,
849
+ "v",
850
+ [
851
+ 3,
852
+ [
853
+ 8,
854
+ [
855
+ 7,
856
+ [
857
+ 7,
858
+ "JaccardLayout",
859
+ "$"
860
+ ],
861
+ "pairsV"
862
+ ],
863
+ "pairIdx"
864
+ ],
865
+ "??",
866
+ [5, "0"]
867
+ ]
868
+ ],
869
+ [
870
+ 13,
871
+ "uStart",
872
+ [
873
+ 3,
874
+ [
875
+ 8,
876
+ [
877
+ 7,
878
+ [
879
+ 7,
880
+ "JaccardLayout",
881
+ "$"
882
+ ],
883
+ "rowOffsets"
884
+ ],
885
+ "u"
886
+ ],
887
+ "??",
888
+ [5, "0"]
889
+ ]
890
+ ],
891
+ [
892
+ 13,
893
+ "uEnd",
894
+ [
895
+ 3,
896
+ [
897
+ 8,
898
+ [
899
+ 7,
900
+ [
901
+ 7,
902
+ "JaccardLayout",
903
+ "$"
904
+ ],
905
+ "rowOffsets"
906
+ ],
907
+ [
908
+ 1,
909
+ "u",
910
+ "+",
911
+ [5, "1"]
912
+ ]
913
+ ],
914
+ "??",
915
+ [5, "0"]
916
+ ]
917
+ ],
918
+ [
919
+ 13,
920
+ "vStart",
921
+ [
922
+ 3,
923
+ [
924
+ 8,
925
+ [
926
+ 7,
927
+ [
928
+ 7,
929
+ "JaccardLayout",
930
+ "$"
931
+ ],
932
+ "rowOffsets"
933
+ ],
934
+ "v"
935
+ ],
936
+ "??",
937
+ [5, "0"]
938
+ ]
939
+ ],
940
+ [
941
+ 13,
942
+ "vEnd",
943
+ [
944
+ 3,
945
+ [
946
+ 8,
947
+ [
948
+ 7,
949
+ [
950
+ 7,
951
+ "JaccardLayout",
952
+ "$"
953
+ ],
954
+ "rowOffsets"
955
+ ],
956
+ [
957
+ 1,
958
+ "v",
959
+ "+",
960
+ [5, "1"]
961
+ ]
962
+ ],
963
+ "??",
964
+ [5, "0"]
965
+ ]
966
+ ],
967
+ [
968
+ 13,
969
+ "degU",
970
+ [
971
+ 1,
972
+ "uEnd",
973
+ "-",
974
+ "uStart"
975
+ ]
976
+ ],
977
+ [
978
+ 13,
979
+ "degV",
980
+ [
981
+ 1,
982
+ "vEnd",
983
+ "-",
984
+ "vStart"
985
+ ]
986
+ ],
987
+ [
988
+ 11,
989
+ [
990
+ 3,
991
+ [
992
+ 1,
993
+ "degU",
994
+ "===",
995
+ [5, "0"]
996
+ ],
997
+ "||",
998
+ [
999
+ 1,
1000
+ "degV",
1001
+ "===",
1002
+ [5, "0"]
1003
+ ]
1004
+ ],
1005
+ [0, [[
1006
+ 2,
1007
+ [
1008
+ 8,
1009
+ [
1010
+ 7,
1011
+ [
1012
+ 7,
1013
+ "JaccardLayout",
1014
+ "$"
1015
+ ],
1016
+ "results"
1017
+ ],
1018
+ "pairIdx"
1019
+ ],
1020
+ "=",
1021
+ [5, "0"]
1022
+ ], [10]]]
1023
+ ],
1024
+ [
1025
+ 12,
1026
+ "intersection",
1027
+ [5, "0"]
1028
+ ],
1029
+ [
1030
+ 11,
1031
+ [
1032
+ 1,
1033
+ "degU",
1034
+ "<=",
1035
+ "degV"
1036
+ ],
1037
+ [0, [[
1038
+ 14,
1039
+ [
1040
+ 12,
1041
+ "i",
1042
+ "uStart"
1043
+ ],
1044
+ [
1045
+ 1,
1046
+ "i",
1047
+ "<",
1048
+ "uEnd"
1049
+ ],
1050
+ [
1051
+ 2,
1052
+ "i",
1053
+ "=",
1054
+ [
1055
+ 1,
1056
+ "i",
1057
+ "+",
1058
+ [5, "1"]
1059
+ ]
1060
+ ],
1061
+ [0, [
1062
+ [
1063
+ 13,
1064
+ "neighbour",
1065
+ [
1066
+ 3,
1067
+ [
1068
+ 8,
1069
+ [
1070
+ 7,
1071
+ [
1072
+ 7,
1073
+ "JaccardLayout",
1074
+ "$"
1075
+ ],
1076
+ "colIndices"
1077
+ ],
1078
+ "i"
1079
+ ],
1080
+ "??",
1081
+ [5, "0"]
1082
+ ]
1083
+ ],
1084
+ [
1085
+ 12,
1086
+ "lo",
1087
+ "vStart"
1088
+ ],
1089
+ [
1090
+ 12,
1091
+ "hi",
1092
+ "vEnd"
1093
+ ],
1094
+ [
1095
+ 15,
1096
+ [
1097
+ 1,
1098
+ "lo",
1099
+ "<",
1100
+ "hi"
1101
+ ],
1102
+ [0, [
1103
+ [
1104
+ 13,
1105
+ "mid",
1106
+ [
1107
+ 1,
1108
+ "lo",
1109
+ "+",
1110
+ [
1111
+ 1,
1112
+ [
1113
+ 1,
1114
+ "hi",
1115
+ "-",
1116
+ "lo"
1117
+ ],
1118
+ "/",
1119
+ [5, "2"]
1120
+ ]
1121
+ ]
1122
+ ],
1123
+ [
1124
+ 13,
1125
+ "midVal",
1126
+ [
1127
+ 3,
1128
+ [
1129
+ 8,
1130
+ [
1131
+ 7,
1132
+ [
1133
+ 7,
1134
+ "JaccardLayout",
1135
+ "$"
1136
+ ],
1137
+ "colIndices"
1138
+ ],
1139
+ "mid"
1140
+ ],
1141
+ "??",
1142
+ [5, "0"]
1143
+ ]
1144
+ ],
1145
+ [
1146
+ 11,
1147
+ [
1148
+ 1,
1149
+ "midVal",
1150
+ "===",
1151
+ "neighbour"
1152
+ ],
1153
+ [0, [[
1154
+ 2,
1155
+ "intersection",
1156
+ "=",
1157
+ [
1158
+ 1,
1159
+ "intersection",
1160
+ "+",
1161
+ [5, "1"]
1162
+ ]
1163
+ ], [
1164
+ 2,
1165
+ "lo",
1166
+ "=",
1167
+ "hi"
1168
+ ]]],
1169
+ [
1170
+ 11,
1171
+ [
1172
+ 1,
1173
+ "midVal",
1174
+ "<",
1175
+ "neighbour"
1176
+ ],
1177
+ [0, [[
1178
+ 2,
1179
+ "lo",
1180
+ "=",
1181
+ [
1182
+ 1,
1183
+ "mid",
1184
+ "+",
1185
+ [5, "1"]
1186
+ ]
1187
+ ]]],
1188
+ [0, [[
1189
+ 2,
1190
+ "hi",
1191
+ "=",
1192
+ "mid"
1193
+ ]]]
1194
+ ]
1195
+ ]
1196
+ ]]
1197
+ ]
1198
+ ]]
1199
+ ]]],
1200
+ [0, [[
1201
+ 14,
1202
+ [
1203
+ 12,
1204
+ "i",
1205
+ "vStart"
1206
+ ],
1207
+ [
1208
+ 1,
1209
+ "i",
1210
+ "<",
1211
+ "vEnd"
1212
+ ],
1213
+ [
1214
+ 2,
1215
+ "i",
1216
+ "=",
1217
+ [
1218
+ 1,
1219
+ "i",
1220
+ "+",
1221
+ [5, "1"]
1222
+ ]
1223
+ ],
1224
+ [0, [
1225
+ [
1226
+ 13,
1227
+ "neighbour",
1228
+ [
1229
+ 3,
1230
+ [
1231
+ 8,
1232
+ [
1233
+ 7,
1234
+ [
1235
+ 7,
1236
+ "JaccardLayout",
1237
+ "$"
1238
+ ],
1239
+ "colIndices"
1240
+ ],
1241
+ "i"
1242
+ ],
1243
+ "??",
1244
+ [5, "0"]
1245
+ ]
1246
+ ],
1247
+ [
1248
+ 12,
1249
+ "lo",
1250
+ "uStart"
1251
+ ],
1252
+ [
1253
+ 12,
1254
+ "hi",
1255
+ "uEnd"
1256
+ ],
1257
+ [
1258
+ 15,
1259
+ [
1260
+ 1,
1261
+ "lo",
1262
+ "<",
1263
+ "hi"
1264
+ ],
1265
+ [0, [
1266
+ [
1267
+ 13,
1268
+ "mid",
1269
+ [
1270
+ 1,
1271
+ "lo",
1272
+ "+",
1273
+ [
1274
+ 1,
1275
+ [
1276
+ 1,
1277
+ "hi",
1278
+ "-",
1279
+ "lo"
1280
+ ],
1281
+ "/",
1282
+ [5, "2"]
1283
+ ]
1284
+ ]
1285
+ ],
1286
+ [
1287
+ 13,
1288
+ "midVal",
1289
+ [
1290
+ 3,
1291
+ [
1292
+ 8,
1293
+ [
1294
+ 7,
1295
+ [
1296
+ 7,
1297
+ "JaccardLayout",
1298
+ "$"
1299
+ ],
1300
+ "colIndices"
1301
+ ],
1302
+ "mid"
1303
+ ],
1304
+ "??",
1305
+ [5, "0"]
1306
+ ]
1307
+ ],
1308
+ [
1309
+ 11,
1310
+ [
1311
+ 1,
1312
+ "midVal",
1313
+ "===",
1314
+ "neighbour"
1315
+ ],
1316
+ [0, [[
1317
+ 2,
1318
+ "intersection",
1319
+ "=",
1320
+ [
1321
+ 1,
1322
+ "intersection",
1323
+ "+",
1324
+ [5, "1"]
1325
+ ]
1326
+ ], [
1327
+ 2,
1328
+ "lo",
1329
+ "=",
1330
+ "hi"
1331
+ ]]],
1332
+ [
1333
+ 11,
1334
+ [
1335
+ 1,
1336
+ "midVal",
1337
+ "<",
1338
+ "neighbour"
1339
+ ],
1340
+ [0, [[
1341
+ 2,
1342
+ "lo",
1343
+ "=",
1344
+ [
1345
+ 1,
1346
+ "mid",
1347
+ "+",
1348
+ [5, "1"]
1349
+ ]
1350
+ ]]],
1351
+ [0, [[
1352
+ 2,
1353
+ "hi",
1354
+ "=",
1355
+ "mid"
1356
+ ]]]
1357
+ ]
1358
+ ]
1359
+ ]]
1360
+ ]
1361
+ ]]
1362
+ ]]]
1363
+ ],
1364
+ [
1365
+ 13,
1366
+ "unionSize",
1367
+ [
1368
+ 1,
1369
+ [
1370
+ 1,
1371
+ "degU",
1372
+ "+",
1373
+ "degV"
1374
+ ],
1375
+ "-",
1376
+ "intersection"
1377
+ ]
1378
+ ],
1379
+ [
1380
+ 2,
1381
+ [
1382
+ 8,
1383
+ [
1384
+ 7,
1385
+ [
1386
+ 7,
1387
+ "JaccardLayout",
1388
+ "$"
1389
+ ],
1390
+ "results"
1391
+ ],
1392
+ "pairIdx"
1393
+ ],
1394
+ "=",
1395
+ [
1396
+ 1,
1397
+ "intersection",
1398
+ "/",
1399
+ "unionSize"
1400
+ ]
1401
+ ]
1402
+ ]],
1403
+ "externalNames": ["JaccardLayout"]
1404
+ },
1405
+ externals: () => ({ JaccardLayout })
1406
+ }) && $.f)({});
1407
+ /**
1408
+ * Dispatch batch Jaccard on GPU.
1409
+ *
1410
+ * @param root - TypeGPU root instance
1411
+ * @param csrBuffers - CSR matrix as typed buffers
1412
+ * @param pairsU - First node of each pair (u32 array)
1413
+ * @param pairsV - Second node of each pair (u32 array)
1414
+ * @param results - Output Jaccard coefficients (f32 array, mutable)
1415
+ * @param pairCount - Number of pairs to compute
1416
+ */
1417
+ function dispatchJaccard(root, csrBuffers, pairsU, pairsV, results, pairCount) {
1418
+ const pipeline = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createGuardedComputePipeline(jaccardPipeline), "pipeline");
1419
+ const pairCountBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.u32, pairCount).$usage("uniform"), "pairCountBuffer");
1420
+ const bindGroup = root.createBindGroup(JaccardLayout, {
1421
+ rowOffsets: csrBuffers.rowOffsets,
1422
+ colIndices: csrBuffers.colIndices,
1423
+ pairsU,
1424
+ pairsV,
1425
+ results,
1426
+ pairCount: pairCountBuffer
1427
+ });
1428
+ pipeline.with(bindGroup).dispatchThreads(pairCount);
1429
+ }
1430
+ //#endregion
1431
+ //#region src/gpu/kernels/degree-histogram/kernel.ts
1432
+ /**
1433
+ * TypeGPU compute kernel for degree computation.
1434
+ *
1435
+ * Computes degree per node from CSR row offsets.
1436
+ * Note: Histogram aggregation requires atomic operations or CPU reduction.
1437
+ *
1438
+ * @module gpu/kernels/degree-histogram/kernel
1439
+ */
1440
+ /**
1441
+ * Bind group layout for degree kernel.
1442
+ */
1443
+ var DegreeLayout = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(src_default.bindGroupLayout({
1444
+ rowOffsets: { storage: data_exports.arrayOf(data_exports.u32) },
1445
+ degrees: {
1446
+ storage: data_exports.arrayOf(data_exports.u32),
1447
+ access: "mutable"
1448
+ },
1449
+ nodeCount: { uniform: data_exports.u32 }
1450
+ }), "DegreeLayout");
1451
+ /**
1452
+ * Degree compute pipeline: compute degree for each node.
1453
+ *
1454
+ * Each thread computes one node's degree from CSR row offsets:
1455
+ * degree[node] = rowOffsets[node+1] - rowOffsets[node]
1456
+ */
1457
+ var degreePipeline = (($) => (globalThis.__TYPEGPU_META__ ??= /* @__PURE__ */ new WeakMap()).set($.f = ((node) => {
1458
+ "use gpu";
1459
+ if (node >= (DegreeLayout.$.nodeCount ?? 0)) return;
1460
+ const start = DegreeLayout.$.rowOffsets[node] ?? 0;
1461
+ const end = DegreeLayout.$.rowOffsets[__tsover_add(node, 1)] ?? 0;
1462
+ const deg = __tsover_sub(end, start);
1463
+ DegreeLayout.$.degrees[node] = deg;
1464
+ }), {
1465
+ v: 1,
1466
+ name: "degreePipeline",
1467
+ ast: {
1468
+ "params": [{
1469
+ "type": "i",
1470
+ "name": "node"
1471
+ }],
1472
+ "body": [0, [
1473
+ [
1474
+ 13,
1475
+ "n",
1476
+ [
1477
+ 3,
1478
+ [
1479
+ 7,
1480
+ [
1481
+ 7,
1482
+ "DegreeLayout",
1483
+ "$"
1484
+ ],
1485
+ "nodeCount"
1486
+ ],
1487
+ "??",
1488
+ [5, "0"]
1489
+ ]
1490
+ ],
1491
+ [
1492
+ 11,
1493
+ [
1494
+ 1,
1495
+ "node",
1496
+ ">=",
1497
+ "n"
1498
+ ],
1499
+ [0, [[10]]]
1500
+ ],
1501
+ [
1502
+ 13,
1503
+ "start",
1504
+ [
1505
+ 3,
1506
+ [
1507
+ 8,
1508
+ [
1509
+ 7,
1510
+ [
1511
+ 7,
1512
+ "DegreeLayout",
1513
+ "$"
1514
+ ],
1515
+ "rowOffsets"
1516
+ ],
1517
+ "node"
1518
+ ],
1519
+ "??",
1520
+ [5, "0"]
1521
+ ]
1522
+ ],
1523
+ [
1524
+ 13,
1525
+ "end",
1526
+ [
1527
+ 3,
1528
+ [
1529
+ 8,
1530
+ [
1531
+ 7,
1532
+ [
1533
+ 7,
1534
+ "DegreeLayout",
1535
+ "$"
1536
+ ],
1537
+ "rowOffsets"
1538
+ ],
1539
+ [
1540
+ 1,
1541
+ "node",
1542
+ "+",
1543
+ [5, "1"]
1544
+ ]
1545
+ ],
1546
+ "??",
1547
+ [5, "0"]
1548
+ ]
1549
+ ],
1550
+ [
1551
+ 13,
1552
+ "deg",
1553
+ [
1554
+ 1,
1555
+ "end",
1556
+ "-",
1557
+ "start"
1558
+ ]
1559
+ ],
1560
+ [
1561
+ 2,
1562
+ [
1563
+ 8,
1564
+ [
1565
+ 7,
1566
+ [
1567
+ 7,
1568
+ "DegreeLayout",
1569
+ "$"
1570
+ ],
1571
+ "degrees"
1572
+ ],
1573
+ "node"
1574
+ ],
1575
+ "=",
1576
+ "deg"
1577
+ ]
1578
+ ]],
1579
+ "externalNames": ["DegreeLayout"]
1580
+ },
1581
+ externals: () => ({ DegreeLayout })
1582
+ }) && $.f)({});
1583
+ /**
1584
+ * Dispatch degree computation on GPU.
1585
+ *
1586
+ * Note: This computes per-node degrees. Histogram aggregation should be
1587
+ * done on CPU or with a separate reduction kernel.
1588
+ *
1589
+ * @param root - TypeGPU root instance
1590
+ * @param csrBuffers - CSR matrix as typed buffers
1591
+ * @param degrees - Output degree array (u32, mutable)
1592
+ * @param nodeCount - Number of nodes
1593
+ */
1594
+ function dispatchDegreeHistogram(root, csrBuffers, degrees, nodeCount) {
1595
+ const pipeline = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createGuardedComputePipeline(degreePipeline), "pipeline");
1596
+ const nodeCountBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.u32, nodeCount).$usage("uniform"), "nodeCountBuffer");
1597
+ const bindGroup = root.createBindGroup(DegreeLayout, {
1598
+ rowOffsets: csrBuffers.rowOffsets,
1599
+ degrees,
1600
+ nodeCount: nodeCountBuffer
1601
+ });
1602
+ pipeline.with(bindGroup).dispatchThreads(nodeCount);
1603
+ }
1604
+ //#endregion
1605
+ //#region src/gpu/operations.ts
1606
+ /**
1607
+ * Sparse matrix-vector multiply on GPU.
1608
+ *
1609
+ * Computes y = A * x where A is the graph adjacency matrix in CSR format.
1610
+ *
1611
+ * @param graph - Input graph
1612
+ * @param x - Input vector (must have length = graph.nodeCount)
1613
+ * @param options - Compute options (backend, root, signal)
1614
+ * @returns Result vector y
1615
+ */
1616
+ async function gpuSpmv(graph, x, options) {
1617
+ const nodeCount = graph.nodeCount;
1618
+ if (x.length !== nodeCount) throw new Error(`Input vector length (${String(x.length)}) must match node count (${String(nodeCount)})`);
1619
+ const cpuFn = () => {
1620
+ const { csr } = graphToCSR(graph);
1621
+ const y = new Float32Array(nodeCount);
1622
+ for (let row = 0; row < nodeCount; row++) {
1623
+ const start = csr.rowOffsets[row] ?? 0;
1624
+ const end = csr.rowOffsets[row + 1] ?? 0;
1625
+ let sum = 0;
1626
+ for (let i = start; i < end; i++) {
1627
+ const col = csr.colIndices[i] ?? 0;
1628
+ const weight = csr.values?.[i] ?? 1;
1629
+ sum += weight * (x[col] ?? 0);
1630
+ }
1631
+ y[row] = sum;
1632
+ }
1633
+ return y;
1634
+ };
1635
+ const gpuFn = async (root) => {
1636
+ const { csr } = graphToCSR(graph);
1637
+ const csrBuffers = csrToTypedBuffers(root, csr);
1638
+ const xBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.f32, nodeCount), Array.from(x)).$usage("storage"), "xBuffer");
1639
+ const yBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.f32, nodeCount)).$usage("storage"), "yBuffer");
1640
+ dispatchSpmv(root, csrBuffers, xBuffer, yBuffer, nodeCount, csr.values !== void 0);
1641
+ const result = await yBuffer.read();
1642
+ return new Float32Array(result);
1643
+ };
1644
+ return withBackend({
1645
+ backend: options?.backend,
1646
+ root: options?.root,
1647
+ signal: options?.signal
1648
+ }, cpuFn, gpuFn);
1649
+ }
1650
+ /**
1651
+ * PageRank via GPU-accelerated power iteration.
1652
+ *
1653
+ * @param graph - Input graph (will be converted to transpose CSR for in-edges)
1654
+ * @param options - Compute options plus damping factor and iteration count
1655
+ * @returns PageRank scores for each node
1656
+ */
1657
+ async function gpuPageRank(graph, options) {
1658
+ const nodeCount = graph.nodeCount;
1659
+ const damping = options?.damping ?? .85;
1660
+ const iterations = options?.iterations ?? 20;
1661
+ const cpuFn = () => {
1662
+ const { csr } = graphToCSR(graph);
1663
+ const ranks = new Float32Array(nodeCount).fill(1 / nodeCount);
1664
+ const outDegrees = new Uint32Array(nodeCount);
1665
+ for (let i = 0; i < nodeCount; i++) outDegrees[i] = (csr.rowOffsets[i + 1] ?? 0) - (csr.rowOffsets[i] ?? 0);
1666
+ for (let iter = 0; iter < iterations; iter++) {
1667
+ const newRanks = new Float32Array(nodeCount);
1668
+ for (let v = 0; v < nodeCount; v++) {
1669
+ const start = csr.rowOffsets[v] ?? 0;
1670
+ const end = csr.rowOffsets[v + 1] ?? 0;
1671
+ let contribution = 0;
1672
+ for (let i = start; i < end; i++) {
1673
+ const source = csr.colIndices[i] ?? 0;
1674
+ const deg = outDegrees[source] ?? 0;
1675
+ if (deg > 0) contribution += (ranks[source] ?? 0) / deg;
1676
+ }
1677
+ newRanks[v] = (1 - damping) / nodeCount + damping * contribution;
1678
+ }
1679
+ ranks.set(newRanks);
1680
+ }
1681
+ return ranks;
1682
+ };
1683
+ const gpuFn = async (root) => {
1684
+ const { csr } = graphToCSR(graph);
1685
+ const csrBuffers = csrToTypedBuffers(root, csr);
1686
+ const outDegrees = new Uint32Array(nodeCount);
1687
+ for (let i = 0; i < nodeCount; i++) outDegrees[i] = (csr.rowOffsets[i + 1] ?? 0) - (csr.rowOffsets[i] ?? 0);
1688
+ const outDegreesBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.u32, nodeCount), Array.from(outDegrees)).$usage("storage"), "outDegreesBuffer");
1689
+ const ranksBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.f32, nodeCount), Array.from(new Float32Array(nodeCount).fill(1 / nodeCount))).$usage("storage"), "ranksBuffer");
1690
+ const newRanksBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.f32, nodeCount)).$usage("storage"), "newRanksBuffer");
1691
+ for (let iter = 0; iter < iterations; iter++) {
1692
+ dispatchPagerank(root, csrBuffers, ranksBuffer, outDegreesBuffer, newRanksBuffer, nodeCount, damping);
1693
+ const newRanks = await newRanksBuffer.read();
1694
+ ranksBuffer.write(Array.from(newRanks));
1695
+ }
1696
+ const result = await ranksBuffer.read();
1697
+ return new Float32Array(result);
1698
+ };
1699
+ return withBackend({
1700
+ backend: options?.backend,
1701
+ root: options?.root,
1702
+ signal: options?.signal
1703
+ }, cpuFn, gpuFn);
1704
+ }
1705
+ /**
1706
+ * Batch Jaccard similarity for node pairs on GPU.
1707
+ *
1708
+ * @param graph - Input graph
1709
+ * @param pairs - Array of [u, v] node ID pairs
1710
+ * @param options - Compute options
1711
+ * @returns Jaccard coefficients for each pair
1712
+ */
1713
+ async function gpuJaccardBatch(graph, pairs, options) {
1714
+ const pairCount = pairs.length;
1715
+ const { indexMap } = graphToCSR(graph);
1716
+ const cpuFn = () => {
1717
+ const { csr } = graphToCSR(graph);
1718
+ const results = new Float32Array(pairCount);
1719
+ for (let p = 0; p < pairCount; p++) {
1720
+ const pair = pairs[p];
1721
+ if (pair === void 0) continue;
1722
+ const [u, v] = pair;
1723
+ const uIdx = indexMap.nodeToIndex.get(u);
1724
+ const vIdx = indexMap.nodeToIndex.get(v);
1725
+ if (uIdx === void 0 || vIdx === void 0) {
1726
+ results[p] = 0;
1727
+ continue;
1728
+ }
1729
+ const uStart = csr.rowOffsets[uIdx] ?? 0;
1730
+ const uEnd = csr.rowOffsets[uIdx + 1] ?? 0;
1731
+ const vStart = csr.rowOffsets[vIdx] ?? 0;
1732
+ const vEnd = csr.rowOffsets[vIdx + 1] ?? 0;
1733
+ const uNeighbours = new Set(Array.from(csr.colIndices.slice(uStart, uEnd)));
1734
+ const vNeighbours = new Set(Array.from(csr.colIndices.slice(vStart, vEnd)));
1735
+ let intersection = 0;
1736
+ for (const n of uNeighbours) if (vNeighbours.has(n)) intersection++;
1737
+ const union = uNeighbours.size + vNeighbours.size - intersection;
1738
+ results[p] = union > 0 ? intersection / union : 0;
1739
+ }
1740
+ return results;
1741
+ };
1742
+ const gpuFn = async (root) => {
1743
+ const { csr } = graphToCSR(graph);
1744
+ const csrBuffers = csrToTypedBuffers(root, csr);
1745
+ const pairsU = new Uint32Array(pairCount);
1746
+ const pairsV = new Uint32Array(pairCount);
1747
+ for (let i = 0; i < pairCount; i++) {
1748
+ const pair = pairs[i];
1749
+ if (pair === void 0) continue;
1750
+ const uIdx = indexMap.nodeToIndex.get(pair[0]);
1751
+ const vIdx = indexMap.nodeToIndex.get(pair[1]);
1752
+ pairsU[i] = uIdx ?? 0;
1753
+ pairsV[i] = vIdx ?? 0;
1754
+ }
1755
+ const pairsUBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.u32, pairCount), Array.from(pairsU)).$usage("storage"), "pairsUBuffer");
1756
+ const pairsVBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.u32, pairCount), Array.from(pairsV)).$usage("storage"), "pairsVBuffer");
1757
+ const resultsBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.f32, pairCount)).$usage("storage"), "resultsBuffer");
1758
+ dispatchJaccard(root, csrBuffers, pairsUBuffer, pairsVBuffer, resultsBuffer, pairCount);
1759
+ const result = await resultsBuffer.read();
1760
+ return new Float32Array(result);
1761
+ };
1762
+ return withBackend({
1763
+ backend: options?.backend,
1764
+ root: options?.root,
1765
+ signal: options?.signal
1766
+ }, cpuFn, gpuFn);
1767
+ }
1768
+ /**
1769
+ * BFS level assignment from source node on GPU.
1770
+ *
1771
+ * Note: Full GPU BFS requires atomics not yet available in TypeGPU.
1772
+ * This implementation uses CPU for now but maintains the API.
1773
+ *
1774
+ * @param graph - Input graph
1775
+ * @param source - Source node ID
1776
+ * @param options - Compute options
1777
+ * @returns BFS level for each node (-1 for unreachable)
1778
+ */
1779
+ async function gpuBfsLevels(graph, source, options) {
1780
+ const nodeCount = graph.nodeCount;
1781
+ const { indexMap } = graphToCSR(graph);
1782
+ const cpuFn = () => {
1783
+ const { csr } = graphToCSR(graph);
1784
+ const levels = new Int32Array(nodeCount).fill(-1);
1785
+ const visited = new Uint8Array(nodeCount);
1786
+ const sourceIndex = indexMap.nodeToIndex.get(source);
1787
+ if (sourceIndex === void 0) throw new Error(`Source node ${source} not found in graph`);
1788
+ const queue = [sourceIndex];
1789
+ levels[sourceIndex] = 0;
1790
+ visited[sourceIndex] = 1;
1791
+ while (queue.length > 0) {
1792
+ const current = queue.shift();
1793
+ if (current === void 0) break;
1794
+ const currentLevel = levels[current] ?? 0;
1795
+ const start = csr.rowOffsets[current] ?? 0;
1796
+ const end = csr.rowOffsets[current + 1] ?? 0;
1797
+ for (let i = start; i < end; i++) {
1798
+ const neighbour = csr.colIndices[i] ?? 0;
1799
+ if (visited[neighbour] === 0) {
1800
+ visited[neighbour] = 1;
1801
+ levels[neighbour] = currentLevel + 1;
1802
+ queue.push(neighbour);
1803
+ }
1804
+ }
1805
+ }
1806
+ return levels;
1807
+ };
1808
+ const gpuFn = (_root) => {
1809
+ return cpuFn();
1810
+ };
1811
+ return withBackend({
1812
+ backend: options?.backend,
1813
+ root: options?.root,
1814
+ signal: options?.signal
1815
+ }, cpuFn, gpuFn);
1816
+ }
1817
+ /**
1818
+ * Degree histogram and statistics on GPU.
1819
+ *
1820
+ * @param graph - Input graph
1821
+ * @param options - Compute options
1822
+ * @returns Degree statistics with histogram
1823
+ */
1824
+ async function gpuDegreeHistogram(graph, options) {
1825
+ const nodeCount = graph.nodeCount;
1826
+ const cpuFn = () => {
1827
+ const { csr } = graphToCSR(graph);
1828
+ const degrees = new Uint32Array(nodeCount);
1829
+ for (let i = 0; i < nodeCount; i++) degrees[i] = (csr.rowOffsets[i + 1] ?? 0) - (csr.rowOffsets[i] ?? 0);
1830
+ const max = degrees.length > 0 ? Math.max(...degrees) : 0;
1831
+ const histogram = Array.from({ length: max + 1 }, () => 0);
1832
+ let sum = 0;
1833
+ let min = Infinity;
1834
+ for (const d of degrees) {
1835
+ histogram[d] = (histogram[d] ?? 0) + 1;
1836
+ sum += d;
1837
+ if (d < min) min = d;
1838
+ }
1839
+ if (degrees.length === 0) min = 0;
1840
+ return {
1841
+ min,
1842
+ max,
1843
+ mean: nodeCount > 0 ? sum / nodeCount : 0,
1844
+ histogram
1845
+ };
1846
+ };
1847
+ const gpuFn = async (root) => {
1848
+ const { csr } = graphToCSR(graph);
1849
+ const csrBuffers = csrToTypedBuffers(root, csr);
1850
+ const degreesBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.u32, nodeCount)).$usage("storage"), "degreesBuffer");
1851
+ dispatchDegreeHistogram(root, csrBuffers, degreesBuffer, nodeCount);
1852
+ const degrees = await degreesBuffer.read();
1853
+ const max = degrees.length > 0 ? Math.max(...degrees) : 0;
1854
+ const histogram = Array.from({ length: max + 1 }, () => 0);
1855
+ let sum = 0;
1856
+ let min = Infinity;
1857
+ for (const d of degrees) {
1858
+ histogram[d] = (histogram[d] ?? 0) + 1;
1859
+ sum += d;
1860
+ if (d < min) min = d;
1861
+ }
1862
+ if (degrees.length === 0) min = 0;
1863
+ return {
1864
+ min,
1865
+ max,
1866
+ mean: nodeCount > 0 ? sum / nodeCount : 0,
1867
+ histogram
1868
+ };
1869
+ };
1870
+ return withBackend({
1871
+ backend: options?.backend,
1872
+ root: options?.root,
1873
+ signal: options?.signal
1874
+ }, cpuFn, gpuFn);
1875
+ }
1876
+ /**
1877
+ * Batch MI computation for multiple node pairs on GPU.
1878
+ *
1879
+ * For Jaccard-family variants, uses the intersection kernel for raw counts
1880
+ * then applies the variant-specific formula on CPU.
1881
+ *
1882
+ * @param graph - Input graph
1883
+ * @param pairs - Array of [u, v] node ID pairs
1884
+ * @param variant - MI variant to compute (default: jaccard)
1885
+ * @param options - Compute options
1886
+ * @returns MI scores and raw intersection data for each pair
1887
+ */
1888
+ async function gpuMIBatch(graph, pairs, variant = "jaccard", options) {
1889
+ const pairCount = pairs.length;
1890
+ const { csr, indexMap } = graphToCSR(graph);
1891
+ const cpuFn = () => {
1892
+ const indexPairs = [];
1893
+ const validPair = [];
1894
+ for (const pair of pairs) {
1895
+ const uIdx = indexMap.nodeToIndex.get(pair[0]);
1896
+ const vIdx = indexMap.nodeToIndex.get(pair[1]);
1897
+ if (uIdx !== void 0 && vIdx !== void 0) {
1898
+ indexPairs.push([uIdx, vIdx]);
1899
+ validPair.push(true);
1900
+ } else {
1901
+ indexPairs.push([0, 0]);
1902
+ validPair.push(false);
1903
+ }
1904
+ }
1905
+ const { intersections, sizeUs, sizeVs } = intersectionBatch(csr.rowOffsets, csr.colIndices, indexPairs);
1906
+ const scores = new Float32Array(pairCount);
1907
+ for (let i = 0; i < pairCount; i++) {
1908
+ if (validPair[i] !== true) {
1909
+ scores[i] = 0;
1910
+ continue;
1911
+ }
1912
+ const result = {
1913
+ intersection: intersections[i] ?? 0,
1914
+ sizeU: sizeUs[i] ?? 0,
1915
+ sizeV: sizeVs[i] ?? 0
1916
+ };
1917
+ const base = applyMIVariant(result, "jaccard");
1918
+ switch (variant) {
1919
+ case "scale": {
1920
+ const rho = computeGraphDensity(csr);
1921
+ scores[i] = rho > 0 ? base / rho : base;
1922
+ break;
1923
+ }
1924
+ case "skew": {
1925
+ const N = csr.rowOffsets.length - 1;
1926
+ const degU = result.sizeU;
1927
+ const degV = result.sizeV;
1928
+ scores[i] = base * (Math.log(N / (degU + 1)) * Math.log(N / (degV + 1)));
1929
+ break;
1930
+ }
1931
+ case "span": {
1932
+ const clustering = computeClusteringCoefficients(csr);
1933
+ const pair = pairs[i];
1934
+ const u0 = pair ? indexMap.nodeToIndex.get(pair[0]) : void 0;
1935
+ const v0 = pair ? indexMap.nodeToIndex.get(pair[1]) : void 0;
1936
+ const cu = (u0 !== void 0 ? clustering[u0] : void 0) ?? 0;
1937
+ const cv = (v0 !== void 0 ? clustering[v0] : void 0) ?? 0;
1938
+ scores[i] = base * (1 - Math.max(cu, cv));
1939
+ break;
1940
+ }
1941
+ default: scores[i] = applyMIVariant(result, variant);
1942
+ }
1943
+ }
1944
+ return {
1945
+ scores,
1946
+ intersections,
1947
+ sizeUs,
1948
+ sizeVs
1949
+ };
1950
+ };
1951
+ const gpuFn = async (root) => {
1952
+ const csrBuffers = csrToTypedBuffers(root, csr);
1953
+ const uArr = new Uint32Array(pairCount);
1954
+ const vArr = new Uint32Array(pairCount);
1955
+ const validPair = Array.from({ length: pairCount }, () => false);
1956
+ for (let i = 0; i < pairCount; i++) {
1957
+ const p = pairs[i];
1958
+ const uIdxRaw = p ? indexMap.nodeToIndex.get(p[0]) : void 0;
1959
+ const vIdxRaw = p ? indexMap.nodeToIndex.get(p[1]) : void 0;
1960
+ const uIdx = uIdxRaw ?? 0;
1961
+ const vIdx = vIdxRaw ?? 0;
1962
+ if (uIdxRaw !== void 0 && vIdxRaw !== void 0) {
1963
+ uArr[i] = uIdx;
1964
+ vArr[i] = vIdx;
1965
+ validPair[i] = true;
1966
+ } else {
1967
+ uArr[i] = 0;
1968
+ vArr[i] = 0;
1969
+ validPair[i] = false;
1970
+ }
1971
+ }
1972
+ const pairsUBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.u32, pairCount), Array.from(uArr)).$usage("storage"), "pairsUBuffer");
1973
+ const pairsVBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.u32, pairCount), Array.from(vArr)).$usage("storage"), "pairsVBuffer");
1974
+ const intersectionsBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.u32, pairCount)).$usage("storage"), "intersectionsBuffer");
1975
+ const sizeUsBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.u32, pairCount)).$usage("storage"), "sizeUsBuffer");
1976
+ const sizeVsBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.u32, pairCount)).$usage("storage"), "sizeVsBuffer");
1977
+ if (variant === "adamic-adar") {
1978
+ const resultsBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.f32, pairCount)).$usage("storage"), "resultsBuffer");
1979
+ const { dispatchAdamicAdar } = await import("./kernel-CvnRsF7E.js");
1980
+ dispatchAdamicAdar(root, csrBuffers, pairsUBuffer, pairsVBuffer, resultsBuffer, intersectionsBuffer, sizeUsBuffer, sizeVsBuffer, pairCount);
1981
+ const scoresRaw = await resultsBuffer.read();
1982
+ const intersectionsRaw = await intersectionsBuffer.read();
1983
+ const sizeUsRaw = await sizeUsBuffer.read();
1984
+ const sizeVsRaw = await sizeVsBuffer.read();
1985
+ const scores = new Float32Array(scoresRaw);
1986
+ const intersections = new Uint32Array(intersectionsRaw);
1987
+ const sizeUs = new Uint32Array(sizeUsRaw);
1988
+ const sizeVs = new Uint32Array(sizeVsRaw);
1989
+ for (let i = 0; i < pairCount; i++) if (validPair[i] !== true) {
1990
+ scores[i] = 0;
1991
+ intersections[i] = 0;
1992
+ sizeUs[i] = 0;
1993
+ sizeVs[i] = 0;
1994
+ }
1995
+ return {
1996
+ scores,
1997
+ intersections,
1998
+ sizeUs,
1999
+ sizeVs
2000
+ };
2001
+ } else {
2002
+ const { dispatchIntersection } = await import("./kernel-6deK9fh1.js");
2003
+ dispatchIntersection(root, csrBuffers, pairsUBuffer, pairsVBuffer, intersectionsBuffer, sizeUsBuffer, sizeVsBuffer, pairCount);
2004
+ const intersectionsRaw = await intersectionsBuffer.read();
2005
+ const sizeUsRaw = await sizeUsBuffer.read();
2006
+ const sizeVsRaw = await sizeVsBuffer.read();
2007
+ const intersections = new Uint32Array(intersectionsRaw);
2008
+ const sizeUs = new Uint32Array(sizeUsRaw);
2009
+ const sizeVs = new Uint32Array(sizeVsRaw);
2010
+ const scores = new Float32Array(pairCount);
2011
+ if (variant === "scale" || variant === "skew" || variant === "span") {
2012
+ const clustering = variant === "span" ? computeClusteringCoefficients(csr) : void 0;
2013
+ const N = csr.rowOffsets.length - 1;
2014
+ const rho = variant === "scale" ? computeGraphDensity(csr) : void 0;
2015
+ for (let i = 0; i < pairCount; i++) {
2016
+ if (validPair[i] !== true) {
2017
+ scores[i] = 0;
2018
+ continue;
2019
+ }
2020
+ const result = {
2021
+ intersection: intersections[i] ?? 0,
2022
+ sizeU: sizeUs[i] ?? 0,
2023
+ sizeV: sizeVs[i] ?? 0
2024
+ };
2025
+ const base = applyMIVariant(result, "jaccard");
2026
+ switch (variant) {
2027
+ case "scale":
2028
+ if (rho !== void 0 && rho > 0) scores[i] = base / rho;
2029
+ else scores[i] = base;
2030
+ break;
2031
+ case "skew": {
2032
+ const degU = result.sizeU;
2033
+ const degV = result.sizeV;
2034
+ scores[i] = base * (Math.log(N / (degU + 1)) * Math.log(N / (degV + 1)));
2035
+ break;
2036
+ }
2037
+ case "span": {
2038
+ const pair = pairs[i];
2039
+ const uId = pair ? pair[0] : void 0;
2040
+ const vId = pair ? pair[1] : void 0;
2041
+ const uIdx = uId !== void 0 ? indexMap.nodeToIndex.get(uId) : void 0;
2042
+ const vIdx = vId !== void 0 ? indexMap.nodeToIndex.get(vId) : void 0;
2043
+ const cu = uIdx !== void 0 ? clustering?.[uIdx] ?? 0 : 0;
2044
+ const cv = vIdx !== void 0 ? clustering?.[vIdx] ?? 0 : 0;
2045
+ scores[i] = base * (1 - Math.max(cu, cv));
2046
+ break;
2047
+ }
2048
+ }
2049
+ }
2050
+ } else for (let i = 0; i < pairCount; i++) {
2051
+ if (validPair[i] !== true) {
2052
+ scores[i] = 0;
2053
+ continue;
2054
+ }
2055
+ scores[i] = applyMIVariant({
2056
+ intersection: intersections[i] ?? 0,
2057
+ sizeU: sizeUs[i] ?? 0,
2058
+ sizeV: sizeVs[i] ?? 0
2059
+ }, variant);
2060
+ }
2061
+ return {
2062
+ scores,
2063
+ intersections,
2064
+ sizeUs,
2065
+ sizeVs
2066
+ };
2067
+ }
2068
+ };
2069
+ return withBackend({
2070
+ backend: options?.backend,
2071
+ root: options?.root,
2072
+ signal: options?.signal
2073
+ }, cpuFn, gpuFn);
2074
+ }
2075
+ /**
2076
+ * Apply MI variant formula to intersection result.
2077
+ */
2078
+ function computeGraphDensity(csr) {
2079
+ const n = csr.rowOffsets.length - 1;
2080
+ const m = csr.colIndices.length;
2081
+ return n > 1 ? 2 * m / (n * (n - 1)) : 0;
2082
+ }
2083
+ function computeClusteringCoefficients(csr) {
2084
+ const n = csr.rowOffsets.length - 1;
2085
+ const coeffs = new Array(n).fill(0);
2086
+ for (let v = 0; v < n; v++) {
2087
+ const start = csr.rowOffsets[v] ?? 0;
2088
+ const end = csr.rowOffsets[v + 1] ?? 0;
2089
+ const deg = end - start;
2090
+ if (deg < 2) {
2091
+ coeffs[v] = 0;
2092
+ continue;
2093
+ }
2094
+ const neighbours = new Set(csr.colIndices.slice(start, end));
2095
+ let links = 0;
2096
+ for (const u of neighbours) {
2097
+ const uStart = csr.rowOffsets[u] ?? 0;
2098
+ const uEnd = csr.rowOffsets[u + 1] ?? 0;
2099
+ for (let k = uStart; k < uEnd; k++) {
2100
+ const colIdx = csr.colIndices[k] ?? 0;
2101
+ if (neighbours.has(colIdx)) links++;
2102
+ }
2103
+ }
2104
+ coeffs[v] = 2 * links / (deg * (deg - 1));
2105
+ }
2106
+ return coeffs;
2107
+ }
2108
+ function applyMIVariant(result, variant) {
2109
+ switch (variant) {
2110
+ case "jaccard": return jaccardFromIntersection(result);
2111
+ case "cosine": return cosineFromIntersection(result);
2112
+ case "sorensen": return sorensenDiceFromIntersection(result);
2113
+ case "overlap-coefficient": return overlapFromIntersection(result);
2114
+ case "hub-promoted": return hubPromotedFromIntersection(result);
2115
+ case "resource-allocation": return jaccardFromIntersection(result);
2116
+ case "adamic-adar": return jaccardFromIntersection(result);
2117
+ case "scale":
2118
+ case "skew":
2119
+ case "span":
2120
+ case "etch":
2121
+ case "notch":
2122
+ case "adaptive": return jaccardFromIntersection(result);
2123
+ default: return jaccardFromIntersection(result);
2124
+ }
2125
+ }
2126
+ /**
2127
+ * Assign points to nearest centroids using GPU.
2128
+ *
2129
+ * For each point, computes distance to all centroids and assigns to nearest.
2130
+ * This is the main parallelizable operation in K-means clustering.
2131
+ *
2132
+ * @param points - Array of 3D points to assign
2133
+ * @param centroids - Array of 3D centroid coordinates
2134
+ * @param options - Compute options
2135
+ * @returns Assignment indices and distances
2136
+ */
2137
+ async function gpuKMeansAssign(points, centroids, options) {
2138
+ const pointCount = points.length;
2139
+ const k = centroids.length;
2140
+ const cpuFn = () => {
2141
+ const assignments = new Uint32Array(pointCount);
2142
+ const distances = new Float32Array(pointCount);
2143
+ for (let i = 0; i < pointCount; i++) {
2144
+ const point = points[i];
2145
+ if (point === void 0) {
2146
+ assignments[i] = 0;
2147
+ distances[i] = 0;
2148
+ continue;
2149
+ }
2150
+ const [px, py, pz] = point;
2151
+ let minDist = Infinity;
2152
+ let minIdx = 0;
2153
+ for (let j = 0; j < k; j++) {
2154
+ const centroid = centroids[j];
2155
+ if (centroid === void 0) continue;
2156
+ const [cx, cy, cz] = centroid;
2157
+ const dx = px - cx;
2158
+ const dy = py - cy;
2159
+ const dz = pz - cz;
2160
+ const distSq = dx * dx + dy * dy + dz * dz;
2161
+ if (distSq < minDist) {
2162
+ minDist = distSq;
2163
+ minIdx = j;
2164
+ }
2165
+ }
2166
+ assignments[i] = minIdx;
2167
+ distances[i] = minDist;
2168
+ }
2169
+ return {
2170
+ assignments,
2171
+ distances
2172
+ };
2173
+ };
2174
+ const gpuFn = async (root) => {
2175
+ if (pointCount < 100) return cpuFn();
2176
+ const pointsBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.vec3f, pointCount), Array.from(points)).$usage("storage"), "pointsBuffer");
2177
+ const centroidsBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.vec3f, k), Array.from(centroids)).$usage("storage"), "centroidsBuffer");
2178
+ const assignmentsBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.u32, pointCount)).$usage("storage"), "assignmentsBuffer");
2179
+ const distancesBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.f32, pointCount)).$usage("storage"), "distancesBuffer");
2180
+ const { dispatchKMeansAssign: dispatch } = await import("./kernel-CigCjrts.js");
2181
+ dispatch(root, pointsBuffer, centroidsBuffer, assignmentsBuffer, distancesBuffer, pointCount, k);
2182
+ const assignments = await assignmentsBuffer.read();
2183
+ const distances = await distancesBuffer.read();
2184
+ return {
2185
+ assignments: new Uint32Array(assignments),
2186
+ distances: new Float32Array(distances)
2187
+ };
2188
+ };
2189
+ return withBackend({
2190
+ backend: options?.backend,
2191
+ root: options?.root,
2192
+ signal: options?.signal
2193
+ }, cpuFn, gpuFn);
2194
+ }
2195
+ //#endregion
2196
+ export { gpuMIBatch as a, withBackend as c, detectWebGPU as d, isWebGPUAvailable as f, gpuKMeansAssign as i, GPUNotAvailableError as l, gpuDegreeHistogram as n, gpuPageRank as o, gpuJaccardBatch as r, gpuSpmv as s, gpuBfsLevels as t, assertWebGPUAvailable as u };
2197
+
2198
+ //# sourceMappingURL=operations-D9otVlIH.js.map