graphwise 1.11.0 → 1.12.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 (50) hide show
  1. package/README.md +1 -1
  2. package/dist/gpu/index.cjs +1 -1
  3. package/dist/gpu/index.js +1 -1
  4. package/dist/index/index.cjs +7 -3
  5. package/dist/index/index.js +4 -4
  6. package/dist/{kernel-CigCjrts.js → kernel-BLwhyVSV.js} +1 -1
  7. package/dist/{kernel-CigCjrts.js.map → kernel-BLwhyVSV.js.map} +1 -1
  8. package/dist/{kernel-2oH4Cn32.cjs → kernel-BffKjhZS.cjs} +1 -1
  9. package/dist/{kernel-2oH4Cn32.cjs.map → kernel-BffKjhZS.cjs.map} +1 -1
  10. package/dist/{kernel-CXeGBH3s.cjs → kernel-CbP715Sq.cjs} +1 -1
  11. package/dist/{kernel-CXeGBH3s.cjs.map → kernel-CbP715Sq.cjs.map} +1 -1
  12. package/dist/{kernel-CvnRsF7E.js → kernel-DolEKSSx.js} +1 -1
  13. package/dist/{kernel-CvnRsF7E.js.map → kernel-DolEKSSx.js.map} +1 -1
  14. package/dist/{kernel-DukrXtVb.cjs → kernel-E_h47HjZ.cjs} +1 -1
  15. package/dist/{kernel-DukrXtVb.cjs.map → kernel-E_h47HjZ.cjs.map} +1 -1
  16. package/dist/{kernel-6deK9fh1.js → kernel-lYa4TYth.js} +1 -1
  17. package/dist/{kernel-6deK9fh1.js.map → kernel-lYa4TYth.js.map} +1 -1
  18. package/dist/{operations-D-RB67WP.cjs → operations-CSU0yFPr.cjs} +4 -4
  19. package/dist/{operations-D-RB67WP.cjs.map → operations-CSU0yFPr.cjs.map} +1 -1
  20. package/dist/{operations-D9otVlIH.js → operations-CdrA87Au.js} +4 -4
  21. package/dist/{operations-D9otVlIH.js.map → operations-CdrA87Au.js.map} +1 -1
  22. package/dist/ranking/index.cjs +1 -1
  23. package/dist/ranking/index.js +1 -1
  24. package/dist/{ranking-pe5UaxKg.cjs → ranking-BQqrH26-.cjs} +2 -2
  25. package/dist/{ranking-pe5UaxKg.cjs.map → ranking-BQqrH26-.cjs.map} +1 -1
  26. package/dist/{ranking-DOKDBcIR.js → ranking-B_KdM8Wq.js} +2 -2
  27. package/dist/{ranking-DOKDBcIR.js.map → ranking-B_KdM8Wq.js.map} +1 -1
  28. package/dist/seeds/basil.d.ts +12 -0
  29. package/dist/seeds/basil.d.ts.map +1 -0
  30. package/dist/seeds/brisk.d.ts +18 -0
  31. package/dist/seeds/brisk.d.ts.map +1 -0
  32. package/dist/seeds/hybrid-core.d.ts +32 -0
  33. package/dist/seeds/hybrid-core.d.ts.map +1 -0
  34. package/dist/seeds/hybrid-ensembles.unit.test.d.ts +2 -0
  35. package/dist/seeds/hybrid-ensembles.unit.test.d.ts.map +1 -0
  36. package/dist/seeds/index.cjs +11 -1108
  37. package/dist/seeds/index.d.ts +4 -0
  38. package/dist/seeds/index.d.ts.map +1 -1
  39. package/dist/seeds/index.js +2 -1103
  40. package/dist/seeds/omnia.d.ts +12 -0
  41. package/dist/seeds/omnia.d.ts.map +1 -0
  42. package/dist/seeds/prism.d.ts +12 -0
  43. package/dist/seeds/prism.d.ts.map +1 -0
  44. package/dist/seeds--fLhoBaG.cjs +1762 -0
  45. package/dist/seeds--fLhoBaG.cjs.map +1 -0
  46. package/dist/seeds-ihozTw4J.js +1703 -0
  47. package/dist/seeds-ihozTw4J.js.map +1 -0
  48. package/package.json +1 -1
  49. package/dist/seeds/index.cjs.map +0 -1
  50. package/dist/seeds/index.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"operations-D-RB67WP.cjs","names":[],"sources":["../src/gpu/detect.ts","../src/gpu/types.ts","../src/gpu/dispatch.ts","../src/gpu/kernels/spmv/kernel.ts","../src/gpu/kernels/pagerank/kernel.ts","../src/gpu/kernels/jaccard/kernel.ts","../src/gpu/kernels/degree-histogram/kernel.ts","../src/gpu/operations.ts"],"sourcesContent":["/**\n * WebGPU availability detection for browser and Node.js environments.\n *\n * This module provides runtime detection of WebGPU support without\n * requiring any polyfills or runtime dependencies.\n */\n\nimport type { GPUDetectionResult } from \"./types\";\n\n/**\n * Detect WebGPU availability in the current environment.\n *\n * Checks for:\n * - Browser: navigator.gpu\n * - Node.js: global GPU constructor (Node.js 21+ with --experimental-webgpu)\n * - Deno: global GPU constructor\n *\n * @returns Detection result with availability status and reason\n */\nexport function detectWebGPU(): GPUDetectionResult {\n\t// Check for browser WebGPU API\n\tif (typeof navigator !== \"undefined\" && \"gpu\" in navigator) {\n\t\treturn { available: true };\n\t}\n\n\t// Check for Node.js / Deno global GPU\n\tif (typeof globalThis !== \"undefined\" && \"GPU\" in globalThis) {\n\t\treturn { available: true };\n\t}\n\n\t// WebGPU not available\n\tconst reasons: string[] = [];\n\n\tif (typeof navigator === \"undefined\" && typeof globalThis === \"undefined\") {\n\t\treasons.push(\"no global scope detected\");\n\t} else if (typeof navigator !== \"undefined\" && !(\"gpu\" in navigator)) {\n\t\treasons.push(\"navigator.gpu not present (browser may not support WebGPU)\");\n\t} else if (typeof globalThis !== \"undefined\" && !(\"GPU\" in globalThis)) {\n\t\treasons.push(\n\t\t\t\"global GPU not present (Node.js requires v21+ with --experimental-webgpu flag)\",\n\t\t);\n\t}\n\n\treturn {\n\t\tavailable: false,\n\t\treason: reasons.length > 0 ? reasons.join(\"; \") : \"unknown environment\",\n\t};\n}\n\n/**\n * Check if WebGPU is available (convenience function).\n *\n * @returns true if WebGPU is available, false otherwise\n */\nexport function isWebGPUAvailable(): boolean {\n\treturn detectWebGPU().available;\n}\n\n/**\n * Assert that WebGPU is available, throwing an error if not.\n *\n * @throws Error if WebGPU is not available\n */\nexport function assertWebGPUAvailable(): void {\n\tconst result = detectWebGPU();\n\tif (!result.available) {\n\t\tthrow new Error(\n\t\t\t`WebGPU required but not available: ${result.reason ?? \"unknown reason\"}`,\n\t\t);\n\t}\n}\n","/**\n * Type definitions for the WebGPU compute backend.\n *\n * These types define the backend selection options and result types\n * for GPU-accelerated graph operations.\n */\n\nimport type { GraphwiseGPURoot } from \"./root\";\n\n/**\n * Backend selection for compute operations.\n *\n * - 'cpu': Synchronous CPU implementation (default, always available)\n * - 'gpu': Async GPU implementation (throws if WebGPU unavailable)\n * - 'auto': Async, detect WebGPU at runtime, fall back to CPU silently\n */\nexport type ComputeBackend = \"auto\" | \"gpu\" | \"cpu\";\n\n/**\n * Result of WebGPU availability detection.\n */\nexport interface GPUDetectionResult {\n\t/** Whether WebGPU is available in the current environment */\n\treadonly available: boolean;\n\t/** Human-readable reason if unavailable */\n\treadonly reason?: string;\n}\n\n/**\n * Error thrown when GPU backend is requested but unavailable.\n */\nexport class GPUNotAvailableError extends Error {\n\tpublic constructor(reason: string) {\n\t\tsuper(`WebGPU not available: ${reason}`);\n\t\tthis.name = \"GPUNotAvailableError\";\n\t}\n}\n\n/**\n * Result wrapper for GPU operations that may fall back to CPU.\n */\nexport interface ComputeResult<T> {\n\t/** The computed result value */\n\treadonly value: T;\n\t/** Which backend was actually used */\n\treadonly backend: \"gpu\" | \"cpu\";\n\t/** Time taken in milliseconds (optional, for profiling) */\n\treadonly elapsedMs?: number;\n}\n\n/**\n * Configuration options for GPU compute operations.\n */\nexport interface GPUComputeOptions {\n\t/** Backend selection: 'auto', 'gpu', or 'cpu' */\n\treadonly backend?: ComputeBackend;\n\t/** Optional TypeGPU root to reuse (avoids device acquisition overhead) */\n\treadonly root?: GraphwiseGPURoot;\n}\n","/**\n * Backend selection and dispatch utilities for GPU compute operations.\n *\n * Provides the `withBackend` function that handles auto/gpu/cpu backend\n * selection with timing and fallback logic.\n *\n * @module gpu/dispatch\n */\n\nimport { detectWebGPU } from \"./detect\";\nimport {\n\tGPUNotAvailableError,\n\ttype ComputeBackend,\n\ttype ComputeResult,\n} from \"./types\";\nimport type { GraphwiseGPURoot } from \"./root\";\n\n/**\n * Options for backend dispatch.\n */\nexport interface DispatchOptions {\n\t/** Backend selection: 'auto', 'gpu', or 'cpu' */\n\treadonly backend?: ComputeBackend | undefined;\n\t/** Optional pre-initialised TypeGPU root */\n\treadonly root?: GraphwiseGPURoot | undefined;\n\t/** Optional abort signal for cancellation */\n\treadonly signal?: AbortSignal | undefined;\n}\n\n/**\n * CPU compute function type.\n */\nexport type CPUFunction<T> = () => T;\n\n/**\n * GPU compute function type.\n */\nexport type GPUFunction<T> = (root: GraphwiseGPURoot) => Promise<T> | T;\n\n/**\n * Execute a compute operation with automatic backend selection.\n *\n * @param options - Backend selection and cancellation options\n * @param cpuFn - CPU fallback implementation\n * @param gpuFn - GPU implementation (receives TypeGPU root)\n * @returns Compute result with backend used and timing\n */\nexport async function withBackend<T>(\n\toptions: DispatchOptions,\n\tcpuFn: CPUFunction<T>,\n\tgpuFn: GPUFunction<T>,\n): Promise<ComputeResult<T>> {\n\tconst backend = options.backend ?? \"auto\";\n\n\t// Check for cancellation\n\tif (options.signal?.aborted === true) {\n\t\tthrow new DOMException(\"Operation aborted\", \"AbortError\");\n\t}\n\n\t// CPU backend - synchronous, always available\n\tif (backend === \"cpu\") {\n\t\tconst start = performance.now();\n\t\tconst value = cpuFn();\n\t\tconst elapsedMs = performance.now() - start;\n\t\treturn { value, backend: \"cpu\", elapsedMs };\n\t}\n\n\t// GPU backend - requires WebGPU\n\tif (backend === \"gpu\") {\n\t\tconst detection = detectWebGPU();\n\t\tif (!detection.available) {\n\t\t\tthrow new GPUNotAvailableError(detection.reason ?? \"Unknown reason\");\n\t\t}\n\n\t\tconst root = options.root;\n\t\tif (root === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t\"GPU backend requires a GraphwiseGPURoot. Pass one via options.root or use backend: 'auto'.\",\n\t\t\t);\n\t\t}\n\n\t\tconst start = performance.now();\n\t\tconst value = await gpuFn(root);\n\t\tconst elapsedMs = performance.now() - start;\n\t\treturn { value, backend: \"gpu\", elapsedMs };\n\t}\n\n\t// Auto backend - detect WebGPU, fall back to CPU\n\tconst detection = detectWebGPU();\n\n\t// No WebGPU available - use CPU\n\tif (!detection.available) {\n\t\tconst start = performance.now();\n\t\tconst value = cpuFn();\n\t\tconst elapsedMs = performance.now() - start;\n\t\treturn { value, backend: \"cpu\", elapsedMs };\n\t}\n\n\t// WebGPU available but no root provided - use CPU\n\tconst root = options.root;\n\tif (root === undefined) {\n\t\tconst start = performance.now();\n\t\tconst value = cpuFn();\n\t\tconst elapsedMs = performance.now() - start;\n\t\treturn { value, backend: \"cpu\", elapsedMs };\n\t}\n\n\t// WebGPU available with root - use GPU\n\tconst start = performance.now();\n\tconst value = await gpuFn(root);\n\tconst elapsedMs = performance.now() - start;\n\treturn { value, backend: \"gpu\", elapsedMs };\n}\n","/**\n * TypeGPU compute kernel for Sparse Matrix-Vector Multiplication (SpMV).\n *\n * Computes y = A * x where A is a sparse matrix in CSR format.\n * Uses TypeGPU's compute pipeline for parallel GPU execution.\n *\n * @module gpu/kernels/spmv/kernel\n */\n\nimport tgpu, { d, type StorageFlag, type TgpuBuffer } from \"typegpu\";\nimport type { TypedBufferGroup } from \"../../csr\";\nimport type { GraphwiseGPURoot } from \"../../root\";\n\n/**\n * Bind group layout for SpMV kernel.\n */\nconst SpMVLayout = tgpu.bindGroupLayout({\n\trowOffsets: { storage: d.arrayOf(d.u32) },\n\tcolIndices: { storage: d.arrayOf(d.u32) },\n\tvalues: { storage: d.arrayOf(d.f32) },\n\tx: { storage: d.arrayOf(d.f32) },\n\ty: { storage: d.arrayOf(d.f32), access: \"mutable\" },\n\tnodeCount: { uniform: d.u32 },\n\thasValues: { uniform: d.u32 },\n});\n\n/**\n * SpMV compute pipeline: y[row] = sum(A[row,col] * x[col]).\n *\n * Each thread computes one row of the output vector using the CSR format:\n * - rowOffsets: start/end indices for each row\n * - colIndices: column index for each non-zero entry\n * - values: edge weights (optional, defaults to 1.0)\n */\nconst spmvPipeline = (row: number): void => {\n\t\"use gpu\";\n\tconst start = SpMVLayout.$.rowOffsets[row] ?? 0;\n\tconst end = SpMVLayout.$.rowOffsets[row + 1] ?? 0;\n\n\tlet sum = 0.0;\n\tfor (let i = start; i < end; i = i + 1) {\n\t\tconst col = SpMVLayout.$.colIndices[i] ?? 0;\n\t\tconst weight =\n\t\t\tSpMVLayout.$.hasValues !== 0 ? (SpMVLayout.$.values[i] ?? 1.0) : 1.0;\n\t\tsum = sum + weight * (SpMVLayout.$.x[col] ?? 0.0);\n\t}\n\tSpMVLayout.$.y[row] = sum;\n};\n\n/**\n * Dispatch SpMV on GPU.\n *\n * @param root - TypeGPU root instance\n * @param csrBuffers - CSR matrix as typed buffers\n * @param x - Input vector buffer\n * @param y - Output vector buffer (mutable)\n * @param nodeCount - Number of nodes/rows\n * @param hasValues - Whether edge weights are present\n */\nexport function dispatchSpmv(\n\troot: GraphwiseGPURoot,\n\tcsrBuffers: TypedBufferGroup,\n\tx: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.f32>>> & StorageFlag,\n\ty: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.f32>>> & StorageFlag,\n\tnodeCount: number,\n\thasValues: boolean,\n): void {\n\tconst pipeline = root.createGuardedComputePipeline(spmvPipeline);\n\n\t// Create values buffer if not present (unweighted graph)\n\tconst valuesBuffer =\n\t\tcsrBuffers.values ??\n\t\troot\n\t\t\t.createBuffer(\n\t\t\t\td.arrayOf(d.f32, csrBuffers.edgeCount),\n\t\t\t\tnew Array(csrBuffers.edgeCount).fill(1.0),\n\t\t\t)\n\t\t\t.$usage(\"storage\");\n\n\t// Create uniform buffers for scalar values\n\tconst nodeCountBuffer = root.createBuffer(d.u32, nodeCount).$usage(\"uniform\");\n\tconst hasValuesBuffer = root\n\t\t.createBuffer(d.u32, hasValues ? 1 : 0)\n\t\t.$usage(\"uniform\");\n\n\tconst bindGroup = root.createBindGroup(SpMVLayout, {\n\t\trowOffsets: csrBuffers.rowOffsets,\n\t\tcolIndices: csrBuffers.colIndices,\n\t\tvalues: valuesBuffer,\n\t\tx,\n\t\ty,\n\t\tnodeCount: nodeCountBuffer,\n\t\thasValues: hasValuesBuffer,\n\t});\n\n\tpipeline.with(bindGroup).dispatchThreads(nodeCount);\n}\n\nexport { SpMVLayout };\n","/**\n * TypeGPU compute kernel for PageRank power iteration.\n *\n * Computes one iteration of PageRank:\n * r(v) = (1 - d)/N + d * sum(r(u) / deg_out(u)) for u -> v\n *\n * Uses TypeGPU's compute pipeline for parallel GPU execution.\n *\n * @module gpu/kernels/pagerank/kernel\n */\n\nimport tgpu, { d, type StorageFlag, type TgpuBuffer } from \"typegpu\";\nimport type { TypedBufferGroup } from \"../../csr\";\nimport type { GraphwiseGPURoot } from \"../../root\";\n\n/**\n * Bind group layout for PageRank kernel.\n */\nconst PageRankLayout = tgpu.bindGroupLayout({\n\trowOffsets: { storage: d.arrayOf(d.u32) },\n\tcolIndices: { storage: d.arrayOf(d.u32) },\n\tranks: { storage: d.arrayOf(d.f32) },\n\toutDegrees: { storage: d.arrayOf(d.u32) },\n\tnewRanks: { storage: d.arrayOf(d.f32), access: \"mutable\" },\n\tnodeCount: { uniform: d.u32 },\n\tdamping: { uniform: d.f32 },\n});\n\n/**\n * PageRank compute pipeline: one power iteration per dispatch.\n *\n * Each thread computes one node's new rank from incoming neighbours:\n * newRank[v] = (1 - damping) / N + damping * sum(rank[u] / outDegree[u])\n */\nconst pagerankPipeline = (node: number): void => {\n\t\"use gpu\";\n\tconst n = PageRankLayout.$.nodeCount ?? 0;\n\tconst damp = PageRankLayout.$.damping ?? 0.85;\n\n\tconst start = PageRankLayout.$.rowOffsets[node] ?? 0;\n\tconst end = PageRankLayout.$.rowOffsets[node + 1] ?? 0;\n\n\tlet contribution = 0.0;\n\tfor (let i = start; i < end; i = i + 1) {\n\t\tconst source = PageRankLayout.$.colIndices[i] ?? 0;\n\t\tconst deg = PageRankLayout.$.outDegrees[source] ?? 0;\n\t\tif (deg > 0) {\n\t\t\tconst rank = PageRankLayout.$.ranks[source] ?? 0.0;\n\t\t\tcontribution = contribution + rank / deg;\n\t\t}\n\t}\n\n\tconst teleport = (1.0 - damp) / n;\n\tPageRankLayout.$.newRanks[node] = teleport + damp * contribution;\n};\n\n/**\n * Dispatch one PageRank iteration on GPU.\n *\n * @param root - TypeGPU root instance\n * @param csrBuffers - CSR matrix as typed buffers (transpose graph: in-edges)\n * @param ranks - Current rank values buffer\n * @param outDegrees - Out-degree buffer for each node\n * @param newRanks - Output buffer for new rank values (mutable)\n * @param nodeCount - Number of nodes\n * @param damping - Damping factor (typically 0.85)\n */\nexport function dispatchPagerank(\n\troot: GraphwiseGPURoot,\n\tcsrBuffers: TypedBufferGroup,\n\tranks: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.f32>>> & StorageFlag,\n\toutDegrees: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.u32>>> &\n\t\tStorageFlag,\n\tnewRanks: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.f32>>> &\n\t\tStorageFlag,\n\tnodeCount: number,\n\tdamping: number,\n): void {\n\tconst pipeline = root.createGuardedComputePipeline(pagerankPipeline);\n\n\tconst nodeCountBuffer = root.createBuffer(d.u32, nodeCount).$usage(\"uniform\");\n\tconst dampingBuffer = root.createBuffer(d.f32, damping).$usage(\"uniform\");\n\n\tconst bindGroup = root.createBindGroup(PageRankLayout, {\n\t\trowOffsets: csrBuffers.rowOffsets,\n\t\tcolIndices: csrBuffers.colIndices,\n\t\tranks,\n\t\toutDegrees,\n\t\tnewRanks,\n\t\tnodeCount: nodeCountBuffer,\n\t\tdamping: dampingBuffer,\n\t});\n\n\tpipeline.with(bindGroup).dispatchThreads(nodeCount);\n}\n\nexport { PageRankLayout };\n","/**\n * TypeGPU compute kernel for batch Jaccard similarity.\n *\n * Computes Jaccard coefficient for multiple node pairs in parallel:\n * J(u, v) = |N(u) ∩ N(v)| / |N(u) ∪ N(v)|\n *\n * Uses binary search optimisation: iterate smaller neighbourhood, search in larger.\n *\n * @module gpu/kernels/jaccard/kernel\n */\n\nimport tgpu, { d, type StorageFlag, type TgpuBuffer } from \"typegpu\";\nimport type { TypedBufferGroup } from \"../../csr\";\nimport type { GraphwiseGPURoot } from \"../../root\";\n\n/**\n * Bind group layout for Jaccard kernel.\n */\nconst JaccardLayout = tgpu.bindGroupLayout({\n\trowOffsets: { storage: d.arrayOf(d.u32) },\n\tcolIndices: { storage: d.arrayOf(d.u32) },\n\tpairsU: { storage: d.arrayOf(d.u32) },\n\tpairsV: { storage: d.arrayOf(d.u32) },\n\tresults: { storage: d.arrayOf(d.f32), access: \"mutable\" },\n\tpairCount: { uniform: d.u32 },\n});\n\n/**\n * Jaccard compute pipeline: one thread per pair.\n *\n * For each pair (u, v):\n * - Count intersection by iterating smaller neighbourhood\n * - Binary search in larger neighbourhood\n * - Jaccard = intersection / (degU + degV - intersection)\n */\nconst jaccardPipeline = (pairIdx: number): void => {\n\t\"use gpu\";\n\tconst u = JaccardLayout.$.pairsU[pairIdx] ?? 0;\n\tconst v = JaccardLayout.$.pairsV[pairIdx] ?? 0;\n\n\tconst uStart = JaccardLayout.$.rowOffsets[u] ?? 0;\n\tconst uEnd = JaccardLayout.$.rowOffsets[u + 1] ?? 0;\n\tconst vStart = JaccardLayout.$.rowOffsets[v] ?? 0;\n\tconst vEnd = JaccardLayout.$.rowOffsets[v + 1] ?? 0;\n\n\tconst degU = uEnd - uStart;\n\tconst degV = vEnd - vStart;\n\n\t// Empty neighbourhoods → Jaccard = 0\n\tif (degU === 0 || degV === 0) {\n\t\tJaccardLayout.$.results[pairIdx] = 0.0;\n\t\treturn;\n\t}\n\n\t// Count intersection: iterate smaller, binary search in larger\n\tlet intersection = 0;\n\n\tif (degU <= degV) {\n\t\t// Iterate u's neighbours, search in v's\n\t\tfor (let i = uStart; i < uEnd; i = i + 1) {\n\t\t\tconst neighbour = JaccardLayout.$.colIndices[i] ?? 0;\n\t\t\t// Binary search in v's neighbourhood\n\t\t\tlet lo = vStart;\n\t\t\tlet hi = vEnd;\n\t\t\twhile (lo < hi) {\n\t\t\t\tconst mid = lo + (hi - lo) / 2;\n\t\t\t\tconst midVal = JaccardLayout.$.colIndices[mid] ?? 0;\n\t\t\t\tif (midVal === neighbour) {\n\t\t\t\t\tintersection = intersection + 1;\n\t\t\t\t\tlo = hi; // break\n\t\t\t\t} else if (midVal < neighbour) {\n\t\t\t\t\tlo = mid + 1;\n\t\t\t\t} else {\n\t\t\t\t\thi = mid;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Iterate v's neighbours, search in u's\n\t\tfor (let i = vStart; i < vEnd; i = i + 1) {\n\t\t\tconst neighbour = JaccardLayout.$.colIndices[i] ?? 0;\n\t\t\t// Binary search in u's neighbourhood\n\t\t\tlet lo = uStart;\n\t\t\tlet hi = uEnd;\n\t\t\twhile (lo < hi) {\n\t\t\t\tconst mid = lo + (hi - lo) / 2;\n\t\t\t\tconst midVal = JaccardLayout.$.colIndices[mid] ?? 0;\n\t\t\t\tif (midVal === neighbour) {\n\t\t\t\t\tintersection = intersection + 1;\n\t\t\t\t\tlo = hi; // break\n\t\t\t\t} else if (midVal < neighbour) {\n\t\t\t\t\tlo = mid + 1;\n\t\t\t\t} else {\n\t\t\t\t\thi = mid;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tconst unionSize = degU + degV - intersection;\n\tJaccardLayout.$.results[pairIdx] = intersection / unionSize;\n};\n\n/**\n * Dispatch batch Jaccard on GPU.\n *\n * @param root - TypeGPU root instance\n * @param csrBuffers - CSR matrix as typed buffers\n * @param pairsU - First node of each pair (u32 array)\n * @param pairsV - Second node of each pair (u32 array)\n * @param results - Output Jaccard coefficients (f32 array, mutable)\n * @param pairCount - Number of pairs to compute\n */\nexport function dispatchJaccard(\n\troot: GraphwiseGPURoot,\n\tcsrBuffers: TypedBufferGroup,\n\tpairsU: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.u32>>> & StorageFlag,\n\tpairsV: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.u32>>> & StorageFlag,\n\tresults: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.f32>>> & StorageFlag,\n\tpairCount: number,\n): void {\n\tconst pipeline = root.createGuardedComputePipeline(jaccardPipeline);\n\n\tconst pairCountBuffer = root.createBuffer(d.u32, pairCount).$usage(\"uniform\");\n\n\tconst bindGroup = root.createBindGroup(JaccardLayout, {\n\t\trowOffsets: csrBuffers.rowOffsets,\n\t\tcolIndices: csrBuffers.colIndices,\n\t\tpairsU,\n\t\tpairsV,\n\t\tresults,\n\t\tpairCount: pairCountBuffer,\n\t});\n\n\tpipeline.with(bindGroup).dispatchThreads(pairCount);\n}\n\nexport { JaccardLayout };\n","/**\n * TypeGPU compute kernel for degree computation.\n *\n * Computes degree per node from CSR row offsets.\n * Note: Histogram aggregation requires atomic operations or CPU reduction.\n *\n * @module gpu/kernels/degree-histogram/kernel\n */\n\nimport tgpu, { d, type StorageFlag, type TgpuBuffer } from \"typegpu\";\nimport type { TypedBufferGroup } from \"../../csr\";\nimport type { GraphwiseGPURoot } from \"../../root\";\n\n/**\n * Bind group layout for degree kernel.\n */\nconst DegreeLayout = tgpu.bindGroupLayout({\n\trowOffsets: { storage: d.arrayOf(d.u32) },\n\tdegrees: { storage: d.arrayOf(d.u32), access: \"mutable\" },\n\tnodeCount: { uniform: d.u32 },\n});\n\n/**\n * Degree compute pipeline: compute degree for each node.\n *\n * Each thread computes one node's degree from CSR row offsets:\n * degree[node] = rowOffsets[node+1] - rowOffsets[node]\n */\nconst degreePipeline = (node: number): void => {\n\t\"use gpu\";\n\tconst n = DegreeLayout.$.nodeCount ?? 0;\n\n\tif (node >= n) {\n\t\treturn;\n\t}\n\n\tconst start = DegreeLayout.$.rowOffsets[node] ?? 0;\n\tconst end = DegreeLayout.$.rowOffsets[node + 1] ?? 0;\n\tconst deg = end - start;\n\n\tDegreeLayout.$.degrees[node] = deg;\n};\n\n/**\n * Dispatch degree computation on GPU.\n *\n * Note: This computes per-node degrees. Histogram aggregation should be\n * done on CPU or with a separate reduction kernel.\n *\n * @param root - TypeGPU root instance\n * @param csrBuffers - CSR matrix as typed buffers\n * @param degrees - Output degree array (u32, mutable)\n * @param nodeCount - Number of nodes\n */\nexport function dispatchDegreeHistogram(\n\troot: GraphwiseGPURoot,\n\tcsrBuffers: TypedBufferGroup,\n\tdegrees: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.u32>>> & StorageFlag,\n\tnodeCount: number,\n): void {\n\tconst pipeline = root.createGuardedComputePipeline(degreePipeline);\n\n\tconst nodeCountBuffer = root.createBuffer(d.u32, nodeCount).$usage(\"uniform\");\n\n\tconst bindGroup = root.createBindGroup(DegreeLayout, {\n\t\trowOffsets: csrBuffers.rowOffsets,\n\t\tdegrees,\n\t\tnodeCount: nodeCountBuffer,\n\t});\n\n\tpipeline.with(bindGroup).dispatchThreads(nodeCount);\n}\n\nexport { DegreeLayout };\n","/**\n * High-level GPU operations for graph algorithms.\n *\n * These functions accept ReadableGraph instances and handle CSR conversion\n * internally, providing a simple API for GPU-accelerated graph operations.\n *\n * @module gpu/operations\n */\n\nimport type { NodeData, EdgeData, NodeId, ReadableGraph } from \"../graph\";\nimport type { MIVariantName } from \"../ranking/mi/types\";\nimport type { ComputeResult, GPUComputeOptions } from \"./types\";\nimport { withBackend, type DispatchOptions } from \"./dispatch\";\nimport { graphToCSR, csrToTypedBuffers, type CSRMatrix } from \"./csr\";\nimport { dispatchSpmv } from \"./kernels/spmv/kernel\";\nimport { dispatchPagerank } from \"./kernels/pagerank/kernel\";\nimport { dispatchJaccard } from \"./kernels/jaccard/kernel\";\nimport { dispatchDegreeHistogram } from \"./kernels/degree-histogram/kernel\";\nimport {\n\tintersectionBatch,\n\tjaccardFromIntersection,\n\tcosineFromIntersection,\n\tsorensenDiceFromIntersection,\n\toverlapFromIntersection,\n\thubPromotedFromIntersection,\n\ttype IntersectionResult,\n} from \"./kernels/intersection/logic\";\nimport type { GraphwiseGPURoot } from \"./root\";\nimport { d } from \"typegpu\";\n// clustering helper not imported; local implementations used below\n\n/**\n * Degree statistics from histogram computation.\n */\nexport interface DegreeStats {\n\t/** Minimum degree in the graph */\n\treadonly min: number;\n\t/** Maximum degree in the graph */\n\treadonly max: number;\n\t/** Average degree */\n\treadonly mean: number;\n\t/** Histogram of degree frequencies (index = degree, value = count) */\n\treadonly histogram: readonly number[];\n}\n\n/**\n * Sparse matrix-vector multiply on GPU.\n *\n * Computes y = A * x where A is the graph adjacency matrix in CSR format.\n *\n * @param graph - Input graph\n * @param x - Input vector (must have length = graph.nodeCount)\n * @param options - Compute options (backend, root, signal)\n * @returns Result vector y\n */\nexport async function gpuSpmv<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tx: Float32Array,\n\toptions?: GPUComputeOptions & { signal?: AbortSignal },\n): Promise<ComputeResult<Float32Array>> {\n\tconst nodeCount = graph.nodeCount;\n\n\tif (x.length !== nodeCount) {\n\t\tthrow new Error(\n\t\t\t`Input vector length (${String(x.length)}) must match node count (${String(nodeCount)})`,\n\t\t);\n\t}\n\n\tconst cpuFn = (): Float32Array => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst y = new Float32Array(nodeCount);\n\n\t\tfor (let row = 0; row < nodeCount; row++) {\n\t\t\tconst start = csr.rowOffsets[row] ?? 0;\n\t\t\tconst end = csr.rowOffsets[row + 1] ?? 0;\n\t\t\tlet sum = 0;\n\n\t\t\tfor (let i = start; i < end; i++) {\n\t\t\t\tconst col = csr.colIndices[i] ?? 0;\n\t\t\t\tconst weight = csr.values?.[i] ?? 1;\n\t\t\t\tsum += weight * (x[col] ?? 0);\n\t\t\t}\n\n\t\t\ty[row] = sum;\n\t\t}\n\n\t\treturn y;\n\t};\n\n\tconst gpuFn = async (root: GraphwiseGPURoot): Promise<Float32Array> => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst csrBuffers = csrToTypedBuffers(root, csr);\n\n\t\tconst xBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.f32, nodeCount), Array.from(x))\n\t\t\t.$usage(\"storage\");\n\n\t\tconst yBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.f32, nodeCount))\n\t\t\t.$usage(\"storage\");\n\n\t\tdispatchSpmv(\n\t\t\troot,\n\t\t\tcsrBuffers,\n\t\t\txBuffer,\n\t\t\tyBuffer,\n\t\t\tnodeCount,\n\t\t\tcsr.values !== undefined,\n\t\t);\n\n\t\tconst result = await yBuffer.read();\n\t\treturn new Float32Array(result);\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n\n/**\n * PageRank via GPU-accelerated power iteration.\n *\n * @param graph - Input graph (will be converted to transpose CSR for in-edges)\n * @param options - Compute options plus damping factor and iteration count\n * @returns PageRank scores for each node\n */\nexport async function gpuPageRank<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\toptions?: GPUComputeOptions & {\n\t\tdamping?: number;\n\t\titerations?: number;\n\t\tsignal?: AbortSignal;\n\t},\n): Promise<ComputeResult<Float32Array>> {\n\tconst nodeCount = graph.nodeCount;\n\tconst damping = options?.damping ?? 0.85;\n\tconst iterations = options?.iterations ?? 20;\n\n\tconst cpuFn = (): Float32Array => {\n\t\t// Build transpose CSR (in-edges) for PageRank\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst ranks = new Float32Array(nodeCount).fill(1 / nodeCount);\n\t\tconst outDegrees = new Uint32Array(nodeCount);\n\n\t\t// Compute out-degrees\n\t\tfor (let i = 0; i < nodeCount; i++) {\n\t\t\toutDegrees[i] = (csr.rowOffsets[i + 1] ?? 0) - (csr.rowOffsets[i] ?? 0);\n\t\t}\n\n\t\t// Power iteration\n\t\tfor (let iter = 0; iter < iterations; iter++) {\n\t\t\tconst newRanks = new Float32Array(nodeCount);\n\n\t\t\tfor (let v = 0; v < nodeCount; v++) {\n\t\t\t\tconst start = csr.rowOffsets[v] ?? 0;\n\t\t\t\tconst end = csr.rowOffsets[v + 1] ?? 0;\n\t\t\t\tlet contribution = 0;\n\n\t\t\t\tfor (let i = start; i < end; i++) {\n\t\t\t\t\tconst source = csr.colIndices[i] ?? 0;\n\t\t\t\t\tconst deg = outDegrees[source] ?? 0;\n\t\t\t\t\tif (deg > 0) {\n\t\t\t\t\t\tcontribution += (ranks[source] ?? 0) / deg;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tnewRanks[v] = (1 - damping) / nodeCount + damping * contribution;\n\t\t\t}\n\n\t\t\tranks.set(newRanks);\n\t\t}\n\n\t\treturn ranks;\n\t};\n\n\tconst gpuFn = async (root: GraphwiseGPURoot): Promise<Float32Array> => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst csrBuffers = csrToTypedBuffers(root, csr);\n\n\t\t// Compute out-degrees\n\t\tconst outDegrees = new Uint32Array(nodeCount);\n\t\tfor (let i = 0; i < nodeCount; i++) {\n\t\t\toutDegrees[i] = (csr.rowOffsets[i + 1] ?? 0) - (csr.rowOffsets[i] ?? 0);\n\t\t}\n\n\t\tconst outDegreesBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, nodeCount), Array.from(outDegrees))\n\t\t\t.$usage(\"storage\");\n\n\t\tconst ranksBuffer = root\n\t\t\t.createBuffer(\n\t\t\t\td.arrayOf(d.f32, nodeCount),\n\t\t\t\tArray.from(new Float32Array(nodeCount).fill(1 / nodeCount)),\n\t\t\t)\n\t\t\t.$usage(\"storage\");\n\n\t\tconst newRanksBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.f32, nodeCount))\n\t\t\t.$usage(\"storage\");\n\n\t\t// Power iteration\n\t\tfor (let iter = 0; iter < iterations; iter++) {\n\t\t\tdispatchPagerank(\n\t\t\t\troot,\n\t\t\t\tcsrBuffers,\n\t\t\t\tranksBuffer,\n\t\t\t\toutDegreesBuffer,\n\t\t\t\tnewRanksBuffer,\n\t\t\t\tnodeCount,\n\t\t\t\tdamping,\n\t\t\t);\n\n\t\t\t// Swap buffers by copying data back\n\t\t\tconst newRanks = await newRanksBuffer.read();\n\t\t\tranksBuffer.write(Array.from(newRanks));\n\t\t}\n\n\t\tconst result = await ranksBuffer.read();\n\t\treturn new Float32Array(result);\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n\n/**\n * Batch Jaccard similarity for node pairs on GPU.\n *\n * @param graph - Input graph\n * @param pairs - Array of [u, v] node ID pairs\n * @param options - Compute options\n * @returns Jaccard coefficients for each pair\n */\nexport async function gpuJaccardBatch<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpairs: readonly [NodeId, NodeId][],\n\toptions?: GPUComputeOptions & { signal?: AbortSignal },\n): Promise<ComputeResult<Float32Array>> {\n\tconst pairCount = pairs.length;\n\tconst { indexMap } = graphToCSR(graph);\n\n\tconst cpuFn = (): Float32Array => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst results = new Float32Array(pairCount);\n\n\t\tfor (let p = 0; p < pairCount; p++) {\n\t\t\tconst pair = pairs[p];\n\t\t\tif (pair === undefined) continue;\n\t\t\tconst [u, v] = pair;\n\t\t\tconst uIdx = indexMap.nodeToIndex.get(u);\n\t\t\tconst vIdx = indexMap.nodeToIndex.get(v);\n\n\t\t\tif (uIdx === undefined || vIdx === undefined) {\n\t\t\t\tresults[p] = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst uStart = csr.rowOffsets[uIdx] ?? 0;\n\t\t\tconst uEnd = csr.rowOffsets[uIdx + 1] ?? 0;\n\t\t\tconst vStart = csr.rowOffsets[vIdx] ?? 0;\n\t\t\tconst vEnd = csr.rowOffsets[vIdx + 1] ?? 0;\n\n\t\t\tconst uNeighbours = new Set(\n\t\t\t\tArray.from(csr.colIndices.slice(uStart, uEnd)),\n\t\t\t);\n\t\t\tconst vNeighbours = new Set(\n\t\t\t\tArray.from(csr.colIndices.slice(vStart, vEnd)),\n\t\t\t);\n\n\t\t\tlet intersection = 0;\n\t\t\tfor (const n of uNeighbours) {\n\t\t\t\tif (vNeighbours.has(n)) {\n\t\t\t\t\tintersection++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst union = uNeighbours.size + vNeighbours.size - intersection;\n\t\t\tresults[p] = union > 0 ? intersection / union : 0;\n\t\t}\n\n\t\treturn results;\n\t};\n\n\tconst gpuFn = async (root: GraphwiseGPURoot): Promise<Float32Array> => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst csrBuffers = csrToTypedBuffers(root, csr);\n\n\t\tconst pairsU = new Uint32Array(pairCount);\n\t\tconst pairsV = new Uint32Array(pairCount);\n\n\t\tfor (let i = 0; i < pairCount; i++) {\n\t\t\tconst pair = pairs[i];\n\t\t\tif (pair === undefined) continue;\n\t\t\tconst uIdx = indexMap.nodeToIndex.get(pair[0]);\n\t\t\tconst vIdx = indexMap.nodeToIndex.get(pair[1]);\n\t\t\tpairsU[i] = uIdx ?? 0;\n\t\t\tpairsV[i] = vIdx ?? 0;\n\t\t}\n\n\t\tconst pairsUBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, pairCount), Array.from(pairsU))\n\t\t\t.$usage(\"storage\");\n\n\t\tconst pairsVBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, pairCount), Array.from(pairsV))\n\t\t\t.$usage(\"storage\");\n\n\t\tconst resultsBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.f32, pairCount))\n\t\t\t.$usage(\"storage\");\n\n\t\tdispatchJaccard(\n\t\t\troot,\n\t\t\tcsrBuffers,\n\t\t\tpairsUBuffer,\n\t\t\tpairsVBuffer,\n\t\t\tresultsBuffer,\n\t\t\tpairCount,\n\t\t);\n\n\t\tconst result = await resultsBuffer.read();\n\t\treturn new Float32Array(result);\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n\n/**\n * BFS level assignment from source node on GPU.\n *\n * Note: Full GPU BFS requires atomics not yet available in TypeGPU.\n * This implementation uses CPU for now but maintains the API.\n *\n * @param graph - Input graph\n * @param source - Source node ID\n * @param options - Compute options\n * @returns BFS level for each node (-1 for unreachable)\n */\nexport async function gpuBfsLevels<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: NodeId,\n\toptions?: GPUComputeOptions & { signal?: AbortSignal },\n): Promise<ComputeResult<Int32Array>> {\n\tconst nodeCount = graph.nodeCount;\n\tconst { indexMap } = graphToCSR(graph);\n\n\tconst cpuFn = (): Int32Array => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst levels = new Int32Array(nodeCount).fill(-1);\n\t\tconst visited = new Uint8Array(nodeCount);\n\n\t\t// Find source index\n\t\tconst sourceIndex = indexMap.nodeToIndex.get(source);\n\t\tif (sourceIndex === undefined) {\n\t\t\tthrow new Error(`Source node ${source} not found in graph`);\n\t\t}\n\n\t\tconst queue: number[] = [sourceIndex];\n\t\tlevels[sourceIndex] = 0;\n\t\tvisited[sourceIndex] = 1;\n\n\t\twhile (queue.length > 0) {\n\t\t\tconst current = queue.shift();\n\t\t\tif (current === undefined) break;\n\t\t\tconst currentLevel = levels[current] ?? 0;\n\n\t\t\tconst start = csr.rowOffsets[current] ?? 0;\n\t\t\tconst end = csr.rowOffsets[current + 1] ?? 0;\n\n\t\t\tfor (let i = start; i < end; i++) {\n\t\t\t\tconst neighbour = csr.colIndices[i] ?? 0;\n\t\t\t\tif (visited[neighbour] === 0) {\n\t\t\t\t\tvisited[neighbour] = 1;\n\t\t\t\t\tlevels[neighbour] = currentLevel + 1;\n\t\t\t\t\tqueue.push(neighbour);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn levels;\n\t};\n\n\tconst gpuFn = (_root: GraphwiseGPURoot): Int32Array => {\n\t\t// BFS requires atomics not yet in TypeGPU - use CPU\n\t\t// _root is intentionally unused as we fall back to CPU implementation\n\t\tvoid _root;\n\t\treturn cpuFn();\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n\n/**\n * Degree histogram and statistics on GPU.\n *\n * @param graph - Input graph\n * @param options - Compute options\n * @returns Degree statistics with histogram\n */\nexport async function gpuDegreeHistogram<\n\tN extends NodeData,\n\tE extends EdgeData,\n>(\n\tgraph: ReadableGraph<N, E>,\n\toptions?: GPUComputeOptions & { signal?: AbortSignal },\n): Promise<ComputeResult<DegreeStats>> {\n\tconst nodeCount = graph.nodeCount;\n\n\tconst cpuFn = (): DegreeStats => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst degrees = new Uint32Array(nodeCount);\n\n\t\tfor (let i = 0; i < nodeCount; i++) {\n\t\t\tdegrees[i] = (csr.rowOffsets[i + 1] ?? 0) - (csr.rowOffsets[i] ?? 0);\n\t\t}\n\n\t\tconst max = degrees.length > 0 ? Math.max(...degrees) : 0;\n\t\tconst histogram: number[] = Array.from({ length: max + 1 }, () => 0);\n\n\t\tlet sum = 0;\n\t\tlet min = Infinity;\n\n\t\tfor (const d of degrees) {\n\t\t\thistogram[d] = (histogram[d] ?? 0) + 1;\n\t\t\tsum += d;\n\t\t\tif (d < min) min = d;\n\t\t}\n\n\t\tif (degrees.length === 0) {\n\t\t\tmin = 0;\n\t\t}\n\n\t\treturn {\n\t\t\tmin,\n\t\t\tmax,\n\t\t\tmean: nodeCount > 0 ? sum / nodeCount : 0,\n\t\t\thistogram,\n\t\t};\n\t};\n\n\tconst gpuFn = async (root: GraphwiseGPURoot): Promise<DegreeStats> => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst csrBuffers = csrToTypedBuffers(root, csr);\n\n\t\tconst degreesBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, nodeCount))\n\t\t\t.$usage(\"storage\");\n\n\t\tdispatchDegreeHistogram(root, csrBuffers, degreesBuffer, nodeCount);\n\n\t\tconst degrees = await degreesBuffer.read();\n\n\t\t// Build histogram on CPU (atomic reduction not in TypeGPU yet)\n\t\tconst max = degrees.length > 0 ? Math.max(...degrees) : 0;\n\t\tconst histogram: number[] = Array.from({ length: max + 1 }, () => 0);\n\n\t\tlet sum = 0;\n\t\tlet min = Infinity;\n\n\t\tfor (const d of degrees) {\n\t\t\thistogram[d] = (histogram[d] ?? 0) + 1;\n\t\t\tsum += d;\n\t\t\tif (d < min) min = d;\n\t\t}\n\n\t\tif (degrees.length === 0) {\n\t\t\tmin = 0;\n\t\t}\n\n\t\treturn {\n\t\t\tmin,\n\t\t\tmax,\n\t\t\tmean: nodeCount > 0 ? sum / nodeCount : 0,\n\t\t\thistogram,\n\t\t};\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n\n/**\n * Result of batch MI computation.\n */\nexport interface MIBatchResult {\n\t/** MI scores for each pair */\n\treadonly scores: Float32Array;\n\t/** Raw intersection counts for each pair */\n\treadonly intersections: Uint32Array;\n\t/** Size of first neighbourhood for each pair */\n\treadonly sizeUs: Uint32Array;\n\t/** Size of second neighbourhood for each pair */\n\treadonly sizeVs: Uint32Array;\n}\n\n/**\n * Batch MI computation for multiple node pairs on GPU.\n *\n * For Jaccard-family variants, uses the intersection kernel for raw counts\n * then applies the variant-specific formula on CPU.\n *\n * @param graph - Input graph\n * @param pairs - Array of [u, v] node ID pairs\n * @param variant - MI variant to compute (default: jaccard)\n * @param options - Compute options\n * @returns MI scores and raw intersection data for each pair\n */\nexport async function gpuMIBatch<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpairs: readonly (readonly [NodeId, NodeId])[],\n\tvariant: MIVariantName = \"jaccard\",\n\toptions?: GPUComputeOptions & { signal?: AbortSignal },\n): Promise<ComputeResult<MIBatchResult>> {\n\tconst pairCount = pairs.length;\n\tconst { csr, indexMap } = graphToCSR(graph);\n\n\tconst cpuFn = (): MIBatchResult => {\n\t\t// Convert node IDs to numeric indices, tracking validity\n\t\tconst indexPairs: (readonly [number, number])[] = [];\n\t\tconst validPair: boolean[] = [];\n\t\tfor (const pair of pairs) {\n\t\t\tconst uIdx = indexMap.nodeToIndex.get(pair[0]);\n\t\t\tconst vIdx = indexMap.nodeToIndex.get(pair[1]);\n\t\t\tif (uIdx !== undefined && vIdx !== undefined) {\n\t\t\t\tindexPairs.push([uIdx, vIdx]);\n\t\t\t\tvalidPair.push(true);\n\t\t\t} else {\n\t\t\t\t// Use sentinel values for invalid pairs\n\t\t\t\tindexPairs.push([0, 0]);\n\t\t\t\tvalidPair.push(false);\n\t\t\t}\n\t\t}\n\n\t\t// Run intersection kernel\n\t\tconst { intersections, sizeUs, sizeVs } = intersectionBatch(\n\t\t\tcsr.rowOffsets,\n\t\t\tcsr.colIndices,\n\t\t\tindexPairs,\n\t\t);\n\n\t\t// Compute MI scores based on variant\n\t\tconst scores = new Float32Array(pairCount);\n\t\tfor (let i = 0; i < pairCount; i++) {\n\t\t\t// Invalid pairs get score of 0\n\t\t\tif (validPair[i] !== true) {\n\t\t\t\tscores[i] = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst result: IntersectionResult = {\n\t\t\t\tintersection: intersections[i] ?? 0,\n\t\t\t\tsizeU: sizeUs[i] ?? 0,\n\t\t\t\tsizeV: sizeVs[i] ?? 0,\n\t\t\t};\n\t\t\tconst base = applyMIVariant(result, \"jaccard\");\n\t\t\t// Apply correction variants\n\t\t\tswitch (variant) {\n\t\t\t\tcase \"scale\": {\n\t\t\t\t\tconst rho = computeGraphDensity(csr);\n\t\t\t\t\tscores[i] = rho > 0 ? base / rho : base;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"skew\": {\n\t\t\t\t\tconst N = csr.rowOffsets.length - 1;\n\t\t\t\t\tconst degU = result.sizeU;\n\t\t\t\t\tconst degV = result.sizeV;\n\t\t\t\t\tconst w = Math.log(N / (degU + 1)) * Math.log(N / (degV + 1));\n\t\t\t\t\tscores[i] = base * w;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"span\": {\n\t\t\t\t\tconst clustering = computeClusteringCoefficients(csr);\n\t\t\t\t\tconst pair = pairs[i];\n\t\t\t\t\tconst u0 = pair ? indexMap.nodeToIndex.get(pair[0]) : undefined;\n\t\t\t\t\tconst v0 = pair ? indexMap.nodeToIndex.get(pair[1]) : undefined;\n\t\t\t\t\tconst cu = (u0 !== undefined ? clustering[u0] : undefined) ?? 0;\n\t\t\t\t\tconst cv = (v0 !== undefined ? clustering[v0] : undefined) ?? 0;\n\t\t\t\t\tscores[i] = base * (1 - Math.max(cu, cv));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tscores[i] = applyMIVariant(result, variant);\n\t\t\t}\n\t\t}\n\n\t\treturn { scores, intersections, sizeUs, sizeVs };\n\t};\n\n\t// GPU implementation uses same intersection kernel, dispatched via GPU when available\n\tconst gpuFn = async (root: GraphwiseGPURoot): Promise<MIBatchResult> => {\n\t\t// Prepare CSR buffers for GPU\n\t\tconst csrBuffers = csrToTypedBuffers(root, csr);\n\n\t\t// Convert node IDs to numeric indices for GPU buffers\n\t\tconst uArr = new Uint32Array(pairCount);\n\t\tconst vArr = new Uint32Array(pairCount);\n\t\tconst validPair: boolean[] = Array.from(\n\t\t\t{ length: pairCount },\n\t\t\t(): boolean => false,\n\t\t);\n\t\tfor (let i = 0; i < pairCount; i++) {\n\t\t\tconst p = pairs[i];\n\t\t\tconst uIdxRaw = p ? indexMap.nodeToIndex.get(p[0]) : undefined;\n\t\t\tconst vIdxRaw = p ? indexMap.nodeToIndex.get(p[1]) : undefined;\n\t\t\tconst uIdx = uIdxRaw ?? 0;\n\t\t\tconst vIdx = vIdxRaw ?? 0;\n\t\t\tif (uIdxRaw !== undefined && vIdxRaw !== undefined) {\n\t\t\t\tuArr[i] = uIdx;\n\t\t\t\tvArr[i] = vIdx;\n\t\t\t\tvalidPair[i] = true;\n\t\t\t} else {\n\t\t\t\tuArr[i] = 0;\n\t\t\t\tvArr[i] = 0;\n\t\t\t\tvalidPair[i] = false;\n\t\t\t}\n\t\t}\n\n\t\t// Create GPU buffers\n\t\tconst pairsUBuffer = root\n\t\t\t.createBuffer(\n\t\t\t\td.arrayOf(d.u32, pairCount),\n\t\t\t\t// TypeGPU type constraints are complex; TypedArrays are compatible with buffer initialization\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument\n\t\t\t\tArray.from(uArr) as any,\n\t\t\t)\n\t\t\t.$usage(\"storage\");\n\t\tconst pairsVBuffer = root\n\t\t\t.createBuffer(\n\t\t\t\td.arrayOf(d.u32, pairCount),\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument\n\t\t\t\tArray.from(vArr) as any,\n\t\t\t)\n\t\t\t.$usage(\"storage\");\n\n\t\tconst intersectionsBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, pairCount))\n\t\t\t.$usage(\"storage\");\n\t\tconst sizeUsBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, pairCount))\n\t\t\t.$usage(\"storage\");\n\t\tconst sizeVsBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, pairCount))\n\t\t\t.$usage(\"storage\");\n\n\t\tif (variant === \"adamic-adar\") {\n\t\t\t// Dispatch dedicated Adamic-Adar kernel which also writes raw counts\n\t\t\tconst resultsBuffer = root\n\t\t\t\t.createBuffer(d.arrayOf(d.f32, pairCount))\n\t\t\t\t.$usage(\"storage\");\n\n\t\t\tconst { dispatchAdamicAdar } =\n\t\t\t\tawait import(\"./kernels/adamic-adar/kernel.js\");\n\t\t\tdispatchAdamicAdar(\n\t\t\t\troot,\n\t\t\t\tcsrBuffers,\n\t\t\t\tpairsUBuffer,\n\t\t\t\tpairsVBuffer,\n\t\t\t\tresultsBuffer,\n\t\t\t\tintersectionsBuffer,\n\t\t\t\tsizeUsBuffer,\n\t\t\t\tsizeVsBuffer,\n\t\t\t\tpairCount,\n\t\t\t);\n\n\t\t\tconst scoresRaw = await resultsBuffer.read();\n\t\t\tconst intersectionsRaw = await intersectionsBuffer.read();\n\t\t\tconst sizeUsRaw = await sizeUsBuffer.read();\n\t\t\tconst sizeVsRaw = await sizeVsBuffer.read();\n\n\t\t\tconst scores = new Float32Array(scoresRaw);\n\t\t\tconst intersections = new Uint32Array(intersectionsRaw);\n\t\t\tconst sizeUs = new Uint32Array(sizeUsRaw);\n\t\t\tconst sizeVs = new Uint32Array(sizeVsRaw);\n\n\t\t\t// Zero-out invalid pairs\n\t\t\tfor (let i = 0; i < pairCount; i++) {\n\t\t\t\tif (validPair[i] !== true) {\n\t\t\t\t\tscores[i] = 0;\n\t\t\t\t\tintersections[i] = 0;\n\t\t\t\t\tsizeUs[i] = 0;\n\t\t\t\t\tsizeVs[i] = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { scores, intersections, sizeUs, sizeVs };\n\t\t} else {\n\t\t\t// Dispatch intersection kernel\n\t\t\tconst { dispatchIntersection } =\n\t\t\t\tawait import(\"./kernels/intersection/kernel.js\");\n\t\t\tdispatchIntersection(\n\t\t\t\troot,\n\t\t\t\tcsrBuffers,\n\t\t\t\tpairsUBuffer,\n\t\t\t\tpairsVBuffer,\n\t\t\t\tintersectionsBuffer,\n\t\t\t\tsizeUsBuffer,\n\t\t\t\tsizeVsBuffer,\n\t\t\t\tpairCount,\n\t\t\t);\n\n\t\t\t// Read back results\n\t\t\tconst intersectionsRaw = await intersectionsBuffer.read();\n\t\t\tconst sizeUsRaw = await sizeUsBuffer.read();\n\t\t\tconst sizeVsRaw = await sizeVsBuffer.read();\n\n\t\t\tconst intersections = new Uint32Array(intersectionsRaw);\n\t\t\tconst sizeUs = new Uint32Array(sizeUsRaw);\n\t\t\tconst sizeVs = new Uint32Array(sizeVsRaw);\n\n\t\t\t// Compute MI scores on CPU from raw counts (and apply GPU-side corrections)\n\t\t\tconst scores = new Float32Array(pairCount);\n\t\t\tif (variant === \"scale\" || variant === \"skew\" || variant === \"span\") {\n\t\t\t\t// Precompute helpers\n\t\t\t\tconst clustering =\n\t\t\t\t\tvariant === \"span\" ? computeClusteringCoefficients(csr) : undefined;\n\t\t\t\tconst N = csr.rowOffsets.length - 1;\n\t\t\t\tconst rho = variant === \"scale\" ? computeGraphDensity(csr) : undefined;\n\n\t\t\t\tfor (let i = 0; i < pairCount; i++) {\n\t\t\t\t\tif (validPair[i] !== true) {\n\t\t\t\t\t\tscores[i] = 0;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst result: IntersectionResult = {\n\t\t\t\t\t\tintersection: intersections[i] ?? 0,\n\t\t\t\t\t\tsizeU: sizeUs[i] ?? 0,\n\t\t\t\t\t\tsizeV: sizeVs[i] ?? 0,\n\t\t\t\t\t};\n\t\t\t\t\tconst base = applyMIVariant(result, \"jaccard\");\n\t\t\t\t\tswitch (variant) {\n\t\t\t\t\t\tcase \"scale\":\n\t\t\t\t\t\t\tif (rho !== undefined && rho > 0) scores[i] = base / rho;\n\t\t\t\t\t\t\telse scores[i] = base;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"skew\": {\n\t\t\t\t\t\t\tconst degU = result.sizeU;\n\t\t\t\t\t\t\tconst degV = result.sizeV;\n\t\t\t\t\t\t\tconst w = Math.log(N / (degU + 1)) * Math.log(N / (degV + 1));\n\t\t\t\t\t\t\tscores[i] = base * w;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase \"span\": {\n\t\t\t\t\t\t\tconst pair = pairs[i];\n\t\t\t\t\t\t\tconst uId = pair ? pair[0] : undefined;\n\t\t\t\t\t\t\tconst vId = pair ? pair[1] : undefined;\n\t\t\t\t\t\t\tconst uIdx =\n\t\t\t\t\t\t\t\tuId !== undefined ? indexMap.nodeToIndex.get(uId) : undefined;\n\t\t\t\t\t\t\tconst vIdx =\n\t\t\t\t\t\t\t\tvId !== undefined ? indexMap.nodeToIndex.get(vId) : undefined;\n\t\t\t\t\t\t\tconst cu = uIdx !== undefined ? (clustering?.[uIdx] ?? 0) : 0;\n\t\t\t\t\t\t\tconst cv = vIdx !== undefined ? (clustering?.[vIdx] ?? 0) : 0;\n\t\t\t\t\t\t\tscores[i] = base * (1 - Math.max(cu, cv));\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (let i = 0; i < pairCount; i++) {\n\t\t\t\t\tif (validPair[i] !== true) {\n\t\t\t\t\t\tscores[i] = 0;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst result: IntersectionResult = {\n\t\t\t\t\t\tintersection: intersections[i] ?? 0,\n\t\t\t\t\t\tsizeU: sizeUs[i] ?? 0,\n\t\t\t\t\t\tsizeV: sizeVs[i] ?? 0,\n\t\t\t\t\t};\n\t\t\t\t\tscores[i] = applyMIVariant(result, variant);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { scores, intersections, sizeUs, sizeVs };\n\t\t}\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n\n/**\n * Apply MI variant formula to intersection result.\n */\nfunction computeGraphDensity(csr: CSRMatrix): number {\n\tconst n = csr.rowOffsets.length - 1;\n\tconst m = csr.colIndices.length;\n\treturn n > 1 ? (2 * m) / (n * (n - 1)) : 0;\n}\n\nfunction computeClusteringCoefficients(csr: CSRMatrix): number[] {\n\t// Naive local clustering coefficient per node: 2 * number of closed triplets / (deg * (deg-1))\n\tconst n = csr.rowOffsets.length - 1;\n\tconst coeffs = new Array<number>(n).fill(0);\n\tfor (let v = 0; v < n; v++) {\n\t\tconst start = csr.rowOffsets[v] ?? 0;\n\t\tconst end = csr.rowOffsets[v + 1] ?? 0;\n\t\tconst deg = end - start;\n\t\tif (deg < 2) {\n\t\t\tcoeffs[v] = 0;\n\t\t\tcontinue;\n\t\t}\n\t\tconst neighbours = new Set(csr.colIndices.slice(start, end));\n\t\tlet links = 0;\n\t\tfor (const u of neighbours) {\n\t\t\tconst uStart = csr.rowOffsets[u] ?? 0;\n\t\t\tconst uEnd = csr.rowOffsets[u + 1] ?? 0;\n\t\t\tfor (let k = uStart; k < uEnd; k++) {\n\t\t\t\tconst colIdx = csr.colIndices[k] ?? 0;\n\t\t\t\tif (neighbours.has(colIdx)) links++;\n\t\t\t}\n\t\t}\n\t\t// each edge counted twice\n\t\tcoeffs[v] = (2 * links) / (deg * (deg - 1));\n\t}\n\treturn coeffs;\n}\n\nfunction applyMIVariant(\n\tresult: IntersectionResult,\n\tvariant: MIVariantName,\n): number {\n\tswitch (variant) {\n\t\tcase \"jaccard\":\n\t\t\treturn jaccardFromIntersection(result);\n\t\tcase \"cosine\":\n\t\t\treturn cosineFromIntersection(result);\n\t\tcase \"sorensen\":\n\t\t\treturn sorensenDiceFromIntersection(result);\n\t\tcase \"overlap-coefficient\":\n\t\t\treturn overlapFromIntersection(result);\n\t\tcase \"hub-promoted\":\n\t\t\treturn hubPromotedFromIntersection(result);\n\t\tcase \"resource-allocation\":\n\t\t\t// Resource allocation requires shared neighbour degrees\n\t\t\t// Fall back to Jaccard for now - dedicated kernel needed\n\t\t\treturn jaccardFromIntersection(result);\n\t\tcase \"adamic-adar\":\n\t\t\t// Adamic-Adar requires shared neighbour degrees\n\t\t\t// Fall back to Jaccard for now - dedicated kernel needed\n\t\t\treturn jaccardFromIntersection(result);\n\t\tcase \"scale\":\n\t\tcase \"skew\":\n\t\tcase \"span\":\n\t\tcase \"etch\":\n\t\tcase \"notch\":\n\t\tcase \"adaptive\":\n\t\t\t// Correction-based variants require additional data\n\t\t\t// Fall back to Jaccard for now\n\t\t\treturn jaccardFromIntersection(result);\n\t\tdefault:\n\t\t\treturn jaccardFromIntersection(result);\n\t}\n}\n\n/**\n * Result of K-means assignment step.\n */\nexport interface KMeansAssignResult {\n\t/** Assignment index for each point (0 to k-1) */\n\treadonly assignments: Uint32Array;\n\t/** Squared distance to assigned centroid for each point */\n\treadonly distances: Float32Array;\n}\n\n/**\n * Assign points to nearest centroids using GPU.\n *\n * For each point, computes distance to all centroids and assigns to nearest.\n * This is the main parallelizable operation in K-means clustering.\n *\n * @param points - Array of 3D points to assign\n * @param centroids - Array of 3D centroid coordinates\n * @param options - Compute options\n * @returns Assignment indices and distances\n */\nexport async function gpuKMeansAssign(\n\tpoints: readonly (readonly [number, number, number])[],\n\tcentroids: readonly (readonly [number, number, number])[],\n\toptions?: GPUComputeOptions & { signal?: AbortSignal },\n): Promise<ComputeResult<KMeansAssignResult>> {\n\tconst pointCount = points.length;\n\tconst k = centroids.length;\n\n\tconst cpuFn = (): KMeansAssignResult => {\n\t\tconst assignments = new Uint32Array(pointCount);\n\t\tconst distances = new Float32Array(pointCount);\n\n\t\tfor (let i = 0; i < pointCount; i++) {\n\t\t\tconst point = points[i];\n\t\t\tif (point === undefined) {\n\t\t\t\tassignments[i] = 0;\n\t\t\t\tdistances[i] = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst [px, py, pz] = point;\n\t\t\tlet minDist = Infinity;\n\t\t\tlet minIdx = 0;\n\n\t\t\tfor (let j = 0; j < k; j++) {\n\t\t\t\tconst centroid = centroids[j];\n\t\t\t\tif (centroid === undefined) continue;\n\n\t\t\t\tconst [cx, cy, cz] = centroid;\n\t\t\t\tconst dx = px - cx;\n\t\t\t\tconst dy = py - cy;\n\t\t\t\tconst dz = pz - cz;\n\t\t\t\tconst distSq = dx * dx + dy * dy + dz * dz;\n\n\t\t\t\tif (distSq < minDist) {\n\t\t\t\t\tminDist = distSq;\n\t\t\t\t\tminIdx = j;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tassignments[i] = minIdx;\n\t\t\tdistances[i] = minDist;\n\t\t}\n\n\t\treturn { assignments, distances };\n\t};\n\n\t// GPU implementation for larger datasets\n\tconst gpuFn = async (root: GraphwiseGPURoot): Promise<KMeansAssignResult> => {\n\t\t// For now, fall back to CPU for small datasets\n\t\t// GPU has overhead that makes it slower for small batches\n\t\tif (pointCount < 100) {\n\t\t\treturn cpuFn();\n\t\t}\n\n\t\tconst pointsBuffer = root\n\t\t\t.createBuffer(\n\t\t\t\td.arrayOf(d.vec3f, pointCount),\n\t\t\t\t// TypeGPU type constraints are complex; TypedArrays are compatible with buffer initialization\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument\n\t\t\t\tArray.from(points) as any,\n\t\t\t)\n\t\t\t.$usage(\"storage\");\n\n\t\tconst centroidsBuffer = root\n\t\t\t.createBuffer(\n\t\t\t\td.arrayOf(d.vec3f, k),\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument\n\t\t\t\tArray.from(centroids) as any,\n\t\t\t)\n\t\t\t.$usage(\"storage\");\n\n\t\tconst assignmentsBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, pointCount))\n\t\t\t.$usage(\"storage\");\n\n\t\tconst distancesBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.f32, pointCount))\n\t\t\t.$usage(\"storage\");\n\n\t\t// Dispatch assignment kernel\n\t\tconst { dispatchKMeansAssign: dispatch } =\n\t\t\tawait import(\"./kernels/kmeans/kernel.js\");\n\t\tdispatch(\n\t\t\troot,\n\t\t\tpointsBuffer,\n\t\t\tcentroidsBuffer,\n\t\t\tassignmentsBuffer,\n\t\t\tdistancesBuffer,\n\t\t\tpointCount,\n\t\t\tk,\n\t\t);\n\n\t\tconst assignments = await assignmentsBuffer.read();\n\t\tconst distances = await distancesBuffer.read();\n\n\t\treturn {\n\t\t\tassignments: new Uint32Array(assignments),\n\t\t\tdistances: new Float32Array(distances),\n\t\t};\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"operations-CSU0yFPr.cjs","names":[],"sources":["../src/gpu/detect.ts","../src/gpu/types.ts","../src/gpu/dispatch.ts","../src/gpu/kernels/spmv/kernel.ts","../src/gpu/kernels/pagerank/kernel.ts","../src/gpu/kernels/jaccard/kernel.ts","../src/gpu/kernels/degree-histogram/kernel.ts","../src/gpu/operations.ts"],"sourcesContent":["/**\n * WebGPU availability detection for browser and Node.js environments.\n *\n * This module provides runtime detection of WebGPU support without\n * requiring any polyfills or runtime dependencies.\n */\n\nimport type { GPUDetectionResult } from \"./types\";\n\n/**\n * Detect WebGPU availability in the current environment.\n *\n * Checks for:\n * - Browser: navigator.gpu\n * - Node.js: global GPU constructor (Node.js 21+ with --experimental-webgpu)\n * - Deno: global GPU constructor\n *\n * @returns Detection result with availability status and reason\n */\nexport function detectWebGPU(): GPUDetectionResult {\n\t// Check for browser WebGPU API\n\tif (typeof navigator !== \"undefined\" && \"gpu\" in navigator) {\n\t\treturn { available: true };\n\t}\n\n\t// Check for Node.js / Deno global GPU\n\tif (typeof globalThis !== \"undefined\" && \"GPU\" in globalThis) {\n\t\treturn { available: true };\n\t}\n\n\t// WebGPU not available\n\tconst reasons: string[] = [];\n\n\tif (typeof navigator === \"undefined\" && typeof globalThis === \"undefined\") {\n\t\treasons.push(\"no global scope detected\");\n\t} else if (typeof navigator !== \"undefined\" && !(\"gpu\" in navigator)) {\n\t\treasons.push(\"navigator.gpu not present (browser may not support WebGPU)\");\n\t} else if (typeof globalThis !== \"undefined\" && !(\"GPU\" in globalThis)) {\n\t\treasons.push(\n\t\t\t\"global GPU not present (Node.js requires v21+ with --experimental-webgpu flag)\",\n\t\t);\n\t}\n\n\treturn {\n\t\tavailable: false,\n\t\treason: reasons.length > 0 ? reasons.join(\"; \") : \"unknown environment\",\n\t};\n}\n\n/**\n * Check if WebGPU is available (convenience function).\n *\n * @returns true if WebGPU is available, false otherwise\n */\nexport function isWebGPUAvailable(): boolean {\n\treturn detectWebGPU().available;\n}\n\n/**\n * Assert that WebGPU is available, throwing an error if not.\n *\n * @throws Error if WebGPU is not available\n */\nexport function assertWebGPUAvailable(): void {\n\tconst result = detectWebGPU();\n\tif (!result.available) {\n\t\tthrow new Error(\n\t\t\t`WebGPU required but not available: ${result.reason ?? \"unknown reason\"}`,\n\t\t);\n\t}\n}\n","/**\n * Type definitions for the WebGPU compute backend.\n *\n * These types define the backend selection options and result types\n * for GPU-accelerated graph operations.\n */\n\nimport type { GraphwiseGPURoot } from \"./root\";\n\n/**\n * Backend selection for compute operations.\n *\n * - 'cpu': Synchronous CPU implementation (default, always available)\n * - 'gpu': Async GPU implementation (throws if WebGPU unavailable)\n * - 'auto': Async, detect WebGPU at runtime, fall back to CPU silently\n */\nexport type ComputeBackend = \"auto\" | \"gpu\" | \"cpu\";\n\n/**\n * Result of WebGPU availability detection.\n */\nexport interface GPUDetectionResult {\n\t/** Whether WebGPU is available in the current environment */\n\treadonly available: boolean;\n\t/** Human-readable reason if unavailable */\n\treadonly reason?: string;\n}\n\n/**\n * Error thrown when GPU backend is requested but unavailable.\n */\nexport class GPUNotAvailableError extends Error {\n\tpublic constructor(reason: string) {\n\t\tsuper(`WebGPU not available: ${reason}`);\n\t\tthis.name = \"GPUNotAvailableError\";\n\t}\n}\n\n/**\n * Result wrapper for GPU operations that may fall back to CPU.\n */\nexport interface ComputeResult<T> {\n\t/** The computed result value */\n\treadonly value: T;\n\t/** Which backend was actually used */\n\treadonly backend: \"gpu\" | \"cpu\";\n\t/** Time taken in milliseconds (optional, for profiling) */\n\treadonly elapsedMs?: number;\n}\n\n/**\n * Configuration options for GPU compute operations.\n */\nexport interface GPUComputeOptions {\n\t/** Backend selection: 'auto', 'gpu', or 'cpu' */\n\treadonly backend?: ComputeBackend;\n\t/** Optional TypeGPU root to reuse (avoids device acquisition overhead) */\n\treadonly root?: GraphwiseGPURoot;\n}\n","/**\n * Backend selection and dispatch utilities for GPU compute operations.\n *\n * Provides the `withBackend` function that handles auto/gpu/cpu backend\n * selection with timing and fallback logic.\n *\n * @module gpu/dispatch\n */\n\nimport { detectWebGPU } from \"./detect\";\nimport {\n\tGPUNotAvailableError,\n\ttype ComputeBackend,\n\ttype ComputeResult,\n} from \"./types\";\nimport type { GraphwiseGPURoot } from \"./root\";\n\n/**\n * Options for backend dispatch.\n */\nexport interface DispatchOptions {\n\t/** Backend selection: 'auto', 'gpu', or 'cpu' */\n\treadonly backend?: ComputeBackend | undefined;\n\t/** Optional pre-initialised TypeGPU root */\n\treadonly root?: GraphwiseGPURoot | undefined;\n\t/** Optional abort signal for cancellation */\n\treadonly signal?: AbortSignal | undefined;\n}\n\n/**\n * CPU compute function type.\n */\nexport type CPUFunction<T> = () => T;\n\n/**\n * GPU compute function type.\n */\nexport type GPUFunction<T> = (root: GraphwiseGPURoot) => Promise<T> | T;\n\n/**\n * Execute a compute operation with automatic backend selection.\n *\n * @param options - Backend selection and cancellation options\n * @param cpuFn - CPU fallback implementation\n * @param gpuFn - GPU implementation (receives TypeGPU root)\n * @returns Compute result with backend used and timing\n */\nexport async function withBackend<T>(\n\toptions: DispatchOptions,\n\tcpuFn: CPUFunction<T>,\n\tgpuFn: GPUFunction<T>,\n): Promise<ComputeResult<T>> {\n\tconst backend = options.backend ?? \"auto\";\n\n\t// Check for cancellation\n\tif (options.signal?.aborted === true) {\n\t\tthrow new DOMException(\"Operation aborted\", \"AbortError\");\n\t}\n\n\t// CPU backend - synchronous, always available\n\tif (backend === \"cpu\") {\n\t\tconst start = performance.now();\n\t\tconst value = cpuFn();\n\t\tconst elapsedMs = performance.now() - start;\n\t\treturn { value, backend: \"cpu\", elapsedMs };\n\t}\n\n\t// GPU backend - requires WebGPU\n\tif (backend === \"gpu\") {\n\t\tconst detection = detectWebGPU();\n\t\tif (!detection.available) {\n\t\t\tthrow new GPUNotAvailableError(detection.reason ?? \"Unknown reason\");\n\t\t}\n\n\t\tconst root = options.root;\n\t\tif (root === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t\"GPU backend requires a GraphwiseGPURoot. Pass one via options.root or use backend: 'auto'.\",\n\t\t\t);\n\t\t}\n\n\t\tconst start = performance.now();\n\t\tconst value = await gpuFn(root);\n\t\tconst elapsedMs = performance.now() - start;\n\t\treturn { value, backend: \"gpu\", elapsedMs };\n\t}\n\n\t// Auto backend - detect WebGPU, fall back to CPU\n\tconst detection = detectWebGPU();\n\n\t// No WebGPU available - use CPU\n\tif (!detection.available) {\n\t\tconst start = performance.now();\n\t\tconst value = cpuFn();\n\t\tconst elapsedMs = performance.now() - start;\n\t\treturn { value, backend: \"cpu\", elapsedMs };\n\t}\n\n\t// WebGPU available but no root provided - use CPU\n\tconst root = options.root;\n\tif (root === undefined) {\n\t\tconst start = performance.now();\n\t\tconst value = cpuFn();\n\t\tconst elapsedMs = performance.now() - start;\n\t\treturn { value, backend: \"cpu\", elapsedMs };\n\t}\n\n\t// WebGPU available with root - use GPU\n\tconst start = performance.now();\n\tconst value = await gpuFn(root);\n\tconst elapsedMs = performance.now() - start;\n\treturn { value, backend: \"gpu\", elapsedMs };\n}\n","/**\n * TypeGPU compute kernel for Sparse Matrix-Vector Multiplication (SpMV).\n *\n * Computes y = A * x where A is a sparse matrix in CSR format.\n * Uses TypeGPU's compute pipeline for parallel GPU execution.\n *\n * @module gpu/kernels/spmv/kernel\n */\n\nimport tgpu, { d, type StorageFlag, type TgpuBuffer } from \"typegpu\";\nimport type { TypedBufferGroup } from \"../../csr\";\nimport type { GraphwiseGPURoot } from \"../../root\";\n\n/**\n * Bind group layout for SpMV kernel.\n */\nconst SpMVLayout = tgpu.bindGroupLayout({\n\trowOffsets: { storage: d.arrayOf(d.u32) },\n\tcolIndices: { storage: d.arrayOf(d.u32) },\n\tvalues: { storage: d.arrayOf(d.f32) },\n\tx: { storage: d.arrayOf(d.f32) },\n\ty: { storage: d.arrayOf(d.f32), access: \"mutable\" },\n\tnodeCount: { uniform: d.u32 },\n\thasValues: { uniform: d.u32 },\n});\n\n/**\n * SpMV compute pipeline: y[row] = sum(A[row,col] * x[col]).\n *\n * Each thread computes one row of the output vector using the CSR format:\n * - rowOffsets: start/end indices for each row\n * - colIndices: column index for each non-zero entry\n * - values: edge weights (optional, defaults to 1.0)\n */\nconst spmvPipeline = (row: number): void => {\n\t\"use gpu\";\n\tconst start = SpMVLayout.$.rowOffsets[row] ?? 0;\n\tconst end = SpMVLayout.$.rowOffsets[row + 1] ?? 0;\n\n\tlet sum = 0.0;\n\tfor (let i = start; i < end; i = i + 1) {\n\t\tconst col = SpMVLayout.$.colIndices[i] ?? 0;\n\t\tconst weight =\n\t\t\tSpMVLayout.$.hasValues !== 0 ? (SpMVLayout.$.values[i] ?? 1.0) : 1.0;\n\t\tsum = sum + weight * (SpMVLayout.$.x[col] ?? 0.0);\n\t}\n\tSpMVLayout.$.y[row] = sum;\n};\n\n/**\n * Dispatch SpMV on GPU.\n *\n * @param root - TypeGPU root instance\n * @param csrBuffers - CSR matrix as typed buffers\n * @param x - Input vector buffer\n * @param y - Output vector buffer (mutable)\n * @param nodeCount - Number of nodes/rows\n * @param hasValues - Whether edge weights are present\n */\nexport function dispatchSpmv(\n\troot: GraphwiseGPURoot,\n\tcsrBuffers: TypedBufferGroup,\n\tx: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.f32>>> & StorageFlag,\n\ty: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.f32>>> & StorageFlag,\n\tnodeCount: number,\n\thasValues: boolean,\n): void {\n\tconst pipeline = root.createGuardedComputePipeline(spmvPipeline);\n\n\t// Create values buffer if not present (unweighted graph)\n\tconst valuesBuffer =\n\t\tcsrBuffers.values ??\n\t\troot\n\t\t\t.createBuffer(\n\t\t\t\td.arrayOf(d.f32, csrBuffers.edgeCount),\n\t\t\t\tnew Array(csrBuffers.edgeCount).fill(1.0),\n\t\t\t)\n\t\t\t.$usage(\"storage\");\n\n\t// Create uniform buffers for scalar values\n\tconst nodeCountBuffer = root.createBuffer(d.u32, nodeCount).$usage(\"uniform\");\n\tconst hasValuesBuffer = root\n\t\t.createBuffer(d.u32, hasValues ? 1 : 0)\n\t\t.$usage(\"uniform\");\n\n\tconst bindGroup = root.createBindGroup(SpMVLayout, {\n\t\trowOffsets: csrBuffers.rowOffsets,\n\t\tcolIndices: csrBuffers.colIndices,\n\t\tvalues: valuesBuffer,\n\t\tx,\n\t\ty,\n\t\tnodeCount: nodeCountBuffer,\n\t\thasValues: hasValuesBuffer,\n\t});\n\n\tpipeline.with(bindGroup).dispatchThreads(nodeCount);\n}\n\nexport { SpMVLayout };\n","/**\n * TypeGPU compute kernel for PageRank power iteration.\n *\n * Computes one iteration of PageRank:\n * r(v) = (1 - d)/N + d * sum(r(u) / deg_out(u)) for u -> v\n *\n * Uses TypeGPU's compute pipeline for parallel GPU execution.\n *\n * @module gpu/kernels/pagerank/kernel\n */\n\nimport tgpu, { d, type StorageFlag, type TgpuBuffer } from \"typegpu\";\nimport type { TypedBufferGroup } from \"../../csr\";\nimport type { GraphwiseGPURoot } from \"../../root\";\n\n/**\n * Bind group layout for PageRank kernel.\n */\nconst PageRankLayout = tgpu.bindGroupLayout({\n\trowOffsets: { storage: d.arrayOf(d.u32) },\n\tcolIndices: { storage: d.arrayOf(d.u32) },\n\tranks: { storage: d.arrayOf(d.f32) },\n\toutDegrees: { storage: d.arrayOf(d.u32) },\n\tnewRanks: { storage: d.arrayOf(d.f32), access: \"mutable\" },\n\tnodeCount: { uniform: d.u32 },\n\tdamping: { uniform: d.f32 },\n});\n\n/**\n * PageRank compute pipeline: one power iteration per dispatch.\n *\n * Each thread computes one node's new rank from incoming neighbours:\n * newRank[v] = (1 - damping) / N + damping * sum(rank[u] / outDegree[u])\n */\nconst pagerankPipeline = (node: number): void => {\n\t\"use gpu\";\n\tconst n = PageRankLayout.$.nodeCount ?? 0;\n\tconst damp = PageRankLayout.$.damping ?? 0.85;\n\n\tconst start = PageRankLayout.$.rowOffsets[node] ?? 0;\n\tconst end = PageRankLayout.$.rowOffsets[node + 1] ?? 0;\n\n\tlet contribution = 0.0;\n\tfor (let i = start; i < end; i = i + 1) {\n\t\tconst source = PageRankLayout.$.colIndices[i] ?? 0;\n\t\tconst deg = PageRankLayout.$.outDegrees[source] ?? 0;\n\t\tif (deg > 0) {\n\t\t\tconst rank = PageRankLayout.$.ranks[source] ?? 0.0;\n\t\t\tcontribution = contribution + rank / deg;\n\t\t}\n\t}\n\n\tconst teleport = (1.0 - damp) / n;\n\tPageRankLayout.$.newRanks[node] = teleport + damp * contribution;\n};\n\n/**\n * Dispatch one PageRank iteration on GPU.\n *\n * @param root - TypeGPU root instance\n * @param csrBuffers - CSR matrix as typed buffers (transpose graph: in-edges)\n * @param ranks - Current rank values buffer\n * @param outDegrees - Out-degree buffer for each node\n * @param newRanks - Output buffer for new rank values (mutable)\n * @param nodeCount - Number of nodes\n * @param damping - Damping factor (typically 0.85)\n */\nexport function dispatchPagerank(\n\troot: GraphwiseGPURoot,\n\tcsrBuffers: TypedBufferGroup,\n\tranks: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.f32>>> & StorageFlag,\n\toutDegrees: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.u32>>> &\n\t\tStorageFlag,\n\tnewRanks: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.f32>>> &\n\t\tStorageFlag,\n\tnodeCount: number,\n\tdamping: number,\n): void {\n\tconst pipeline = root.createGuardedComputePipeline(pagerankPipeline);\n\n\tconst nodeCountBuffer = root.createBuffer(d.u32, nodeCount).$usage(\"uniform\");\n\tconst dampingBuffer = root.createBuffer(d.f32, damping).$usage(\"uniform\");\n\n\tconst bindGroup = root.createBindGroup(PageRankLayout, {\n\t\trowOffsets: csrBuffers.rowOffsets,\n\t\tcolIndices: csrBuffers.colIndices,\n\t\tranks,\n\t\toutDegrees,\n\t\tnewRanks,\n\t\tnodeCount: nodeCountBuffer,\n\t\tdamping: dampingBuffer,\n\t});\n\n\tpipeline.with(bindGroup).dispatchThreads(nodeCount);\n}\n\nexport { PageRankLayout };\n","/**\n * TypeGPU compute kernel for batch Jaccard similarity.\n *\n * Computes Jaccard coefficient for multiple node pairs in parallel:\n * J(u, v) = |N(u) ∩ N(v)| / |N(u) ∪ N(v)|\n *\n * Uses binary search optimisation: iterate smaller neighbourhood, search in larger.\n *\n * @module gpu/kernels/jaccard/kernel\n */\n\nimport tgpu, { d, type StorageFlag, type TgpuBuffer } from \"typegpu\";\nimport type { TypedBufferGroup } from \"../../csr\";\nimport type { GraphwiseGPURoot } from \"../../root\";\n\n/**\n * Bind group layout for Jaccard kernel.\n */\nconst JaccardLayout = tgpu.bindGroupLayout({\n\trowOffsets: { storage: d.arrayOf(d.u32) },\n\tcolIndices: { storage: d.arrayOf(d.u32) },\n\tpairsU: { storage: d.arrayOf(d.u32) },\n\tpairsV: { storage: d.arrayOf(d.u32) },\n\tresults: { storage: d.arrayOf(d.f32), access: \"mutable\" },\n\tpairCount: { uniform: d.u32 },\n});\n\n/**\n * Jaccard compute pipeline: one thread per pair.\n *\n * For each pair (u, v):\n * - Count intersection by iterating smaller neighbourhood\n * - Binary search in larger neighbourhood\n * - Jaccard = intersection / (degU + degV - intersection)\n */\nconst jaccardPipeline = (pairIdx: number): void => {\n\t\"use gpu\";\n\tconst u = JaccardLayout.$.pairsU[pairIdx] ?? 0;\n\tconst v = JaccardLayout.$.pairsV[pairIdx] ?? 0;\n\n\tconst uStart = JaccardLayout.$.rowOffsets[u] ?? 0;\n\tconst uEnd = JaccardLayout.$.rowOffsets[u + 1] ?? 0;\n\tconst vStart = JaccardLayout.$.rowOffsets[v] ?? 0;\n\tconst vEnd = JaccardLayout.$.rowOffsets[v + 1] ?? 0;\n\n\tconst degU = uEnd - uStart;\n\tconst degV = vEnd - vStart;\n\n\t// Empty neighbourhoods → Jaccard = 0\n\tif (degU === 0 || degV === 0) {\n\t\tJaccardLayout.$.results[pairIdx] = 0.0;\n\t\treturn;\n\t}\n\n\t// Count intersection: iterate smaller, binary search in larger\n\tlet intersection = 0;\n\n\tif (degU <= degV) {\n\t\t// Iterate u's neighbours, search in v's\n\t\tfor (let i = uStart; i < uEnd; i = i + 1) {\n\t\t\tconst neighbour = JaccardLayout.$.colIndices[i] ?? 0;\n\t\t\t// Binary search in v's neighbourhood\n\t\t\tlet lo = vStart;\n\t\t\tlet hi = vEnd;\n\t\t\twhile (lo < hi) {\n\t\t\t\tconst mid = lo + (hi - lo) / 2;\n\t\t\t\tconst midVal = JaccardLayout.$.colIndices[mid] ?? 0;\n\t\t\t\tif (midVal === neighbour) {\n\t\t\t\t\tintersection = intersection + 1;\n\t\t\t\t\tlo = hi; // break\n\t\t\t\t} else if (midVal < neighbour) {\n\t\t\t\t\tlo = mid + 1;\n\t\t\t\t} else {\n\t\t\t\t\thi = mid;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Iterate v's neighbours, search in u's\n\t\tfor (let i = vStart; i < vEnd; i = i + 1) {\n\t\t\tconst neighbour = JaccardLayout.$.colIndices[i] ?? 0;\n\t\t\t// Binary search in u's neighbourhood\n\t\t\tlet lo = uStart;\n\t\t\tlet hi = uEnd;\n\t\t\twhile (lo < hi) {\n\t\t\t\tconst mid = lo + (hi - lo) / 2;\n\t\t\t\tconst midVal = JaccardLayout.$.colIndices[mid] ?? 0;\n\t\t\t\tif (midVal === neighbour) {\n\t\t\t\t\tintersection = intersection + 1;\n\t\t\t\t\tlo = hi; // break\n\t\t\t\t} else if (midVal < neighbour) {\n\t\t\t\t\tlo = mid + 1;\n\t\t\t\t} else {\n\t\t\t\t\thi = mid;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tconst unionSize = degU + degV - intersection;\n\tJaccardLayout.$.results[pairIdx] = intersection / unionSize;\n};\n\n/**\n * Dispatch batch Jaccard on GPU.\n *\n * @param root - TypeGPU root instance\n * @param csrBuffers - CSR matrix as typed buffers\n * @param pairsU - First node of each pair (u32 array)\n * @param pairsV - Second node of each pair (u32 array)\n * @param results - Output Jaccard coefficients (f32 array, mutable)\n * @param pairCount - Number of pairs to compute\n */\nexport function dispatchJaccard(\n\troot: GraphwiseGPURoot,\n\tcsrBuffers: TypedBufferGroup,\n\tpairsU: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.u32>>> & StorageFlag,\n\tpairsV: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.u32>>> & StorageFlag,\n\tresults: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.f32>>> & StorageFlag,\n\tpairCount: number,\n): void {\n\tconst pipeline = root.createGuardedComputePipeline(jaccardPipeline);\n\n\tconst pairCountBuffer = root.createBuffer(d.u32, pairCount).$usage(\"uniform\");\n\n\tconst bindGroup = root.createBindGroup(JaccardLayout, {\n\t\trowOffsets: csrBuffers.rowOffsets,\n\t\tcolIndices: csrBuffers.colIndices,\n\t\tpairsU,\n\t\tpairsV,\n\t\tresults,\n\t\tpairCount: pairCountBuffer,\n\t});\n\n\tpipeline.with(bindGroup).dispatchThreads(pairCount);\n}\n\nexport { JaccardLayout };\n","/**\n * TypeGPU compute kernel for degree computation.\n *\n * Computes degree per node from CSR row offsets.\n * Note: Histogram aggregation requires atomic operations or CPU reduction.\n *\n * @module gpu/kernels/degree-histogram/kernel\n */\n\nimport tgpu, { d, type StorageFlag, type TgpuBuffer } from \"typegpu\";\nimport type { TypedBufferGroup } from \"../../csr\";\nimport type { GraphwiseGPURoot } from \"../../root\";\n\n/**\n * Bind group layout for degree kernel.\n */\nconst DegreeLayout = tgpu.bindGroupLayout({\n\trowOffsets: { storage: d.arrayOf(d.u32) },\n\tdegrees: { storage: d.arrayOf(d.u32), access: \"mutable\" },\n\tnodeCount: { uniform: d.u32 },\n});\n\n/**\n * Degree compute pipeline: compute degree for each node.\n *\n * Each thread computes one node's degree from CSR row offsets:\n * degree[node] = rowOffsets[node+1] - rowOffsets[node]\n */\nconst degreePipeline = (node: number): void => {\n\t\"use gpu\";\n\tconst n = DegreeLayout.$.nodeCount ?? 0;\n\n\tif (node >= n) {\n\t\treturn;\n\t}\n\n\tconst start = DegreeLayout.$.rowOffsets[node] ?? 0;\n\tconst end = DegreeLayout.$.rowOffsets[node + 1] ?? 0;\n\tconst deg = end - start;\n\n\tDegreeLayout.$.degrees[node] = deg;\n};\n\n/**\n * Dispatch degree computation on GPU.\n *\n * Note: This computes per-node degrees. Histogram aggregation should be\n * done on CPU or with a separate reduction kernel.\n *\n * @param root - TypeGPU root instance\n * @param csrBuffers - CSR matrix as typed buffers\n * @param degrees - Output degree array (u32, mutable)\n * @param nodeCount - Number of nodes\n */\nexport function dispatchDegreeHistogram(\n\troot: GraphwiseGPURoot,\n\tcsrBuffers: TypedBufferGroup,\n\tdegrees: TgpuBuffer<ReturnType<typeof d.arrayOf<typeof d.u32>>> & StorageFlag,\n\tnodeCount: number,\n): void {\n\tconst pipeline = root.createGuardedComputePipeline(degreePipeline);\n\n\tconst nodeCountBuffer = root.createBuffer(d.u32, nodeCount).$usage(\"uniform\");\n\n\tconst bindGroup = root.createBindGroup(DegreeLayout, {\n\t\trowOffsets: csrBuffers.rowOffsets,\n\t\tdegrees,\n\t\tnodeCount: nodeCountBuffer,\n\t});\n\n\tpipeline.with(bindGroup).dispatchThreads(nodeCount);\n}\n\nexport { DegreeLayout };\n","/**\n * High-level GPU operations for graph algorithms.\n *\n * These functions accept ReadableGraph instances and handle CSR conversion\n * internally, providing a simple API for GPU-accelerated graph operations.\n *\n * @module gpu/operations\n */\n\nimport type { NodeData, EdgeData, NodeId, ReadableGraph } from \"../graph\";\nimport type { MIVariantName } from \"../ranking/mi/types\";\nimport type { ComputeResult, GPUComputeOptions } from \"./types\";\nimport { withBackend, type DispatchOptions } from \"./dispatch\";\nimport { graphToCSR, csrToTypedBuffers, type CSRMatrix } from \"./csr\";\nimport { dispatchSpmv } from \"./kernels/spmv/kernel\";\nimport { dispatchPagerank } from \"./kernels/pagerank/kernel\";\nimport { dispatchJaccard } from \"./kernels/jaccard/kernel\";\nimport { dispatchDegreeHistogram } from \"./kernels/degree-histogram/kernel\";\nimport {\n\tintersectionBatch,\n\tjaccardFromIntersection,\n\tcosineFromIntersection,\n\tsorensenDiceFromIntersection,\n\toverlapFromIntersection,\n\thubPromotedFromIntersection,\n\ttype IntersectionResult,\n} from \"./kernels/intersection/logic\";\nimport type { GraphwiseGPURoot } from \"./root\";\nimport { d } from \"typegpu\";\n// clustering helper not imported; local implementations used below\n\n/**\n * Degree statistics from histogram computation.\n */\nexport interface DegreeStats {\n\t/** Minimum degree in the graph */\n\treadonly min: number;\n\t/** Maximum degree in the graph */\n\treadonly max: number;\n\t/** Average degree */\n\treadonly mean: number;\n\t/** Histogram of degree frequencies (index = degree, value = count) */\n\treadonly histogram: readonly number[];\n}\n\n/**\n * Sparse matrix-vector multiply on GPU.\n *\n * Computes y = A * x where A is the graph adjacency matrix in CSR format.\n *\n * @param graph - Input graph\n * @param x - Input vector (must have length = graph.nodeCount)\n * @param options - Compute options (backend, root, signal)\n * @returns Result vector y\n */\nexport async function gpuSpmv<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tx: Float32Array,\n\toptions?: GPUComputeOptions & { signal?: AbortSignal },\n): Promise<ComputeResult<Float32Array>> {\n\tconst nodeCount = graph.nodeCount;\n\n\tif (x.length !== nodeCount) {\n\t\tthrow new Error(\n\t\t\t`Input vector length (${String(x.length)}) must match node count (${String(nodeCount)})`,\n\t\t);\n\t}\n\n\tconst cpuFn = (): Float32Array => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst y = new Float32Array(nodeCount);\n\n\t\tfor (let row = 0; row < nodeCount; row++) {\n\t\t\tconst start = csr.rowOffsets[row] ?? 0;\n\t\t\tconst end = csr.rowOffsets[row + 1] ?? 0;\n\t\t\tlet sum = 0;\n\n\t\t\tfor (let i = start; i < end; i++) {\n\t\t\t\tconst col = csr.colIndices[i] ?? 0;\n\t\t\t\tconst weight = csr.values?.[i] ?? 1;\n\t\t\t\tsum += weight * (x[col] ?? 0);\n\t\t\t}\n\n\t\t\ty[row] = sum;\n\t\t}\n\n\t\treturn y;\n\t};\n\n\tconst gpuFn = async (root: GraphwiseGPURoot): Promise<Float32Array> => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst csrBuffers = csrToTypedBuffers(root, csr);\n\n\t\tconst xBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.f32, nodeCount), Array.from(x))\n\t\t\t.$usage(\"storage\");\n\n\t\tconst yBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.f32, nodeCount))\n\t\t\t.$usage(\"storage\");\n\n\t\tdispatchSpmv(\n\t\t\troot,\n\t\t\tcsrBuffers,\n\t\t\txBuffer,\n\t\t\tyBuffer,\n\t\t\tnodeCount,\n\t\t\tcsr.values !== undefined,\n\t\t);\n\n\t\tconst result = await yBuffer.read();\n\t\treturn new Float32Array(result);\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n\n/**\n * PageRank via GPU-accelerated power iteration.\n *\n * @param graph - Input graph (will be converted to transpose CSR for in-edges)\n * @param options - Compute options plus damping factor and iteration count\n * @returns PageRank scores for each node\n */\nexport async function gpuPageRank<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\toptions?: GPUComputeOptions & {\n\t\tdamping?: number;\n\t\titerations?: number;\n\t\tsignal?: AbortSignal;\n\t},\n): Promise<ComputeResult<Float32Array>> {\n\tconst nodeCount = graph.nodeCount;\n\tconst damping = options?.damping ?? 0.85;\n\tconst iterations = options?.iterations ?? 20;\n\n\tconst cpuFn = (): Float32Array => {\n\t\t// Build transpose CSR (in-edges) for PageRank\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst ranks = new Float32Array(nodeCount).fill(1 / nodeCount);\n\t\tconst outDegrees = new Uint32Array(nodeCount);\n\n\t\t// Compute out-degrees\n\t\tfor (let i = 0; i < nodeCount; i++) {\n\t\t\toutDegrees[i] = (csr.rowOffsets[i + 1] ?? 0) - (csr.rowOffsets[i] ?? 0);\n\t\t}\n\n\t\t// Power iteration\n\t\tfor (let iter = 0; iter < iterations; iter++) {\n\t\t\tconst newRanks = new Float32Array(nodeCount);\n\n\t\t\tfor (let v = 0; v < nodeCount; v++) {\n\t\t\t\tconst start = csr.rowOffsets[v] ?? 0;\n\t\t\t\tconst end = csr.rowOffsets[v + 1] ?? 0;\n\t\t\t\tlet contribution = 0;\n\n\t\t\t\tfor (let i = start; i < end; i++) {\n\t\t\t\t\tconst source = csr.colIndices[i] ?? 0;\n\t\t\t\t\tconst deg = outDegrees[source] ?? 0;\n\t\t\t\t\tif (deg > 0) {\n\t\t\t\t\t\tcontribution += (ranks[source] ?? 0) / deg;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tnewRanks[v] = (1 - damping) / nodeCount + damping * contribution;\n\t\t\t}\n\n\t\t\tranks.set(newRanks);\n\t\t}\n\n\t\treturn ranks;\n\t};\n\n\tconst gpuFn = async (root: GraphwiseGPURoot): Promise<Float32Array> => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst csrBuffers = csrToTypedBuffers(root, csr);\n\n\t\t// Compute out-degrees\n\t\tconst outDegrees = new Uint32Array(nodeCount);\n\t\tfor (let i = 0; i < nodeCount; i++) {\n\t\t\toutDegrees[i] = (csr.rowOffsets[i + 1] ?? 0) - (csr.rowOffsets[i] ?? 0);\n\t\t}\n\n\t\tconst outDegreesBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, nodeCount), Array.from(outDegrees))\n\t\t\t.$usage(\"storage\");\n\n\t\tconst ranksBuffer = root\n\t\t\t.createBuffer(\n\t\t\t\td.arrayOf(d.f32, nodeCount),\n\t\t\t\tArray.from(new Float32Array(nodeCount).fill(1 / nodeCount)),\n\t\t\t)\n\t\t\t.$usage(\"storage\");\n\n\t\tconst newRanksBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.f32, nodeCount))\n\t\t\t.$usage(\"storage\");\n\n\t\t// Power iteration\n\t\tfor (let iter = 0; iter < iterations; iter++) {\n\t\t\tdispatchPagerank(\n\t\t\t\troot,\n\t\t\t\tcsrBuffers,\n\t\t\t\tranksBuffer,\n\t\t\t\toutDegreesBuffer,\n\t\t\t\tnewRanksBuffer,\n\t\t\t\tnodeCount,\n\t\t\t\tdamping,\n\t\t\t);\n\n\t\t\t// Swap buffers by copying data back\n\t\t\tconst newRanks = await newRanksBuffer.read();\n\t\t\tranksBuffer.write(Array.from(newRanks));\n\t\t}\n\n\t\tconst result = await ranksBuffer.read();\n\t\treturn new Float32Array(result);\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n\n/**\n * Batch Jaccard similarity for node pairs on GPU.\n *\n * @param graph - Input graph\n * @param pairs - Array of [u, v] node ID pairs\n * @param options - Compute options\n * @returns Jaccard coefficients for each pair\n */\nexport async function gpuJaccardBatch<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpairs: readonly [NodeId, NodeId][],\n\toptions?: GPUComputeOptions & { signal?: AbortSignal },\n): Promise<ComputeResult<Float32Array>> {\n\tconst pairCount = pairs.length;\n\tconst { indexMap } = graphToCSR(graph);\n\n\tconst cpuFn = (): Float32Array => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst results = new Float32Array(pairCount);\n\n\t\tfor (let p = 0; p < pairCount; p++) {\n\t\t\tconst pair = pairs[p];\n\t\t\tif (pair === undefined) continue;\n\t\t\tconst [u, v] = pair;\n\t\t\tconst uIdx = indexMap.nodeToIndex.get(u);\n\t\t\tconst vIdx = indexMap.nodeToIndex.get(v);\n\n\t\t\tif (uIdx === undefined || vIdx === undefined) {\n\t\t\t\tresults[p] = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst uStart = csr.rowOffsets[uIdx] ?? 0;\n\t\t\tconst uEnd = csr.rowOffsets[uIdx + 1] ?? 0;\n\t\t\tconst vStart = csr.rowOffsets[vIdx] ?? 0;\n\t\t\tconst vEnd = csr.rowOffsets[vIdx + 1] ?? 0;\n\n\t\t\tconst uNeighbours = new Set(\n\t\t\t\tArray.from(csr.colIndices.slice(uStart, uEnd)),\n\t\t\t);\n\t\t\tconst vNeighbours = new Set(\n\t\t\t\tArray.from(csr.colIndices.slice(vStart, vEnd)),\n\t\t\t);\n\n\t\t\tlet intersection = 0;\n\t\t\tfor (const n of uNeighbours) {\n\t\t\t\tif (vNeighbours.has(n)) {\n\t\t\t\t\tintersection++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst union = uNeighbours.size + vNeighbours.size - intersection;\n\t\t\tresults[p] = union > 0 ? intersection / union : 0;\n\t\t}\n\n\t\treturn results;\n\t};\n\n\tconst gpuFn = async (root: GraphwiseGPURoot): Promise<Float32Array> => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst csrBuffers = csrToTypedBuffers(root, csr);\n\n\t\tconst pairsU = new Uint32Array(pairCount);\n\t\tconst pairsV = new Uint32Array(pairCount);\n\n\t\tfor (let i = 0; i < pairCount; i++) {\n\t\t\tconst pair = pairs[i];\n\t\t\tif (pair === undefined) continue;\n\t\t\tconst uIdx = indexMap.nodeToIndex.get(pair[0]);\n\t\t\tconst vIdx = indexMap.nodeToIndex.get(pair[1]);\n\t\t\tpairsU[i] = uIdx ?? 0;\n\t\t\tpairsV[i] = vIdx ?? 0;\n\t\t}\n\n\t\tconst pairsUBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, pairCount), Array.from(pairsU))\n\t\t\t.$usage(\"storage\");\n\n\t\tconst pairsVBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, pairCount), Array.from(pairsV))\n\t\t\t.$usage(\"storage\");\n\n\t\tconst resultsBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.f32, pairCount))\n\t\t\t.$usage(\"storage\");\n\n\t\tdispatchJaccard(\n\t\t\troot,\n\t\t\tcsrBuffers,\n\t\t\tpairsUBuffer,\n\t\t\tpairsVBuffer,\n\t\t\tresultsBuffer,\n\t\t\tpairCount,\n\t\t);\n\n\t\tconst result = await resultsBuffer.read();\n\t\treturn new Float32Array(result);\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n\n/**\n * BFS level assignment from source node on GPU.\n *\n * Note: Full GPU BFS requires atomics not yet available in TypeGPU.\n * This implementation uses CPU for now but maintains the API.\n *\n * @param graph - Input graph\n * @param source - Source node ID\n * @param options - Compute options\n * @returns BFS level for each node (-1 for unreachable)\n */\nexport async function gpuBfsLevels<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: NodeId,\n\toptions?: GPUComputeOptions & { signal?: AbortSignal },\n): Promise<ComputeResult<Int32Array>> {\n\tconst nodeCount = graph.nodeCount;\n\tconst { indexMap } = graphToCSR(graph);\n\n\tconst cpuFn = (): Int32Array => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst levels = new Int32Array(nodeCount).fill(-1);\n\t\tconst visited = new Uint8Array(nodeCount);\n\n\t\t// Find source index\n\t\tconst sourceIndex = indexMap.nodeToIndex.get(source);\n\t\tif (sourceIndex === undefined) {\n\t\t\tthrow new Error(`Source node ${source} not found in graph`);\n\t\t}\n\n\t\tconst queue: number[] = [sourceIndex];\n\t\tlevels[sourceIndex] = 0;\n\t\tvisited[sourceIndex] = 1;\n\n\t\twhile (queue.length > 0) {\n\t\t\tconst current = queue.shift();\n\t\t\tif (current === undefined) break;\n\t\t\tconst currentLevel = levels[current] ?? 0;\n\n\t\t\tconst start = csr.rowOffsets[current] ?? 0;\n\t\t\tconst end = csr.rowOffsets[current + 1] ?? 0;\n\n\t\t\tfor (let i = start; i < end; i++) {\n\t\t\t\tconst neighbour = csr.colIndices[i] ?? 0;\n\t\t\t\tif (visited[neighbour] === 0) {\n\t\t\t\t\tvisited[neighbour] = 1;\n\t\t\t\t\tlevels[neighbour] = currentLevel + 1;\n\t\t\t\t\tqueue.push(neighbour);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn levels;\n\t};\n\n\tconst gpuFn = (_root: GraphwiseGPURoot): Int32Array => {\n\t\t// BFS requires atomics not yet in TypeGPU - use CPU\n\t\t// _root is intentionally unused as we fall back to CPU implementation\n\t\tvoid _root;\n\t\treturn cpuFn();\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n\n/**\n * Degree histogram and statistics on GPU.\n *\n * @param graph - Input graph\n * @param options - Compute options\n * @returns Degree statistics with histogram\n */\nexport async function gpuDegreeHistogram<\n\tN extends NodeData,\n\tE extends EdgeData,\n>(\n\tgraph: ReadableGraph<N, E>,\n\toptions?: GPUComputeOptions & { signal?: AbortSignal },\n): Promise<ComputeResult<DegreeStats>> {\n\tconst nodeCount = graph.nodeCount;\n\n\tconst cpuFn = (): DegreeStats => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst degrees = new Uint32Array(nodeCount);\n\n\t\tfor (let i = 0; i < nodeCount; i++) {\n\t\t\tdegrees[i] = (csr.rowOffsets[i + 1] ?? 0) - (csr.rowOffsets[i] ?? 0);\n\t\t}\n\n\t\tconst max = degrees.length > 0 ? Math.max(...degrees) : 0;\n\t\tconst histogram: number[] = Array.from({ length: max + 1 }, () => 0);\n\n\t\tlet sum = 0;\n\t\tlet min = Infinity;\n\n\t\tfor (const d of degrees) {\n\t\t\thistogram[d] = (histogram[d] ?? 0) + 1;\n\t\t\tsum += d;\n\t\t\tif (d < min) min = d;\n\t\t}\n\n\t\tif (degrees.length === 0) {\n\t\t\tmin = 0;\n\t\t}\n\n\t\treturn {\n\t\t\tmin,\n\t\t\tmax,\n\t\t\tmean: nodeCount > 0 ? sum / nodeCount : 0,\n\t\t\thistogram,\n\t\t};\n\t};\n\n\tconst gpuFn = async (root: GraphwiseGPURoot): Promise<DegreeStats> => {\n\t\tconst { csr } = graphToCSR(graph);\n\t\tconst csrBuffers = csrToTypedBuffers(root, csr);\n\n\t\tconst degreesBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, nodeCount))\n\t\t\t.$usage(\"storage\");\n\n\t\tdispatchDegreeHistogram(root, csrBuffers, degreesBuffer, nodeCount);\n\n\t\tconst degrees = await degreesBuffer.read();\n\n\t\t// Build histogram on CPU (atomic reduction not in TypeGPU yet)\n\t\tconst max = degrees.length > 0 ? Math.max(...degrees) : 0;\n\t\tconst histogram: number[] = Array.from({ length: max + 1 }, () => 0);\n\n\t\tlet sum = 0;\n\t\tlet min = Infinity;\n\n\t\tfor (const d of degrees) {\n\t\t\thistogram[d] = (histogram[d] ?? 0) + 1;\n\t\t\tsum += d;\n\t\t\tif (d < min) min = d;\n\t\t}\n\n\t\tif (degrees.length === 0) {\n\t\t\tmin = 0;\n\t\t}\n\n\t\treturn {\n\t\t\tmin,\n\t\t\tmax,\n\t\t\tmean: nodeCount > 0 ? sum / nodeCount : 0,\n\t\t\thistogram,\n\t\t};\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n\n/**\n * Result of batch MI computation.\n */\nexport interface MIBatchResult {\n\t/** MI scores for each pair */\n\treadonly scores: Float32Array;\n\t/** Raw intersection counts for each pair */\n\treadonly intersections: Uint32Array;\n\t/** Size of first neighbourhood for each pair */\n\treadonly sizeUs: Uint32Array;\n\t/** Size of second neighbourhood for each pair */\n\treadonly sizeVs: Uint32Array;\n}\n\n/**\n * Batch MI computation for multiple node pairs on GPU.\n *\n * For Jaccard-family variants, uses the intersection kernel for raw counts\n * then applies the variant-specific formula on CPU.\n *\n * @param graph - Input graph\n * @param pairs - Array of [u, v] node ID pairs\n * @param variant - MI variant to compute (default: jaccard)\n * @param options - Compute options\n * @returns MI scores and raw intersection data for each pair\n */\nexport async function gpuMIBatch<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpairs: readonly (readonly [NodeId, NodeId])[],\n\tvariant: MIVariantName = \"jaccard\",\n\toptions?: GPUComputeOptions & { signal?: AbortSignal },\n): Promise<ComputeResult<MIBatchResult>> {\n\tconst pairCount = pairs.length;\n\tconst { csr, indexMap } = graphToCSR(graph);\n\n\tconst cpuFn = (): MIBatchResult => {\n\t\t// Convert node IDs to numeric indices, tracking validity\n\t\tconst indexPairs: (readonly [number, number])[] = [];\n\t\tconst validPair: boolean[] = [];\n\t\tfor (const pair of pairs) {\n\t\t\tconst uIdx = indexMap.nodeToIndex.get(pair[0]);\n\t\t\tconst vIdx = indexMap.nodeToIndex.get(pair[1]);\n\t\t\tif (uIdx !== undefined && vIdx !== undefined) {\n\t\t\t\tindexPairs.push([uIdx, vIdx]);\n\t\t\t\tvalidPair.push(true);\n\t\t\t} else {\n\t\t\t\t// Use sentinel values for invalid pairs\n\t\t\t\tindexPairs.push([0, 0]);\n\t\t\t\tvalidPair.push(false);\n\t\t\t}\n\t\t}\n\n\t\t// Run intersection kernel\n\t\tconst { intersections, sizeUs, sizeVs } = intersectionBatch(\n\t\t\tcsr.rowOffsets,\n\t\t\tcsr.colIndices,\n\t\t\tindexPairs,\n\t\t);\n\n\t\t// Compute MI scores based on variant\n\t\tconst scores = new Float32Array(pairCount);\n\t\tfor (let i = 0; i < pairCount; i++) {\n\t\t\t// Invalid pairs get score of 0\n\t\t\tif (validPair[i] !== true) {\n\t\t\t\tscores[i] = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst result: IntersectionResult = {\n\t\t\t\tintersection: intersections[i] ?? 0,\n\t\t\t\tsizeU: sizeUs[i] ?? 0,\n\t\t\t\tsizeV: sizeVs[i] ?? 0,\n\t\t\t};\n\t\t\tconst base = applyMIVariant(result, \"jaccard\");\n\t\t\t// Apply correction variants\n\t\t\tswitch (variant) {\n\t\t\t\tcase \"scale\": {\n\t\t\t\t\tconst rho = computeGraphDensity(csr);\n\t\t\t\t\tscores[i] = rho > 0 ? base / rho : base;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"skew\": {\n\t\t\t\t\tconst N = csr.rowOffsets.length - 1;\n\t\t\t\t\tconst degU = result.sizeU;\n\t\t\t\t\tconst degV = result.sizeV;\n\t\t\t\t\tconst w = Math.log(N / (degU + 1)) * Math.log(N / (degV + 1));\n\t\t\t\t\tscores[i] = base * w;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"span\": {\n\t\t\t\t\tconst clustering = computeClusteringCoefficients(csr);\n\t\t\t\t\tconst pair = pairs[i];\n\t\t\t\t\tconst u0 = pair ? indexMap.nodeToIndex.get(pair[0]) : undefined;\n\t\t\t\t\tconst v0 = pair ? indexMap.nodeToIndex.get(pair[1]) : undefined;\n\t\t\t\t\tconst cu = (u0 !== undefined ? clustering[u0] : undefined) ?? 0;\n\t\t\t\t\tconst cv = (v0 !== undefined ? clustering[v0] : undefined) ?? 0;\n\t\t\t\t\tscores[i] = base * (1 - Math.max(cu, cv));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tscores[i] = applyMIVariant(result, variant);\n\t\t\t}\n\t\t}\n\n\t\treturn { scores, intersections, sizeUs, sizeVs };\n\t};\n\n\t// GPU implementation uses same intersection kernel, dispatched via GPU when available\n\tconst gpuFn = async (root: GraphwiseGPURoot): Promise<MIBatchResult> => {\n\t\t// Prepare CSR buffers for GPU\n\t\tconst csrBuffers = csrToTypedBuffers(root, csr);\n\n\t\t// Convert node IDs to numeric indices for GPU buffers\n\t\tconst uArr = new Uint32Array(pairCount);\n\t\tconst vArr = new Uint32Array(pairCount);\n\t\tconst validPair: boolean[] = Array.from(\n\t\t\t{ length: pairCount },\n\t\t\t(): boolean => false,\n\t\t);\n\t\tfor (let i = 0; i < pairCount; i++) {\n\t\t\tconst p = pairs[i];\n\t\t\tconst uIdxRaw = p ? indexMap.nodeToIndex.get(p[0]) : undefined;\n\t\t\tconst vIdxRaw = p ? indexMap.nodeToIndex.get(p[1]) : undefined;\n\t\t\tconst uIdx = uIdxRaw ?? 0;\n\t\t\tconst vIdx = vIdxRaw ?? 0;\n\t\t\tif (uIdxRaw !== undefined && vIdxRaw !== undefined) {\n\t\t\t\tuArr[i] = uIdx;\n\t\t\t\tvArr[i] = vIdx;\n\t\t\t\tvalidPair[i] = true;\n\t\t\t} else {\n\t\t\t\tuArr[i] = 0;\n\t\t\t\tvArr[i] = 0;\n\t\t\t\tvalidPair[i] = false;\n\t\t\t}\n\t\t}\n\n\t\t// Create GPU buffers\n\t\tconst pairsUBuffer = root\n\t\t\t.createBuffer(\n\t\t\t\td.arrayOf(d.u32, pairCount),\n\t\t\t\t// TypeGPU type constraints are complex; TypedArrays are compatible with buffer initialization\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument\n\t\t\t\tArray.from(uArr) as any,\n\t\t\t)\n\t\t\t.$usage(\"storage\");\n\t\tconst pairsVBuffer = root\n\t\t\t.createBuffer(\n\t\t\t\td.arrayOf(d.u32, pairCount),\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument\n\t\t\t\tArray.from(vArr) as any,\n\t\t\t)\n\t\t\t.$usage(\"storage\");\n\n\t\tconst intersectionsBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, pairCount))\n\t\t\t.$usage(\"storage\");\n\t\tconst sizeUsBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, pairCount))\n\t\t\t.$usage(\"storage\");\n\t\tconst sizeVsBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, pairCount))\n\t\t\t.$usage(\"storage\");\n\n\t\tif (variant === \"adamic-adar\") {\n\t\t\t// Dispatch dedicated Adamic-Adar kernel which also writes raw counts\n\t\t\tconst resultsBuffer = root\n\t\t\t\t.createBuffer(d.arrayOf(d.f32, pairCount))\n\t\t\t\t.$usage(\"storage\");\n\n\t\t\tconst { dispatchAdamicAdar } =\n\t\t\t\tawait import(\"./kernels/adamic-adar/kernel.js\");\n\t\t\tdispatchAdamicAdar(\n\t\t\t\troot,\n\t\t\t\tcsrBuffers,\n\t\t\t\tpairsUBuffer,\n\t\t\t\tpairsVBuffer,\n\t\t\t\tresultsBuffer,\n\t\t\t\tintersectionsBuffer,\n\t\t\t\tsizeUsBuffer,\n\t\t\t\tsizeVsBuffer,\n\t\t\t\tpairCount,\n\t\t\t);\n\n\t\t\tconst scoresRaw = await resultsBuffer.read();\n\t\t\tconst intersectionsRaw = await intersectionsBuffer.read();\n\t\t\tconst sizeUsRaw = await sizeUsBuffer.read();\n\t\t\tconst sizeVsRaw = await sizeVsBuffer.read();\n\n\t\t\tconst scores = new Float32Array(scoresRaw);\n\t\t\tconst intersections = new Uint32Array(intersectionsRaw);\n\t\t\tconst sizeUs = new Uint32Array(sizeUsRaw);\n\t\t\tconst sizeVs = new Uint32Array(sizeVsRaw);\n\n\t\t\t// Zero-out invalid pairs\n\t\t\tfor (let i = 0; i < pairCount; i++) {\n\t\t\t\tif (validPair[i] !== true) {\n\t\t\t\t\tscores[i] = 0;\n\t\t\t\t\tintersections[i] = 0;\n\t\t\t\t\tsizeUs[i] = 0;\n\t\t\t\t\tsizeVs[i] = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { scores, intersections, sizeUs, sizeVs };\n\t\t} else {\n\t\t\t// Dispatch intersection kernel\n\t\t\tconst { dispatchIntersection } =\n\t\t\t\tawait import(\"./kernels/intersection/kernel.js\");\n\t\t\tdispatchIntersection(\n\t\t\t\troot,\n\t\t\t\tcsrBuffers,\n\t\t\t\tpairsUBuffer,\n\t\t\t\tpairsVBuffer,\n\t\t\t\tintersectionsBuffer,\n\t\t\t\tsizeUsBuffer,\n\t\t\t\tsizeVsBuffer,\n\t\t\t\tpairCount,\n\t\t\t);\n\n\t\t\t// Read back results\n\t\t\tconst intersectionsRaw = await intersectionsBuffer.read();\n\t\t\tconst sizeUsRaw = await sizeUsBuffer.read();\n\t\t\tconst sizeVsRaw = await sizeVsBuffer.read();\n\n\t\t\tconst intersections = new Uint32Array(intersectionsRaw);\n\t\t\tconst sizeUs = new Uint32Array(sizeUsRaw);\n\t\t\tconst sizeVs = new Uint32Array(sizeVsRaw);\n\n\t\t\t// Compute MI scores on CPU from raw counts (and apply GPU-side corrections)\n\t\t\tconst scores = new Float32Array(pairCount);\n\t\t\tif (variant === \"scale\" || variant === \"skew\" || variant === \"span\") {\n\t\t\t\t// Precompute helpers\n\t\t\t\tconst clustering =\n\t\t\t\t\tvariant === \"span\" ? computeClusteringCoefficients(csr) : undefined;\n\t\t\t\tconst N = csr.rowOffsets.length - 1;\n\t\t\t\tconst rho = variant === \"scale\" ? computeGraphDensity(csr) : undefined;\n\n\t\t\t\tfor (let i = 0; i < pairCount; i++) {\n\t\t\t\t\tif (validPair[i] !== true) {\n\t\t\t\t\t\tscores[i] = 0;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst result: IntersectionResult = {\n\t\t\t\t\t\tintersection: intersections[i] ?? 0,\n\t\t\t\t\t\tsizeU: sizeUs[i] ?? 0,\n\t\t\t\t\t\tsizeV: sizeVs[i] ?? 0,\n\t\t\t\t\t};\n\t\t\t\t\tconst base = applyMIVariant(result, \"jaccard\");\n\t\t\t\t\tswitch (variant) {\n\t\t\t\t\t\tcase \"scale\":\n\t\t\t\t\t\t\tif (rho !== undefined && rho > 0) scores[i] = base / rho;\n\t\t\t\t\t\t\telse scores[i] = base;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"skew\": {\n\t\t\t\t\t\t\tconst degU = result.sizeU;\n\t\t\t\t\t\t\tconst degV = result.sizeV;\n\t\t\t\t\t\t\tconst w = Math.log(N / (degU + 1)) * Math.log(N / (degV + 1));\n\t\t\t\t\t\t\tscores[i] = base * w;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase \"span\": {\n\t\t\t\t\t\t\tconst pair = pairs[i];\n\t\t\t\t\t\t\tconst uId = pair ? pair[0] : undefined;\n\t\t\t\t\t\t\tconst vId = pair ? pair[1] : undefined;\n\t\t\t\t\t\t\tconst uIdx =\n\t\t\t\t\t\t\t\tuId !== undefined ? indexMap.nodeToIndex.get(uId) : undefined;\n\t\t\t\t\t\t\tconst vIdx =\n\t\t\t\t\t\t\t\tvId !== undefined ? indexMap.nodeToIndex.get(vId) : undefined;\n\t\t\t\t\t\t\tconst cu = uIdx !== undefined ? (clustering?.[uIdx] ?? 0) : 0;\n\t\t\t\t\t\t\tconst cv = vIdx !== undefined ? (clustering?.[vIdx] ?? 0) : 0;\n\t\t\t\t\t\t\tscores[i] = base * (1 - Math.max(cu, cv));\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (let i = 0; i < pairCount; i++) {\n\t\t\t\t\tif (validPair[i] !== true) {\n\t\t\t\t\t\tscores[i] = 0;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst result: IntersectionResult = {\n\t\t\t\t\t\tintersection: intersections[i] ?? 0,\n\t\t\t\t\t\tsizeU: sizeUs[i] ?? 0,\n\t\t\t\t\t\tsizeV: sizeVs[i] ?? 0,\n\t\t\t\t\t};\n\t\t\t\t\tscores[i] = applyMIVariant(result, variant);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { scores, intersections, sizeUs, sizeVs };\n\t\t}\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n\n/**\n * Apply MI variant formula to intersection result.\n */\nfunction computeGraphDensity(csr: CSRMatrix): number {\n\tconst n = csr.rowOffsets.length - 1;\n\tconst m = csr.colIndices.length;\n\treturn n > 1 ? (2 * m) / (n * (n - 1)) : 0;\n}\n\nfunction computeClusteringCoefficients(csr: CSRMatrix): number[] {\n\t// Naive local clustering coefficient per node: 2 * number of closed triplets / (deg * (deg-1))\n\tconst n = csr.rowOffsets.length - 1;\n\tconst coeffs = new Array<number>(n).fill(0);\n\tfor (let v = 0; v < n; v++) {\n\t\tconst start = csr.rowOffsets[v] ?? 0;\n\t\tconst end = csr.rowOffsets[v + 1] ?? 0;\n\t\tconst deg = end - start;\n\t\tif (deg < 2) {\n\t\t\tcoeffs[v] = 0;\n\t\t\tcontinue;\n\t\t}\n\t\tconst neighbours = new Set(csr.colIndices.slice(start, end));\n\t\tlet links = 0;\n\t\tfor (const u of neighbours) {\n\t\t\tconst uStart = csr.rowOffsets[u] ?? 0;\n\t\t\tconst uEnd = csr.rowOffsets[u + 1] ?? 0;\n\t\t\tfor (let k = uStart; k < uEnd; k++) {\n\t\t\t\tconst colIdx = csr.colIndices[k] ?? 0;\n\t\t\t\tif (neighbours.has(colIdx)) links++;\n\t\t\t}\n\t\t}\n\t\t// each edge counted twice\n\t\tcoeffs[v] = (2 * links) / (deg * (deg - 1));\n\t}\n\treturn coeffs;\n}\n\nfunction applyMIVariant(\n\tresult: IntersectionResult,\n\tvariant: MIVariantName,\n): number {\n\tswitch (variant) {\n\t\tcase \"jaccard\":\n\t\t\treturn jaccardFromIntersection(result);\n\t\tcase \"cosine\":\n\t\t\treturn cosineFromIntersection(result);\n\t\tcase \"sorensen\":\n\t\t\treturn sorensenDiceFromIntersection(result);\n\t\tcase \"overlap-coefficient\":\n\t\t\treturn overlapFromIntersection(result);\n\t\tcase \"hub-promoted\":\n\t\t\treturn hubPromotedFromIntersection(result);\n\t\tcase \"resource-allocation\":\n\t\t\t// Resource allocation requires shared neighbour degrees\n\t\t\t// Fall back to Jaccard for now - dedicated kernel needed\n\t\t\treturn jaccardFromIntersection(result);\n\t\tcase \"adamic-adar\":\n\t\t\t// Adamic-Adar requires shared neighbour degrees\n\t\t\t// Fall back to Jaccard for now - dedicated kernel needed\n\t\t\treturn jaccardFromIntersection(result);\n\t\tcase \"scale\":\n\t\tcase \"skew\":\n\t\tcase \"span\":\n\t\tcase \"etch\":\n\t\tcase \"notch\":\n\t\tcase \"adaptive\":\n\t\t\t// Correction-based variants require additional data\n\t\t\t// Fall back to Jaccard for now\n\t\t\treturn jaccardFromIntersection(result);\n\t\tdefault:\n\t\t\treturn jaccardFromIntersection(result);\n\t}\n}\n\n/**\n * Result of K-means assignment step.\n */\nexport interface KMeansAssignResult {\n\t/** Assignment index for each point (0 to k-1) */\n\treadonly assignments: Uint32Array;\n\t/** Squared distance to assigned centroid for each point */\n\treadonly distances: Float32Array;\n}\n\n/**\n * Assign points to nearest centroids using GPU.\n *\n * For each point, computes distance to all centroids and assigns to nearest.\n * This is the main parallelizable operation in K-means clustering.\n *\n * @param points - Array of 3D points to assign\n * @param centroids - Array of 3D centroid coordinates\n * @param options - Compute options\n * @returns Assignment indices and distances\n */\nexport async function gpuKMeansAssign(\n\tpoints: readonly (readonly [number, number, number])[],\n\tcentroids: readonly (readonly [number, number, number])[],\n\toptions?: GPUComputeOptions & { signal?: AbortSignal },\n): Promise<ComputeResult<KMeansAssignResult>> {\n\tconst pointCount = points.length;\n\tconst k = centroids.length;\n\n\tconst cpuFn = (): KMeansAssignResult => {\n\t\tconst assignments = new Uint32Array(pointCount);\n\t\tconst distances = new Float32Array(pointCount);\n\n\t\tfor (let i = 0; i < pointCount; i++) {\n\t\t\tconst point = points[i];\n\t\t\tif (point === undefined) {\n\t\t\t\tassignments[i] = 0;\n\t\t\t\tdistances[i] = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst [px, py, pz] = point;\n\t\t\tlet minDist = Infinity;\n\t\t\tlet minIdx = 0;\n\n\t\t\tfor (let j = 0; j < k; j++) {\n\t\t\t\tconst centroid = centroids[j];\n\t\t\t\tif (centroid === undefined) continue;\n\n\t\t\t\tconst [cx, cy, cz] = centroid;\n\t\t\t\tconst dx = px - cx;\n\t\t\t\tconst dy = py - cy;\n\t\t\t\tconst dz = pz - cz;\n\t\t\t\tconst distSq = dx * dx + dy * dy + dz * dz;\n\n\t\t\t\tif (distSq < minDist) {\n\t\t\t\t\tminDist = distSq;\n\t\t\t\t\tminIdx = j;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tassignments[i] = minIdx;\n\t\t\tdistances[i] = minDist;\n\t\t}\n\n\t\treturn { assignments, distances };\n\t};\n\n\t// GPU implementation for larger datasets\n\tconst gpuFn = async (root: GraphwiseGPURoot): Promise<KMeansAssignResult> => {\n\t\t// For now, fall back to CPU for small datasets\n\t\t// GPU has overhead that makes it slower for small batches\n\t\tif (pointCount < 100) {\n\t\t\treturn cpuFn();\n\t\t}\n\n\t\tconst pointsBuffer = root\n\t\t\t.createBuffer(\n\t\t\t\td.arrayOf(d.vec3f, pointCount),\n\t\t\t\t// TypeGPU type constraints are complex; TypedArrays are compatible with buffer initialization\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument\n\t\t\t\tArray.from(points) as any,\n\t\t\t)\n\t\t\t.$usage(\"storage\");\n\n\t\tconst centroidsBuffer = root\n\t\t\t.createBuffer(\n\t\t\t\td.arrayOf(d.vec3f, k),\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument\n\t\t\t\tArray.from(centroids) as any,\n\t\t\t)\n\t\t\t.$usage(\"storage\");\n\n\t\tconst assignmentsBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.u32, pointCount))\n\t\t\t.$usage(\"storage\");\n\n\t\tconst distancesBuffer = root\n\t\t\t.createBuffer(d.arrayOf(d.f32, pointCount))\n\t\t\t.$usage(\"storage\");\n\n\t\t// Dispatch assignment kernel\n\t\tconst { dispatchKMeansAssign: dispatch } =\n\t\t\tawait import(\"./kernels/kmeans/kernel.js\");\n\t\tdispatch(\n\t\t\troot,\n\t\t\tpointsBuffer,\n\t\t\tcentroidsBuffer,\n\t\t\tassignmentsBuffer,\n\t\t\tdistancesBuffer,\n\t\t\tpointCount,\n\t\t\tk,\n\t\t);\n\n\t\tconst assignments = await assignmentsBuffer.read();\n\t\tconst distances = await distancesBuffer.read();\n\n\t\treturn {\n\t\t\tassignments: new Uint32Array(assignments),\n\t\t\tdistances: new Float32Array(distances),\n\t\t};\n\t};\n\n\tconst dispatchOpts: DispatchOptions = {\n\t\tbackend: options?.backend,\n\t\troot: options?.root,\n\t\tsignal: options?.signal,\n\t};\n\n\treturn withBackend(dispatchOpts, cpuFn, gpuFn);\n}\n"],"mappings":"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"}
@@ -1976,7 +1976,7 @@ async function gpuMIBatch(graph, pairs, variant = "jaccard", options) {
1976
1976
  const sizeVsBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.u32, pairCount)).$usage("storage"), "sizeVsBuffer");
1977
1977
  if (variant === "adamic-adar") {
1978
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");
1979
+ const { dispatchAdamicAdar } = await import("./kernel-DolEKSSx.js");
1980
1980
  dispatchAdamicAdar(root, csrBuffers, pairsUBuffer, pairsVBuffer, resultsBuffer, intersectionsBuffer, sizeUsBuffer, sizeVsBuffer, pairCount);
1981
1981
  const scoresRaw = await resultsBuffer.read();
1982
1982
  const intersectionsRaw = await intersectionsBuffer.read();
@@ -1999,7 +1999,7 @@ async function gpuMIBatch(graph, pairs, variant = "jaccard", options) {
1999
1999
  sizeVs
2000
2000
  };
2001
2001
  } else {
2002
- const { dispatchIntersection } = await import("./kernel-6deK9fh1.js");
2002
+ const { dispatchIntersection } = await import("./kernel-lYa4TYth.js");
2003
2003
  dispatchIntersection(root, csrBuffers, pairsUBuffer, pairsVBuffer, intersectionsBuffer, sizeUsBuffer, sizeVsBuffer, pairCount);
2004
2004
  const intersectionsRaw = await intersectionsBuffer.read();
2005
2005
  const sizeUsRaw = await sizeUsBuffer.read();
@@ -2177,7 +2177,7 @@ async function gpuKMeansAssign(points, centroids, options) {
2177
2177
  const centroidsBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.vec3f, k), Array.from(centroids)).$usage("storage"), "centroidsBuffer");
2178
2178
  const assignmentsBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((a) => a))(root.createBuffer(data_exports.arrayOf(data_exports.u32, pointCount)).$usage("storage"), "assignmentsBuffer");
2179
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");
2180
+ const { dispatchKMeansAssign: dispatch } = await import("./kernel-BLwhyVSV.js");
2181
2181
  dispatch(root, pointsBuffer, centroidsBuffer, assignmentsBuffer, distancesBuffer, pointCount, k);
2182
2182
  const assignments = await assignmentsBuffer.read();
2183
2183
  const distances = await distancesBuffer.read();
@@ -2195,4 +2195,4 @@ async function gpuKMeansAssign(points, centroids, options) {
2195
2195
  //#endregion
2196
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
2197
 
2198
- //# sourceMappingURL=operations-D9otVlIH.js.map
2198
+ //# sourceMappingURL=operations-CdrA87Au.js.map