graphwise 1.9.0 → 1.10.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.
- package/dist/async/index.cjs +98 -1
- package/dist/async/index.cjs.map +1 -0
- package/dist/async/index.d.ts +1 -0
- package/dist/async/index.d.ts.map +1 -1
- package/dist/async/index.js +96 -2
- package/dist/async/index.js.map +1 -0
- package/dist/async/ops.d.ts +2 -0
- package/dist/async/ops.d.ts.map +1 -1
- package/dist/async/protocol.d.ts +14 -0
- package/dist/async/protocol.d.ts.map +1 -1
- package/dist/async/runner-batched.d.ts +21 -0
- package/dist/async/runner-batched.d.ts.map +1 -0
- package/dist/async/runner-batched.unit.test.d.ts +2 -0
- package/dist/async/runner-batched.unit.test.d.ts.map +1 -0
- package/dist/async/runners.d.ts.map +1 -1
- package/dist/expansion/base-core.d.ts.map +1 -1
- package/dist/expansion/fuse.d.ts +24 -1
- package/dist/expansion/fuse.d.ts.map +1 -1
- package/dist/expansion/index.cjs +9 -1
- package/dist/expansion/index.js +2 -2
- package/dist/expansion/lace.d.ts +23 -2
- package/dist/expansion/lace.d.ts.map +1 -1
- package/dist/expansion/priority-helpers.d.ts +20 -1
- package/dist/expansion/priority-helpers.d.ts.map +1 -1
- package/dist/expansion/sift.d.ts +24 -1
- package/dist/expansion/sift.d.ts.map +1 -1
- package/dist/expansion/types.d.ts +30 -0
- package/dist/expansion/types.d.ts.map +1 -1
- package/dist/{expansion-DaTroIyv.cjs → expansion--UuRowv-.cjs} +267 -4
- package/dist/expansion--UuRowv-.cjs.map +1 -0
- package/dist/{expansion-ClDhlMK8.js → expansion-CZLNK6Pr.js} +220 -5
- package/dist/expansion-CZLNK6Pr.js.map +1 -0
- package/dist/gpu/csr-graph.d.ts +68 -0
- package/dist/gpu/csr-graph.d.ts.map +1 -0
- package/dist/gpu/csr-graph.unit.test.d.ts +2 -0
- package/dist/gpu/csr-graph.unit.test.d.ts.map +1 -0
- package/dist/gpu/index.cjs +220 -15
- package/dist/gpu/index.cjs.map +1 -0
- package/dist/gpu/index.d.ts +1 -0
- package/dist/gpu/index.d.ts.map +1 -1
- package/dist/gpu/index.js +204 -2
- package/dist/gpu/index.js.map +1 -0
- package/dist/gpu/kernels/adamic-adar/kernel.d.ts +39 -0
- package/dist/gpu/kernels/adamic-adar/kernel.d.ts.map +1 -0
- package/dist/gpu/kernels/intersection/kernel.d.ts +50 -0
- package/dist/gpu/kernels/intersection/kernel.d.ts.map +1 -0
- package/dist/gpu/kernels/intersection/logic.d.ts +87 -0
- package/dist/gpu/kernels/intersection/logic.d.ts.map +1 -0
- package/dist/gpu/kernels/intersection/logic.unit.test.d.ts +2 -0
- package/dist/gpu/kernels/intersection/logic.unit.test.d.ts.map +1 -0
- package/dist/gpu/kernels/kmeans/index.d.ts +6 -0
- package/dist/gpu/kernels/kmeans/index.d.ts.map +1 -0
- package/dist/gpu/kernels/kmeans/kernel.d.ts +34 -0
- package/dist/gpu/kernels/kmeans/kernel.d.ts.map +1 -0
- package/dist/gpu/kernels/kmeans/logic.d.ts +111 -0
- package/dist/gpu/kernels/kmeans/logic.d.ts.map +1 -0
- package/dist/gpu/kernels/kmeans/logic.unit.test.d.ts +5 -0
- package/dist/gpu/kernels/kmeans/logic.unit.test.d.ts.map +1 -0
- package/dist/gpu/operations.d.ts +52 -0
- package/dist/gpu/operations.d.ts.map +1 -1
- package/dist/index/index.cjs +38 -19
- package/dist/index/index.js +10 -8
- package/dist/{jaccard-Bys9_dGW.cjs → jaccard-Bdw4B0i4.cjs} +1 -1
- package/dist/{jaccard-Bys9_dGW.cjs.map → jaccard-Bdw4B0i4.cjs.map} +1 -1
- package/dist/{jaccard-3rCdilwm.js → jaccard-BwC_NuQu.js} +1 -1
- package/dist/{jaccard-3rCdilwm.js.map → jaccard-BwC_NuQu.js.map} +1 -1
- package/dist/kernel-2oH4Cn32.cjs +1001 -0
- package/dist/kernel-2oH4Cn32.cjs.map +1 -0
- package/dist/kernel-6deK9fh1.js +724 -0
- package/dist/kernel-6deK9fh1.js.map +1 -0
- package/dist/kernel-CXeGBH3s.cjs +467 -0
- package/dist/kernel-CXeGBH3s.cjs.map +1 -0
- package/dist/kernel-CigCjrts.js +467 -0
- package/dist/kernel-CigCjrts.js.map +1 -0
- package/dist/kernel-CvnRsF7E.js +1001 -0
- package/dist/kernel-CvnRsF7E.js.map +1 -0
- package/dist/kernel-DukrXtVb.cjs +724 -0
- package/dist/kernel-DukrXtVb.cjs.map +1 -0
- package/dist/{kmeans-B8x9D1kt.cjs → kmeans-CZ7tJFYw.cjs} +1 -1
- package/dist/{kmeans-B8x9D1kt.cjs.map → kmeans-CZ7tJFYw.cjs.map} +1 -1
- package/dist/{kmeans-DKkL9rAN.js → kmeans-DLrlrp6i.js} +1 -1
- package/dist/{kmeans-DKkL9rAN.js.map → kmeans-DLrlrp6i.js.map} +1 -1
- package/dist/logic-Dbyfb_-7.cjs +289 -0
- package/dist/logic-Dbyfb_-7.cjs.map +1 -0
- package/dist/logic-DyBzRg1A.js +242 -0
- package/dist/logic-DyBzRg1A.js.map +1 -0
- package/dist/operations-D-RB67WP.cjs +2269 -0
- package/dist/operations-D-RB67WP.cjs.map +1 -0
- package/dist/operations-D9otVlIH.js +2198 -0
- package/dist/operations-D9otVlIH.js.map +1 -0
- package/dist/{ops-upIi6JIi.js → ops-D5xZr4fV.js} +60 -2
- package/dist/ops-D5xZr4fV.js.map +1 -0
- package/dist/{ops-djAsQQSh.cjs → ops-paa1Nvlf.cjs} +71 -1
- package/dist/ops-paa1Nvlf.cjs.map +1 -0
- package/dist/ranking/baselines/communicability.d.ts +12 -0
- package/dist/ranking/baselines/communicability.d.ts.map +1 -1
- package/dist/ranking/baselines/katz.d.ts +12 -0
- package/dist/ranking/baselines/katz.d.ts.map +1 -1
- package/dist/ranking/baselines/pagerank.d.ts +15 -0
- package/dist/ranking/baselines/pagerank.d.ts.map +1 -1
- package/dist/ranking/baselines/types.d.ts +3 -0
- package/dist/ranking/baselines/types.d.ts.map +1 -1
- package/dist/ranking/index.cjs +5 -2
- package/dist/ranking/index.js +3 -3
- package/dist/ranking/mi/index.cjs +1 -1
- package/dist/ranking/mi/index.js +1 -1
- package/dist/ranking/parse-gpu.d.ts +31 -0
- package/dist/ranking/parse-gpu.d.ts.map +1 -0
- package/dist/ranking/parse-gpu.unit.test.d.ts +5 -0
- package/dist/ranking/parse-gpu.unit.test.d.ts.map +1 -0
- package/dist/ranking/parse.d.ts.map +1 -1
- package/dist/{ranking-3ez5m67U.js → ranking-DOKDBcIR.js} +237 -11
- package/dist/ranking-DOKDBcIR.js.map +1 -0
- package/dist/{ranking-DVvajgUZ.cjs → ranking-pe5UaxKg.cjs} +254 -10
- package/dist/ranking-pe5UaxKg.cjs.map +1 -0
- package/dist/schemas/graph.d.ts +1 -1
- package/dist/seeds/grasp-gpu.d.ts +40 -0
- package/dist/seeds/grasp-gpu.d.ts.map +1 -0
- package/dist/seeds/index.cjs +1 -1
- package/dist/seeds/index.js +1 -1
- package/dist/{gpu-CHiCN0wa.js → typegpu-Dq5FfUB8.cjs} +16 -2041
- package/dist/typegpu-Dq5FfUB8.cjs.map +1 -0
- package/dist/{gpu-Y6owRVMi.cjs → typegpu-DwnJf28i.js} +2 -2127
- package/dist/typegpu-DwnJf28i.js.map +1 -0
- package/dist/utils/index.cjs +1 -1
- package/dist/utils/index.js +1 -1
- package/package.json +1 -1
- package/dist/expansion-ClDhlMK8.js.map +0 -1
- package/dist/expansion-DaTroIyv.cjs.map +0 -1
- package/dist/gpu-CHiCN0wa.js.map +0 -1
- package/dist/gpu-Y6owRVMi.cjs.map +0 -1
- package/dist/ops-djAsQQSh.cjs.map +0 -1
- package/dist/ops-upIi6JIi.js.map +0 -1
- package/dist/ranking-3ez5m67U.js.map +0 -1
- package/dist/ranking-DVvajgUZ.cjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations-D9otVlIH.js","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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"}
|
|
@@ -32,6 +32,22 @@ function resolveSyncOp(graph, op) {
|
|
|
32
32
|
tag: "hasNode",
|
|
33
33
|
value: graph.hasNode(op.id)
|
|
34
34
|
};
|
|
35
|
+
case "batchNeighbours": {
|
|
36
|
+
const result = /* @__PURE__ */ new Map();
|
|
37
|
+
for (const id of op.ids) result.set(id, Array.from(graph.neighbours(id, op.direction)));
|
|
38
|
+
return {
|
|
39
|
+
tag: "batchNeighbours",
|
|
40
|
+
value: result
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
case "batchDegree": {
|
|
44
|
+
const result = /* @__PURE__ */ new Map();
|
|
45
|
+
for (const id of op.ids) result.set(id, graph.degree(id, op.direction));
|
|
46
|
+
return {
|
|
47
|
+
tag: "batchDegree",
|
|
48
|
+
value: result
|
|
49
|
+
};
|
|
50
|
+
}
|
|
35
51
|
case "yield": return { tag: "yield" };
|
|
36
52
|
case "progress": return { tag: "progress" };
|
|
37
53
|
}
|
|
@@ -87,6 +103,24 @@ async function resolveAsyncOp(graph, op) {
|
|
|
87
103
|
tag: "hasNode",
|
|
88
104
|
value: await graph.hasNode(op.id)
|
|
89
105
|
};
|
|
106
|
+
case "batchNeighbours": {
|
|
107
|
+
const promises = op.ids.map(async (id) => {
|
|
108
|
+
return [id, await collectAsyncIterable(graph.neighbours(id, op.direction))];
|
|
109
|
+
});
|
|
110
|
+
const results = await Promise.all(promises);
|
|
111
|
+
return {
|
|
112
|
+
tag: "batchNeighbours",
|
|
113
|
+
value: new Map(results)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
case "batchDegree": {
|
|
117
|
+
const promises = op.ids.map(async (id) => [id, await graph.degree(id, op.direction)]);
|
|
118
|
+
const results = await Promise.all(promises);
|
|
119
|
+
return {
|
|
120
|
+
tag: "batchDegree",
|
|
121
|
+
value: new Map(results)
|
|
122
|
+
};
|
|
123
|
+
}
|
|
90
124
|
case "yield": return { tag: "yield" };
|
|
91
125
|
case "progress": return { tag: "progress" };
|
|
92
126
|
}
|
|
@@ -206,7 +240,31 @@ function* opProgress(stats) {
|
|
|
206
240
|
stats
|
|
207
241
|
};
|
|
208
242
|
}
|
|
243
|
+
function* opBatchNeighbours(ids, direction) {
|
|
244
|
+
const response = yield direction !== void 0 ? {
|
|
245
|
+
tag: "batchNeighbours",
|
|
246
|
+
ids,
|
|
247
|
+
direction
|
|
248
|
+
} : {
|
|
249
|
+
tag: "batchNeighbours",
|
|
250
|
+
ids
|
|
251
|
+
};
|
|
252
|
+
if (response.tag !== "batchNeighbours") throw new TypeError(`Expected batchNeighbours response, got ${response.tag}`);
|
|
253
|
+
return response.value;
|
|
254
|
+
}
|
|
255
|
+
function* opBatchDegree(ids, direction) {
|
|
256
|
+
const response = yield direction !== void 0 ? {
|
|
257
|
+
tag: "batchDegree",
|
|
258
|
+
ids,
|
|
259
|
+
direction
|
|
260
|
+
} : {
|
|
261
|
+
tag: "batchDegree",
|
|
262
|
+
ids
|
|
263
|
+
};
|
|
264
|
+
if (response.tag !== "batchDegree") throw new TypeError(`Expected batchDegree response, got ${response.tag}`);
|
|
265
|
+
return response.value;
|
|
266
|
+
}
|
|
209
267
|
//#endregion
|
|
210
|
-
export {
|
|
268
|
+
export { opGetNode as a, opProgress as c, resolveSyncOp as d, runAsync as f, opGetEdge as i, opYield as l, opBatchNeighbours as n, opHasNode as o, runSync as p, opDegree as r, opNeighbours as s, opBatchDegree as t, resolveAsyncOp as u };
|
|
211
269
|
|
|
212
|
-
//# sourceMappingURL=ops-
|
|
270
|
+
//# sourceMappingURL=ops-D5xZr4fV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops-D5xZr4fV.js","names":[],"sources":["../src/async/runners.ts","../src/async/ops.ts"],"sourcesContent":["/**\n * Sync and async runners for generator-based graph algorithms.\n *\n * The runner drives a generator that yields GraphOp objects, resolves each op\n * against the graph, and feeds the result back via gen.next(response). This\n * allows algorithm logic to be written once as a generator and executed\n * synchronously or asynchronously depending on the graph backing.\n *\n * @module async/runners\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport type { AsyncReadableGraph } from \"../graph/async-interfaces\";\nimport type { GraphOp, GraphOpResponse } from \"./protocol\";\nimport type { AsyncRunnerOptions } from \"./types\";\nimport { collectAsyncIterable, defaultYieldStrategy } from \"./utils\";\n\n// ---------------------------------------------------------------------------\n// Sync runner\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a single GraphOp against a synchronous ReadableGraph.\n *\n * Returns a tagged GraphOpResponse so the receiving generator can narrow\n * the result type without type assertions.\n *\n * @param graph - The synchronous graph to query\n * @param op - The operation to resolve\n * @returns The tagged response\n */\nexport function resolveSyncOp<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\top: GraphOp,\n): GraphOpResponse<N, E> {\n\tswitch (op.tag) {\n\t\tcase \"neighbours\":\n\t\t\treturn {\n\t\t\t\ttag: \"neighbours\",\n\t\t\t\tvalue: Array.from(graph.neighbours(op.id, op.direction)),\n\t\t\t};\n\t\tcase \"degree\":\n\t\t\treturn { tag: \"degree\", value: graph.degree(op.id, op.direction) };\n\t\tcase \"getNode\":\n\t\t\treturn { tag: \"getNode\", value: graph.getNode(op.id) };\n\t\tcase \"getEdge\":\n\t\t\treturn { tag: \"getEdge\", value: graph.getEdge(op.source, op.target) };\n\t\tcase \"hasNode\":\n\t\t\treturn { tag: \"hasNode\", value: graph.hasNode(op.id) };\n\t\tcase \"batchNeighbours\": {\n\t\t\tconst result = new Map<NodeId, readonly NodeId[]>();\n\t\t\tfor (const id of op.ids) {\n\t\t\t\tresult.set(id, Array.from(graph.neighbours(id, op.direction)));\n\t\t\t}\n\t\t\treturn { tag: \"batchNeighbours\", value: result };\n\t\t}\n\t\tcase \"batchDegree\": {\n\t\t\tconst result = new Map<NodeId, number>();\n\t\t\tfor (const id of op.ids) {\n\t\t\t\tresult.set(id, graph.degree(id, op.direction));\n\t\t\t}\n\t\t\treturn { tag: \"batchDegree\", value: result };\n\t\t}\n\t\tcase \"yield\":\n\t\t\treturn { tag: \"yield\" };\n\t\tcase \"progress\":\n\t\t\treturn { tag: \"progress\" };\n\t}\n}\n\n/**\n * Drive a generator to completion using a synchronous graph.\n *\n * The generator yields GraphOp requests; each is resolved immediately\n * against the graph and the tagged response is fed back via gen.next().\n *\n * @param gen - The generator to drive\n * @param graph - The graph to resolve ops against\n * @returns The generator's return value\n */\nexport function runSync<N extends NodeData, E extends EdgeData, R>(\n\tgen: Generator<GraphOp, R, GraphOpResponse<N, E>>,\n\tgraph: ReadableGraph<N, E>,\n): R {\n\tlet step = gen.next();\n\twhile (step.done !== true) {\n\t\tconst response = resolveSyncOp(graph, step.value);\n\t\tstep = gen.next(response);\n\t}\n\treturn step.value;\n}\n\n// ---------------------------------------------------------------------------\n// Async runner\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a single GraphOp against an async ReadableGraph.\n *\n * AsyncIterables (neighbours) are collected into readonly arrays so the\n * generator receives the same value type as in sync mode. Returns a tagged\n * GraphOpResponse for type-safe narrowing without assertions.\n *\n * @param graph - The async graph to query\n * @param op - The operation to resolve\n * @returns A promise resolving to the tagged response\n */\nexport async function resolveAsyncOp<N extends NodeData, E extends EdgeData>(\n\tgraph: AsyncReadableGraph<N, E>,\n\top: GraphOp,\n): Promise<GraphOpResponse<N, E>> {\n\tswitch (op.tag) {\n\t\tcase \"neighbours\":\n\t\t\treturn {\n\t\t\t\ttag: \"neighbours\",\n\t\t\t\tvalue: await collectAsyncIterable(\n\t\t\t\t\tgraph.neighbours(op.id, op.direction),\n\t\t\t\t),\n\t\t\t};\n\t\tcase \"degree\":\n\t\t\treturn { tag: \"degree\", value: await graph.degree(op.id, op.direction) };\n\t\tcase \"getNode\":\n\t\t\treturn { tag: \"getNode\", value: await graph.getNode(op.id) };\n\t\tcase \"getEdge\":\n\t\t\treturn {\n\t\t\t\ttag: \"getEdge\",\n\t\t\t\tvalue: await graph.getEdge(op.source, op.target),\n\t\t\t};\n\t\tcase \"hasNode\":\n\t\t\treturn { tag: \"hasNode\", value: await graph.hasNode(op.id) };\n\t\tcase \"batchNeighbours\": {\n\t\t\tconst promises = op.ids.map(async (id) => {\n\t\t\t\tconst neighbours = await collectAsyncIterable(\n\t\t\t\t\tgraph.neighbours(id, op.direction),\n\t\t\t\t);\n\t\t\t\treturn [id, neighbours] as const;\n\t\t\t});\n\t\t\tconst results = await Promise.all(promises);\n\t\t\treturn { tag: \"batchNeighbours\", value: new Map(results) };\n\t\t}\n\t\tcase \"batchDegree\": {\n\t\t\tconst promises = op.ids.map(\n\t\t\t\tasync (id) => [id, await graph.degree(id, op.direction)] as const,\n\t\t\t);\n\t\t\tconst results = await Promise.all(promises);\n\t\t\treturn { tag: \"batchDegree\", value: new Map(results) };\n\t\t}\n\t\tcase \"yield\":\n\t\t\treturn { tag: \"yield\" };\n\t\tcase \"progress\":\n\t\t\treturn { tag: \"progress\" };\n\t}\n}\n\n/**\n * Drive a generator to completion using an async graph.\n *\n * Extends sync semantics with:\n * - Cancellation via AbortSignal (throws DOMException \"AbortError\")\n * - Cooperative yielding at `yield` ops (calls yieldStrategy)\n * - Progress callbacks at `progress` ops (may be async for backpressure)\n * - Error propagation: graph errors are forwarded via gen.throw(); if the\n * generator does not handle them, they propagate to the caller\n *\n * @param gen - The generator to drive\n * @param graph - The async graph to resolve ops against\n * @param options - Runner configuration\n * @returns A promise resolving to the generator's return value\n */\nexport async function runAsync<N extends NodeData, E extends EdgeData, R>(\n\tgen: Generator<GraphOp, R, GraphOpResponse<N, E>>,\n\tgraph: AsyncReadableGraph<N, E>,\n\toptions?: AsyncRunnerOptions,\n): Promise<R> {\n\tconst signal = options?.signal;\n\tconst onProgress = options?.onProgress;\n\tconst yieldStrategy = options?.yieldStrategy ?? defaultYieldStrategy;\n\n\tlet step = gen.next();\n\n\twhile (step.done !== true) {\n\t\t// Check for cancellation before processing each op. Throw the error\n\t\t// into the generator so that any finally blocks in the algorithm run\n\t\t// before the error propagates to the caller.\n\t\tif (signal?.aborted === true) {\n\t\t\tconst abortError = new DOMException(\"Aborted\", \"AbortError\");\n\t\t\ttry {\n\t\t\t\tgen.throw(abortError);\n\t\t\t} catch {\n\t\t\t\t// Generator did not handle the error — propagate it\n\t\t\t\tthrow abortError;\n\t\t\t}\n\t\t\t// Generator handled the error but we still honour cancellation\n\t\t\tthrow abortError;\n\t\t}\n\n\t\tconst op = step.value;\n\n\t\t// Handle cooperative yield ops without hitting the graph\n\t\tif (op.tag === \"yield\") {\n\t\t\tawait yieldStrategy();\n\t\t\tstep = gen.next({ tag: \"yield\" });\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Handle progress ops: call the callback (awaiting if async)\n\t\tif (op.tag === \"progress\") {\n\t\t\tif (onProgress !== undefined) {\n\t\t\t\tconst maybePromise = onProgress(op.stats);\n\t\t\t\tif (maybePromise instanceof Promise) {\n\t\t\t\t\tawait maybePromise;\n\t\t\t\t}\n\t\t\t}\n\t\t\tstep = gen.next({ tag: \"progress\" });\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Resolve graph ops, forwarding any errors into the generator\n\t\tlet response: GraphOpResponse<N, E>;\n\t\ttry {\n\t\t\tresponse = await resolveAsyncOp(graph, op);\n\t\t} catch (error) {\n\t\t\t// Forward the error into the generator; if unhandled, it propagates\n\t\t\tstep = gen.throw(error);\n\t\t\tcontinue;\n\t\t}\n\n\t\tstep = gen.next(response);\n\t}\n\n\treturn step.value;\n}\n","/**\n * Type-safe yield helpers for graph operations.\n *\n * Each function is a sub-generator that yields one GraphOp and returns\n * the correctly-typed result. Narrowing is done via the tagged discriminated\n * union in GraphOpResponse — no type assertions needed.\n *\n * Use with `yield*` inside algorithm generators.\n *\n * @module async/ops\n */\n\nimport type { NodeId, NodeData, EdgeData, Direction } from \"../graph\";\nimport type { GraphOp, GraphOpResponse, ProgressStats } from \"./protocol\";\n\nexport function* opNeighbours<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(\n\tid: NodeId,\n\tdirection?: Direction,\n): Generator<GraphOp, readonly NodeId[], GraphOpResponse<N, E>> {\n\tconst op: GraphOp =\n\t\tdirection !== undefined\n\t\t\t? { tag: \"neighbours\", id, direction }\n\t\t\t: { tag: \"neighbours\", id };\n\tconst response: GraphOpResponse<N, E> = yield op;\n\tif (response.tag !== \"neighbours\") {\n\t\tthrow new TypeError(`Expected neighbours response, got ${response.tag}`);\n\t}\n\treturn response.value;\n}\n\nexport function* opDegree<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(\n\tid: NodeId,\n\tdirection?: Direction,\n): Generator<GraphOp, number, GraphOpResponse<N, E>> {\n\tconst op: GraphOp =\n\t\tdirection !== undefined\n\t\t\t? { tag: \"degree\", id, direction }\n\t\t\t: { tag: \"degree\", id };\n\tconst response: GraphOpResponse<N, E> = yield op;\n\tif (response.tag !== \"degree\") {\n\t\tthrow new TypeError(`Expected degree response, got ${response.tag}`);\n\t}\n\treturn response.value;\n}\n\nexport function* opGetNode<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(id: NodeId): Generator<GraphOp, N | undefined, GraphOpResponse<N, E>> {\n\tconst response: GraphOpResponse<N, E> = yield { tag: \"getNode\", id };\n\tif (response.tag !== \"getNode\") {\n\t\tthrow new TypeError(`Expected getNode response, got ${response.tag}`);\n\t}\n\treturn response.value;\n}\n\nexport function* opGetEdge<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(\n\tsource: NodeId,\n\ttarget: NodeId,\n): Generator<GraphOp, E | undefined, GraphOpResponse<N, E>> {\n\tconst response: GraphOpResponse<N, E> = yield {\n\t\ttag: \"getEdge\",\n\t\tsource,\n\t\ttarget,\n\t};\n\tif (response.tag !== \"getEdge\") {\n\t\tthrow new TypeError(`Expected getEdge response, got ${response.tag}`);\n\t}\n\treturn response.value;\n}\n\nexport function* opHasNode<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(id: NodeId): Generator<GraphOp, boolean, GraphOpResponse<N, E>> {\n\tconst response: GraphOpResponse<N, E> = yield { tag: \"hasNode\", id };\n\tif (response.tag !== \"hasNode\") {\n\t\tthrow new TypeError(`Expected hasNode response, got ${response.tag}`);\n\t}\n\treturn response.value;\n}\n\nexport function* opYield<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(): Generator<GraphOp, void, GraphOpResponse<N, E>> {\n\tyield { tag: \"yield\" };\n}\n\nexport function* opProgress<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(stats: ProgressStats): Generator<GraphOp, void, GraphOpResponse<N, E>> {\n\tyield { tag: \"progress\", stats };\n}\n\nexport function* opBatchNeighbours<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(\n\tids: readonly NodeId[],\n\tdirection?: Direction,\n): Generator<\n\tGraphOp,\n\tReadonlyMap<NodeId, readonly NodeId[]>,\n\tGraphOpResponse<N, E>\n> {\n\tconst op: GraphOp =\n\t\tdirection !== undefined\n\t\t\t? { tag: \"batchNeighbours\", ids, direction }\n\t\t\t: { tag: \"batchNeighbours\", ids };\n\tconst response: GraphOpResponse<N, E> = yield op;\n\tif (response.tag !== \"batchNeighbours\") {\n\t\tthrow new TypeError(\n\t\t\t`Expected batchNeighbours response, got ${response.tag}`,\n\t\t);\n\t}\n\treturn response.value;\n}\n\nexport function* opBatchDegree<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(\n\tids: readonly NodeId[],\n\tdirection?: Direction,\n): Generator<GraphOp, ReadonlyMap<NodeId, number>, GraphOpResponse<N, E>> {\n\tconst op: GraphOp =\n\t\tdirection !== undefined\n\t\t\t? { tag: \"batchDegree\", ids, direction }\n\t\t\t: { tag: \"batchDegree\", ids };\n\tconst response: GraphOpResponse<N, E> = yield op;\n\tif (response.tag !== \"batchDegree\") {\n\t\tthrow new TypeError(`Expected batchDegree response, got ${response.tag}`);\n\t}\n\treturn response.value;\n}\n"],"mappings":"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"}
|
|
@@ -32,6 +32,22 @@ function resolveSyncOp(graph, op) {
|
|
|
32
32
|
tag: "hasNode",
|
|
33
33
|
value: graph.hasNode(op.id)
|
|
34
34
|
};
|
|
35
|
+
case "batchNeighbours": {
|
|
36
|
+
const result = /* @__PURE__ */ new Map();
|
|
37
|
+
for (const id of op.ids) result.set(id, Array.from(graph.neighbours(id, op.direction)));
|
|
38
|
+
return {
|
|
39
|
+
tag: "batchNeighbours",
|
|
40
|
+
value: result
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
case "batchDegree": {
|
|
44
|
+
const result = /* @__PURE__ */ new Map();
|
|
45
|
+
for (const id of op.ids) result.set(id, graph.degree(id, op.direction));
|
|
46
|
+
return {
|
|
47
|
+
tag: "batchDegree",
|
|
48
|
+
value: result
|
|
49
|
+
};
|
|
50
|
+
}
|
|
35
51
|
case "yield": return { tag: "yield" };
|
|
36
52
|
case "progress": return { tag: "progress" };
|
|
37
53
|
}
|
|
@@ -87,6 +103,24 @@ async function resolveAsyncOp(graph, op) {
|
|
|
87
103
|
tag: "hasNode",
|
|
88
104
|
value: await graph.hasNode(op.id)
|
|
89
105
|
};
|
|
106
|
+
case "batchNeighbours": {
|
|
107
|
+
const promises = op.ids.map(async (id) => {
|
|
108
|
+
return [id, await require_utils.collectAsyncIterable(graph.neighbours(id, op.direction))];
|
|
109
|
+
});
|
|
110
|
+
const results = await Promise.all(promises);
|
|
111
|
+
return {
|
|
112
|
+
tag: "batchNeighbours",
|
|
113
|
+
value: new Map(results)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
case "batchDegree": {
|
|
117
|
+
const promises = op.ids.map(async (id) => [id, await graph.degree(id, op.direction)]);
|
|
118
|
+
const results = await Promise.all(promises);
|
|
119
|
+
return {
|
|
120
|
+
tag: "batchDegree",
|
|
121
|
+
value: new Map(results)
|
|
122
|
+
};
|
|
123
|
+
}
|
|
90
124
|
case "yield": return { tag: "yield" };
|
|
91
125
|
case "progress": return { tag: "progress" };
|
|
92
126
|
}
|
|
@@ -206,7 +240,43 @@ function* opProgress(stats) {
|
|
|
206
240
|
stats
|
|
207
241
|
};
|
|
208
242
|
}
|
|
243
|
+
function* opBatchNeighbours(ids, direction) {
|
|
244
|
+
const response = yield direction !== void 0 ? {
|
|
245
|
+
tag: "batchNeighbours",
|
|
246
|
+
ids,
|
|
247
|
+
direction
|
|
248
|
+
} : {
|
|
249
|
+
tag: "batchNeighbours",
|
|
250
|
+
ids
|
|
251
|
+
};
|
|
252
|
+
if (response.tag !== "batchNeighbours") throw new TypeError(`Expected batchNeighbours response, got ${response.tag}`);
|
|
253
|
+
return response.value;
|
|
254
|
+
}
|
|
255
|
+
function* opBatchDegree(ids, direction) {
|
|
256
|
+
const response = yield direction !== void 0 ? {
|
|
257
|
+
tag: "batchDegree",
|
|
258
|
+
ids,
|
|
259
|
+
direction
|
|
260
|
+
} : {
|
|
261
|
+
tag: "batchDegree",
|
|
262
|
+
ids
|
|
263
|
+
};
|
|
264
|
+
if (response.tag !== "batchDegree") throw new TypeError(`Expected batchDegree response, got ${response.tag}`);
|
|
265
|
+
return response.value;
|
|
266
|
+
}
|
|
209
267
|
//#endregion
|
|
268
|
+
Object.defineProperty(exports, "opBatchDegree", {
|
|
269
|
+
enumerable: true,
|
|
270
|
+
get: function() {
|
|
271
|
+
return opBatchDegree;
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
Object.defineProperty(exports, "opBatchNeighbours", {
|
|
275
|
+
enumerable: true,
|
|
276
|
+
get: function() {
|
|
277
|
+
return opBatchNeighbours;
|
|
278
|
+
}
|
|
279
|
+
});
|
|
210
280
|
Object.defineProperty(exports, "opDegree", {
|
|
211
281
|
enumerable: true,
|
|
212
282
|
get: function() {
|
|
@@ -274,4 +344,4 @@ Object.defineProperty(exports, "runSync", {
|
|
|
274
344
|
}
|
|
275
345
|
});
|
|
276
346
|
|
|
277
|
-
//# sourceMappingURL=ops-
|
|
347
|
+
//# sourceMappingURL=ops-paa1Nvlf.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops-paa1Nvlf.cjs","names":[],"sources":["../src/async/runners.ts","../src/async/ops.ts"],"sourcesContent":["/**\n * Sync and async runners for generator-based graph algorithms.\n *\n * The runner drives a generator that yields GraphOp objects, resolves each op\n * against the graph, and feeds the result back via gen.next(response). This\n * allows algorithm logic to be written once as a generator and executed\n * synchronously or asynchronously depending on the graph backing.\n *\n * @module async/runners\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport type { AsyncReadableGraph } from \"../graph/async-interfaces\";\nimport type { GraphOp, GraphOpResponse } from \"./protocol\";\nimport type { AsyncRunnerOptions } from \"./types\";\nimport { collectAsyncIterable, defaultYieldStrategy } from \"./utils\";\n\n// ---------------------------------------------------------------------------\n// Sync runner\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a single GraphOp against a synchronous ReadableGraph.\n *\n * Returns a tagged GraphOpResponse so the receiving generator can narrow\n * the result type without type assertions.\n *\n * @param graph - The synchronous graph to query\n * @param op - The operation to resolve\n * @returns The tagged response\n */\nexport function resolveSyncOp<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\top: GraphOp,\n): GraphOpResponse<N, E> {\n\tswitch (op.tag) {\n\t\tcase \"neighbours\":\n\t\t\treturn {\n\t\t\t\ttag: \"neighbours\",\n\t\t\t\tvalue: Array.from(graph.neighbours(op.id, op.direction)),\n\t\t\t};\n\t\tcase \"degree\":\n\t\t\treturn { tag: \"degree\", value: graph.degree(op.id, op.direction) };\n\t\tcase \"getNode\":\n\t\t\treturn { tag: \"getNode\", value: graph.getNode(op.id) };\n\t\tcase \"getEdge\":\n\t\t\treturn { tag: \"getEdge\", value: graph.getEdge(op.source, op.target) };\n\t\tcase \"hasNode\":\n\t\t\treturn { tag: \"hasNode\", value: graph.hasNode(op.id) };\n\t\tcase \"batchNeighbours\": {\n\t\t\tconst result = new Map<NodeId, readonly NodeId[]>();\n\t\t\tfor (const id of op.ids) {\n\t\t\t\tresult.set(id, Array.from(graph.neighbours(id, op.direction)));\n\t\t\t}\n\t\t\treturn { tag: \"batchNeighbours\", value: result };\n\t\t}\n\t\tcase \"batchDegree\": {\n\t\t\tconst result = new Map<NodeId, number>();\n\t\t\tfor (const id of op.ids) {\n\t\t\t\tresult.set(id, graph.degree(id, op.direction));\n\t\t\t}\n\t\t\treturn { tag: \"batchDegree\", value: result };\n\t\t}\n\t\tcase \"yield\":\n\t\t\treturn { tag: \"yield\" };\n\t\tcase \"progress\":\n\t\t\treturn { tag: \"progress\" };\n\t}\n}\n\n/**\n * Drive a generator to completion using a synchronous graph.\n *\n * The generator yields GraphOp requests; each is resolved immediately\n * against the graph and the tagged response is fed back via gen.next().\n *\n * @param gen - The generator to drive\n * @param graph - The graph to resolve ops against\n * @returns The generator's return value\n */\nexport function runSync<N extends NodeData, E extends EdgeData, R>(\n\tgen: Generator<GraphOp, R, GraphOpResponse<N, E>>,\n\tgraph: ReadableGraph<N, E>,\n): R {\n\tlet step = gen.next();\n\twhile (step.done !== true) {\n\t\tconst response = resolveSyncOp(graph, step.value);\n\t\tstep = gen.next(response);\n\t}\n\treturn step.value;\n}\n\n// ---------------------------------------------------------------------------\n// Async runner\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve a single GraphOp against an async ReadableGraph.\n *\n * AsyncIterables (neighbours) are collected into readonly arrays so the\n * generator receives the same value type as in sync mode. Returns a tagged\n * GraphOpResponse for type-safe narrowing without assertions.\n *\n * @param graph - The async graph to query\n * @param op - The operation to resolve\n * @returns A promise resolving to the tagged response\n */\nexport async function resolveAsyncOp<N extends NodeData, E extends EdgeData>(\n\tgraph: AsyncReadableGraph<N, E>,\n\top: GraphOp,\n): Promise<GraphOpResponse<N, E>> {\n\tswitch (op.tag) {\n\t\tcase \"neighbours\":\n\t\t\treturn {\n\t\t\t\ttag: \"neighbours\",\n\t\t\t\tvalue: await collectAsyncIterable(\n\t\t\t\t\tgraph.neighbours(op.id, op.direction),\n\t\t\t\t),\n\t\t\t};\n\t\tcase \"degree\":\n\t\t\treturn { tag: \"degree\", value: await graph.degree(op.id, op.direction) };\n\t\tcase \"getNode\":\n\t\t\treturn { tag: \"getNode\", value: await graph.getNode(op.id) };\n\t\tcase \"getEdge\":\n\t\t\treturn {\n\t\t\t\ttag: \"getEdge\",\n\t\t\t\tvalue: await graph.getEdge(op.source, op.target),\n\t\t\t};\n\t\tcase \"hasNode\":\n\t\t\treturn { tag: \"hasNode\", value: await graph.hasNode(op.id) };\n\t\tcase \"batchNeighbours\": {\n\t\t\tconst promises = op.ids.map(async (id) => {\n\t\t\t\tconst neighbours = await collectAsyncIterable(\n\t\t\t\t\tgraph.neighbours(id, op.direction),\n\t\t\t\t);\n\t\t\t\treturn [id, neighbours] as const;\n\t\t\t});\n\t\t\tconst results = await Promise.all(promises);\n\t\t\treturn { tag: \"batchNeighbours\", value: new Map(results) };\n\t\t}\n\t\tcase \"batchDegree\": {\n\t\t\tconst promises = op.ids.map(\n\t\t\t\tasync (id) => [id, await graph.degree(id, op.direction)] as const,\n\t\t\t);\n\t\t\tconst results = await Promise.all(promises);\n\t\t\treturn { tag: \"batchDegree\", value: new Map(results) };\n\t\t}\n\t\tcase \"yield\":\n\t\t\treturn { tag: \"yield\" };\n\t\tcase \"progress\":\n\t\t\treturn { tag: \"progress\" };\n\t}\n}\n\n/**\n * Drive a generator to completion using an async graph.\n *\n * Extends sync semantics with:\n * - Cancellation via AbortSignal (throws DOMException \"AbortError\")\n * - Cooperative yielding at `yield` ops (calls yieldStrategy)\n * - Progress callbacks at `progress` ops (may be async for backpressure)\n * - Error propagation: graph errors are forwarded via gen.throw(); if the\n * generator does not handle them, they propagate to the caller\n *\n * @param gen - The generator to drive\n * @param graph - The async graph to resolve ops against\n * @param options - Runner configuration\n * @returns A promise resolving to the generator's return value\n */\nexport async function runAsync<N extends NodeData, E extends EdgeData, R>(\n\tgen: Generator<GraphOp, R, GraphOpResponse<N, E>>,\n\tgraph: AsyncReadableGraph<N, E>,\n\toptions?: AsyncRunnerOptions,\n): Promise<R> {\n\tconst signal = options?.signal;\n\tconst onProgress = options?.onProgress;\n\tconst yieldStrategy = options?.yieldStrategy ?? defaultYieldStrategy;\n\n\tlet step = gen.next();\n\n\twhile (step.done !== true) {\n\t\t// Check for cancellation before processing each op. Throw the error\n\t\t// into the generator so that any finally blocks in the algorithm run\n\t\t// before the error propagates to the caller.\n\t\tif (signal?.aborted === true) {\n\t\t\tconst abortError = new DOMException(\"Aborted\", \"AbortError\");\n\t\t\ttry {\n\t\t\t\tgen.throw(abortError);\n\t\t\t} catch {\n\t\t\t\t// Generator did not handle the error — propagate it\n\t\t\t\tthrow abortError;\n\t\t\t}\n\t\t\t// Generator handled the error but we still honour cancellation\n\t\t\tthrow abortError;\n\t\t}\n\n\t\tconst op = step.value;\n\n\t\t// Handle cooperative yield ops without hitting the graph\n\t\tif (op.tag === \"yield\") {\n\t\t\tawait yieldStrategy();\n\t\t\tstep = gen.next({ tag: \"yield\" });\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Handle progress ops: call the callback (awaiting if async)\n\t\tif (op.tag === \"progress\") {\n\t\t\tif (onProgress !== undefined) {\n\t\t\t\tconst maybePromise = onProgress(op.stats);\n\t\t\t\tif (maybePromise instanceof Promise) {\n\t\t\t\t\tawait maybePromise;\n\t\t\t\t}\n\t\t\t}\n\t\t\tstep = gen.next({ tag: \"progress\" });\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Resolve graph ops, forwarding any errors into the generator\n\t\tlet response: GraphOpResponse<N, E>;\n\t\ttry {\n\t\t\tresponse = await resolveAsyncOp(graph, op);\n\t\t} catch (error) {\n\t\t\t// Forward the error into the generator; if unhandled, it propagates\n\t\t\tstep = gen.throw(error);\n\t\t\tcontinue;\n\t\t}\n\n\t\tstep = gen.next(response);\n\t}\n\n\treturn step.value;\n}\n","/**\n * Type-safe yield helpers for graph operations.\n *\n * Each function is a sub-generator that yields one GraphOp and returns\n * the correctly-typed result. Narrowing is done via the tagged discriminated\n * union in GraphOpResponse — no type assertions needed.\n *\n * Use with `yield*` inside algorithm generators.\n *\n * @module async/ops\n */\n\nimport type { NodeId, NodeData, EdgeData, Direction } from \"../graph\";\nimport type { GraphOp, GraphOpResponse, ProgressStats } from \"./protocol\";\n\nexport function* opNeighbours<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(\n\tid: NodeId,\n\tdirection?: Direction,\n): Generator<GraphOp, readonly NodeId[], GraphOpResponse<N, E>> {\n\tconst op: GraphOp =\n\t\tdirection !== undefined\n\t\t\t? { tag: \"neighbours\", id, direction }\n\t\t\t: { tag: \"neighbours\", id };\n\tconst response: GraphOpResponse<N, E> = yield op;\n\tif (response.tag !== \"neighbours\") {\n\t\tthrow new TypeError(`Expected neighbours response, got ${response.tag}`);\n\t}\n\treturn response.value;\n}\n\nexport function* opDegree<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(\n\tid: NodeId,\n\tdirection?: Direction,\n): Generator<GraphOp, number, GraphOpResponse<N, E>> {\n\tconst op: GraphOp =\n\t\tdirection !== undefined\n\t\t\t? { tag: \"degree\", id, direction }\n\t\t\t: { tag: \"degree\", id };\n\tconst response: GraphOpResponse<N, E> = yield op;\n\tif (response.tag !== \"degree\") {\n\t\tthrow new TypeError(`Expected degree response, got ${response.tag}`);\n\t}\n\treturn response.value;\n}\n\nexport function* opGetNode<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(id: NodeId): Generator<GraphOp, N | undefined, GraphOpResponse<N, E>> {\n\tconst response: GraphOpResponse<N, E> = yield { tag: \"getNode\", id };\n\tif (response.tag !== \"getNode\") {\n\t\tthrow new TypeError(`Expected getNode response, got ${response.tag}`);\n\t}\n\treturn response.value;\n}\n\nexport function* opGetEdge<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(\n\tsource: NodeId,\n\ttarget: NodeId,\n): Generator<GraphOp, E | undefined, GraphOpResponse<N, E>> {\n\tconst response: GraphOpResponse<N, E> = yield {\n\t\ttag: \"getEdge\",\n\t\tsource,\n\t\ttarget,\n\t};\n\tif (response.tag !== \"getEdge\") {\n\t\tthrow new TypeError(`Expected getEdge response, got ${response.tag}`);\n\t}\n\treturn response.value;\n}\n\nexport function* opHasNode<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(id: NodeId): Generator<GraphOp, boolean, GraphOpResponse<N, E>> {\n\tconst response: GraphOpResponse<N, E> = yield { tag: \"hasNode\", id };\n\tif (response.tag !== \"hasNode\") {\n\t\tthrow new TypeError(`Expected hasNode response, got ${response.tag}`);\n\t}\n\treturn response.value;\n}\n\nexport function* opYield<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(): Generator<GraphOp, void, GraphOpResponse<N, E>> {\n\tyield { tag: \"yield\" };\n}\n\nexport function* opProgress<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(stats: ProgressStats): Generator<GraphOp, void, GraphOpResponse<N, E>> {\n\tyield { tag: \"progress\", stats };\n}\n\nexport function* opBatchNeighbours<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(\n\tids: readonly NodeId[],\n\tdirection?: Direction,\n): Generator<\n\tGraphOp,\n\tReadonlyMap<NodeId, readonly NodeId[]>,\n\tGraphOpResponse<N, E>\n> {\n\tconst op: GraphOp =\n\t\tdirection !== undefined\n\t\t\t? { tag: \"batchNeighbours\", ids, direction }\n\t\t\t: { tag: \"batchNeighbours\", ids };\n\tconst response: GraphOpResponse<N, E> = yield op;\n\tif (response.tag !== \"batchNeighbours\") {\n\t\tthrow new TypeError(\n\t\t\t`Expected batchNeighbours response, got ${response.tag}`,\n\t\t);\n\t}\n\treturn response.value;\n}\n\nexport function* opBatchDegree<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n>(\n\tids: readonly NodeId[],\n\tdirection?: Direction,\n): Generator<GraphOp, ReadonlyMap<NodeId, number>, GraphOpResponse<N, E>> {\n\tconst op: GraphOp =\n\t\tdirection !== undefined\n\t\t\t? { tag: \"batchDegree\", ids, direction }\n\t\t\t: { tag: \"batchDegree\", ids };\n\tconst response: GraphOpResponse<N, E> = yield op;\n\tif (response.tag !== \"batchDegree\") {\n\t\tthrow new TypeError(`Expected batchDegree response, got ${response.tag}`);\n\t}\n\treturn response.value;\n}\n"],"mappings":"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"}
|
|
@@ -10,4 +10,16 @@ import { BaselineConfig, BaselineResult } from './types';
|
|
|
10
10
|
* @returns Ranked paths (highest communicability first)
|
|
11
11
|
*/
|
|
12
12
|
export declare function communicability<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): BaselineResult;
|
|
13
|
+
/**
|
|
14
|
+
* Rank paths by communicability between endpoints (async with GPU support).
|
|
15
|
+
*
|
|
16
|
+
* GPU Support: When `config.gpu?.backend === 'gpu'` and a GPU root is provided,
|
|
17
|
+
* uses WebGPU-accelerated SpMV for improved performance on large graphs.
|
|
18
|
+
*
|
|
19
|
+
* @param graph - Source graph
|
|
20
|
+
* @param paths - Paths to rank
|
|
21
|
+
* @param config - Configuration options
|
|
22
|
+
* @returns Promise resolving to ranked paths (highest communicability first)
|
|
23
|
+
*/
|
|
24
|
+
export declare function communicabilityAsync<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): Promise<BaselineResult>;
|
|
13
25
|
//# sourceMappingURL=communicability.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"communicability.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/communicability.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"communicability.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/communicability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AA8E9D;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EACrE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,cAAc,CAwBhB;AAiED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACzC,CAAC,SAAS,QAAQ,EAClB,CAAC,SAAS,QAAQ,EAElB,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,OAAO,CAAC,cAAc,CAAC,CA6DzB"}
|
|
@@ -10,4 +10,16 @@ import { BaselineConfig, BaselineResult } from './types';
|
|
|
10
10
|
* @returns Ranked paths (highest Katz score first)
|
|
11
11
|
*/
|
|
12
12
|
export declare function katz<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): BaselineResult;
|
|
13
|
+
/**
|
|
14
|
+
* Rank paths by Katz centrality between endpoints (async with GPU support).
|
|
15
|
+
*
|
|
16
|
+
* GPU Support: When `config.gpu?.backend === 'gpu'` and a GPU root is provided,
|
|
17
|
+
* uses WebGPU-accelerated SpMV for improved performance on large graphs.
|
|
18
|
+
*
|
|
19
|
+
* @param graph - Source graph
|
|
20
|
+
* @param paths - Paths to rank
|
|
21
|
+
* @param config - Configuration options
|
|
22
|
+
* @returns Promise resolving to ranked paths (highest Katz score first)
|
|
23
|
+
*/
|
|
24
|
+
export declare function katzAsync<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): Promise<BaselineResult>;
|
|
13
25
|
//# sourceMappingURL=katz.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"katz.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/katz.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"katz.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/katz.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AA6E9D;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC1D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,cAAc,CAwBhB;AA6DD;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EACrE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,OAAO,CAAC,cAAc,CAAC,CA6DzB"}
|
|
@@ -4,6 +4,21 @@ import { BaselineConfig, BaselineResult } from './types';
|
|
|
4
4
|
/**
|
|
5
5
|
* Rank paths by sum of PageRank scores.
|
|
6
6
|
*
|
|
7
|
+
* GPU Support: When `config.gpu?.backend === 'gpu'` and a GPU root is provided,
|
|
8
|
+
* uses WebGPU-accelerated computation for improved performance on large graphs.
|
|
9
|
+
*
|
|
10
|
+
* @param graph - Source graph
|
|
11
|
+
* @param paths - Paths to rank
|
|
12
|
+
* @param config - Configuration options
|
|
13
|
+
* @returns Ranked paths (highest PageRank sum first)
|
|
14
|
+
*/
|
|
15
|
+
export declare function pagerankAsync<N extends NodeData, E extends EdgeData>(graph: ReadableGraph<N, E>, paths: readonly ExpansionPath[], config?: BaselineConfig): Promise<BaselineResult>;
|
|
16
|
+
/**
|
|
17
|
+
* Rank paths by sum of PageRank scores (synchronous version).
|
|
18
|
+
*
|
|
19
|
+
* This synchronous version uses CPU computation only.
|
|
20
|
+
* For GPU support, use the async `pagerankAsync` function.
|
|
21
|
+
*
|
|
7
22
|
* @param graph - Source graph
|
|
8
23
|
* @param paths - Paths to rank
|
|
9
24
|
* @param config - Configuration options
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagerank.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/pagerank.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pagerank.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/pagerank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AA4E9D;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EACzE,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,OAAO,CAAC,cAAc,CAAC,CA0CzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,QAAQ,EAAE,CAAC,SAAS,QAAQ,EAC9D,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,GACrB,cAAc,CAuBhB"}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { NodeData, EdgeData, ReadableGraph } from '../../graph';
|
|
2
2
|
import { ExpansionPath } from '../../expansion/types';
|
|
3
|
+
import { GPUComputeOptions } from '../../gpu/types';
|
|
3
4
|
/**
|
|
4
5
|
* Configuration for baseline ranking methods.
|
|
5
6
|
*/
|
|
6
7
|
export interface BaselineConfig {
|
|
7
8
|
/** Whether to include scores in result */
|
|
8
9
|
readonly includeScores?: boolean;
|
|
10
|
+
/** GPU acceleration options */
|
|
11
|
+
readonly gpu?: GPUComputeOptions;
|
|
9
12
|
}
|
|
10
13
|
/**
|
|
11
14
|
* A scored path from baseline ranking.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/ranking/baselines/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,0CAA0C;IAC1C,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC,+BAA+B;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,iBAAiB,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,UAAW,SAAQ,aAAa;IAChD,oBAAoB;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IACtC,0BAA0B;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,UAAU,CACrB,CAAC,SAAS,QAAQ,GAAG,QAAQ,EAC7B,CAAC,SAAS,QAAQ,GAAG,QAAQ,IAC1B,CACH,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,MAAM,CAAC,EAAE,cAAc,KACnB,cAAc,CAAC"}
|
package/dist/ranking/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_jaccard = require("../jaccard-
|
|
3
|
-
const require_ranking = require("../ranking-
|
|
2
|
+
const require_jaccard = require("../jaccard-Bdw4B0i4.cjs");
|
|
3
|
+
const require_ranking = require("../ranking-pe5UaxKg.cjs");
|
|
4
4
|
const require_ranking_mi = require("./mi/index.cjs");
|
|
5
5
|
exports.adamicAdar = require_ranking_mi.adamicAdar;
|
|
6
6
|
exports.adamicAdarAsync = require_ranking_mi.adamicAdarAsync;
|
|
@@ -8,6 +8,7 @@ exports.adaptive = require_ranking_mi.adaptive;
|
|
|
8
8
|
exports.adaptiveAsync = require_ranking_mi.adaptiveAsync;
|
|
9
9
|
exports.betweenness = require_ranking.betweenness;
|
|
10
10
|
exports.communicability = require_ranking.communicability;
|
|
11
|
+
exports.communicabilityAsync = require_ranking.communicabilityAsync;
|
|
11
12
|
exports.cosine = require_ranking_mi.cosine;
|
|
12
13
|
exports.cosineAsync = require_ranking_mi.cosineAsync;
|
|
13
14
|
exports.degreeSum = require_ranking.degreeSum;
|
|
@@ -20,11 +21,13 @@ exports.jaccard = require_jaccard.jaccard;
|
|
|
20
21
|
exports.jaccardArithmetic = require_ranking.jaccardArithmetic;
|
|
21
22
|
exports.jaccardAsync = require_jaccard.jaccardAsync;
|
|
22
23
|
exports.katz = require_ranking.katz;
|
|
24
|
+
exports.katzAsync = require_ranking.katzAsync;
|
|
23
25
|
exports.notch = require_ranking_mi.notch;
|
|
24
26
|
exports.notchAsync = require_ranking_mi.notchAsync;
|
|
25
27
|
exports.overlapCoefficient = require_ranking_mi.overlapCoefficient;
|
|
26
28
|
exports.overlapCoefficientAsync = require_ranking_mi.overlapCoefficientAsync;
|
|
27
29
|
exports.pagerank = require_ranking.pagerank;
|
|
30
|
+
exports.pagerankAsync = require_ranking.pagerankAsync;
|
|
28
31
|
exports.parse = require_ranking.parse;
|
|
29
32
|
exports.parseAsync = require_ranking.parseAsync;
|
|
30
33
|
exports.randomRanking = require_ranking.randomRanking;
|
package/dist/ranking/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as jaccardAsync, t as jaccard } from "../jaccard-
|
|
2
|
-
import { a as
|
|
1
|
+
import { n as jaccardAsync, t as jaccard } from "../jaccard-BwC_NuQu.js";
|
|
2
|
+
import { a as communicabilityAsync, c as betweenness, d as jaccardArithmetic, f as widestPath, g as parseAsync, h as parse, i as communicability, l as pagerank, m as shortest, n as randomRanking, o as katz, p as degreeSum, r as resistanceDistance, s as katzAsync, t as hittingTime, u as pagerankAsync } from "../ranking-DOKDBcIR.js";
|
|
3
3
|
import { adamicAdar, adamicAdarAsync, adaptive, adaptiveAsync, cosine, cosineAsync, etch, etchAsync, hubPromoted, hubPromotedAsync, notch, notchAsync, overlapCoefficient, overlapCoefficientAsync, resourceAllocation, resourceAllocationAsync, scale, scaleAsync, skew, skewAsync, sorensen, sorensenAsync, span, spanAsync } from "./mi/index.js";
|
|
4
|
-
export { adamicAdar, adamicAdarAsync, adaptive, adaptiveAsync, betweenness, communicability, cosine, cosineAsync, degreeSum, etch, etchAsync, hittingTime, hubPromoted, hubPromotedAsync, jaccard, jaccardArithmetic, jaccardAsync, katz, notch, notchAsync, overlapCoefficient, overlapCoefficientAsync, pagerank, parse, parseAsync, randomRanking, resistanceDistance, resourceAllocation, resourceAllocationAsync, scale, scaleAsync, shortest, skew, skewAsync, sorensen, sorensenAsync, span, spanAsync, widestPath };
|
|
4
|
+
export { adamicAdar, adamicAdarAsync, adaptive, adaptiveAsync, betweenness, communicability, communicabilityAsync, cosine, cosineAsync, degreeSum, etch, etchAsync, hittingTime, hubPromoted, hubPromotedAsync, jaccard, jaccardArithmetic, jaccardAsync, katz, katzAsync, notch, notchAsync, overlapCoefficient, overlapCoefficientAsync, pagerank, pagerankAsync, parse, parseAsync, randomRanking, resistanceDistance, resourceAllocation, resourceAllocationAsync, scale, scaleAsync, shortest, skew, skewAsync, sorensen, sorensenAsync, span, spanAsync, widestPath };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_utils = require("../../utils-CDtCcsyF.cjs");
|
|
3
3
|
const require_utils$1 = require("../../utils/index.cjs");
|
|
4
|
-
const require_jaccard = require("../../jaccard-
|
|
4
|
+
const require_jaccard = require("../../jaccard-Bdw4B0i4.cjs");
|
|
5
5
|
//#region src/ranking/mi/adamic-adar.ts
|
|
6
6
|
/**
|
|
7
7
|
* Compute Adamic-Adar index between neighbourhoods of two nodes.
|
package/dist/ranking/mi/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as collectAsyncIterable } from "../../utils-BodeE2Mo.js";
|
|
2
2
|
import { computeJaccard, countEdgesOfType, countNodesOfType, localClusteringCoefficient, neighbourIntersection, neighbourOverlap, neighbourSet } from "../../utils/index.js";
|
|
3
|
-
import { n as jaccardAsync, t as jaccard } from "../../jaccard-
|
|
3
|
+
import { n as jaccardAsync, t as jaccard } from "../../jaccard-BwC_NuQu.js";
|
|
4
4
|
//#region src/ranking/mi/adamic-adar.ts
|
|
5
5
|
/**
|
|
6
6
|
* Compute Adamic-Adar index between neighbourhoods of two nodes.
|