graphwise 1.8.0 → 1.9.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/adjacency-map-BtKzcuJq.js +229 -0
- package/dist/adjacency-map-BtKzcuJq.js.map +1 -0
- package/dist/adjacency-map-JqBnMNkF.cjs +234 -0
- package/dist/adjacency-map-JqBnMNkF.cjs.map +1 -0
- package/dist/async/index.cjs +15 -242
- package/dist/async/index.js +2 -229
- package/dist/expansion/index.cjs +43 -0
- package/dist/expansion/index.js +2 -0
- package/dist/expansion-ClDhlMK8.js +1704 -0
- package/dist/expansion-ClDhlMK8.js.map +1 -0
- package/dist/expansion-DaTroIyv.cjs +1949 -0
- package/dist/expansion-DaTroIyv.cjs.map +1 -0
- package/dist/extraction/index.cjs +630 -0
- package/dist/extraction/index.cjs.map +1 -0
- package/dist/extraction/index.js +621 -0
- package/dist/extraction/index.js.map +1 -0
- package/dist/gpu/csr.d.ts +29 -30
- package/dist/gpu/csr.d.ts.map +1 -1
- package/dist/gpu/dispatch.d.ts +31 -0
- package/dist/gpu/dispatch.d.ts.map +1 -0
- package/dist/gpu/dispatch.unit.test.d.ts +5 -0
- package/dist/gpu/dispatch.unit.test.d.ts.map +1 -0
- package/dist/gpu/index.cjs +15 -410
- package/dist/gpu/index.d.ts +3 -1
- package/dist/gpu/index.d.ts.map +1 -1
- package/dist/gpu/index.js +2 -400
- package/dist/gpu/kernels/bfs/kernel.d.ts +59 -0
- package/dist/gpu/kernels/bfs/kernel.d.ts.map +1 -0
- package/dist/gpu/kernels/bfs/logic.d.ts +47 -0
- package/dist/gpu/kernels/bfs/logic.d.ts.map +1 -0
- package/dist/gpu/kernels/bfs/logic.unit.test.d.ts +2 -0
- package/dist/gpu/kernels/bfs/logic.unit.test.d.ts.map +1 -0
- package/dist/gpu/kernels/degree-histogram/kernel.d.ts +32 -0
- package/dist/gpu/kernels/degree-histogram/kernel.d.ts.map +1 -0
- package/dist/gpu/kernels/degree-histogram/logic.d.ts +45 -0
- package/dist/gpu/kernels/degree-histogram/logic.d.ts.map +1 -0
- package/dist/gpu/kernels/degree-histogram/logic.unit.test.d.ts +2 -0
- package/dist/gpu/kernels/degree-histogram/logic.unit.test.d.ts.map +1 -0
- package/dist/gpu/kernels/jaccard/kernel.d.ts +40 -0
- package/dist/gpu/kernels/jaccard/kernel.d.ts.map +1 -0
- package/dist/gpu/kernels/jaccard/logic.d.ts +43 -0
- package/dist/gpu/kernels/jaccard/logic.d.ts.map +1 -0
- package/dist/gpu/kernels/jaccard/logic.unit.test.d.ts +2 -0
- package/dist/gpu/kernels/jaccard/logic.unit.test.d.ts.map +1 -0
- package/dist/gpu/kernels/pagerank/kernel.d.ts +44 -0
- package/dist/gpu/kernels/pagerank/kernel.d.ts.map +1 -0
- package/dist/gpu/kernels/pagerank/logic.d.ts +50 -0
- package/dist/gpu/kernels/pagerank/logic.d.ts.map +1 -0
- package/dist/gpu/kernels/pagerank/logic.unit.test.d.ts +2 -0
- package/dist/gpu/kernels/pagerank/logic.unit.test.d.ts.map +1 -0
- package/dist/gpu/kernels/spmv/kernel.d.ts +43 -0
- package/dist/gpu/kernels/spmv/kernel.d.ts.map +1 -0
- package/dist/gpu/kernels/spmv/logic.d.ts +31 -0
- package/dist/gpu/kernels/spmv/logic.d.ts.map +1 -0
- package/dist/gpu/kernels/spmv/logic.unit.test.d.ts +2 -0
- package/dist/gpu/kernels/spmv/logic.unit.test.d.ts.map +1 -0
- package/dist/gpu/operations.d.ts +76 -0
- package/dist/gpu/operations.d.ts.map +1 -0
- package/dist/gpu/operations.unit.test.d.ts +5 -0
- package/dist/gpu/operations.unit.test.d.ts.map +1 -0
- package/dist/gpu/root.d.ts +53 -0
- package/dist/gpu/root.d.ts.map +1 -0
- package/dist/gpu/root.unit.test.d.ts +2 -0
- package/dist/gpu/root.unit.test.d.ts.map +1 -0
- package/dist/gpu/types.d.ts +3 -8
- package/dist/gpu/types.d.ts.map +1 -1
- package/dist/gpu-CHiCN0wa.js +16945 -0
- package/dist/gpu-CHiCN0wa.js.map +1 -0
- package/dist/gpu-Y6owRVMi.cjs +17028 -0
- package/dist/gpu-Y6owRVMi.cjs.map +1 -0
- package/dist/graph/index.cjs +2 -229
- package/dist/graph/index.js +1 -228
- package/dist/index/index.cjs +141 -4040
- package/dist/index/index.js +15 -3917
- package/dist/jaccard-3rCdilwm.js +39 -0
- package/dist/jaccard-3rCdilwm.js.map +1 -0
- package/dist/jaccard-Bys9_dGW.cjs +50 -0
- package/dist/jaccard-Bys9_dGW.cjs.map +1 -0
- package/dist/{kmeans-BIgSyGKu.cjs → kmeans-B8x9D1kt.cjs} +1 -1
- package/dist/{kmeans-BIgSyGKu.cjs.map → kmeans-B8x9D1kt.cjs.map} +1 -1
- package/dist/{kmeans-87ExSUNZ.js → kmeans-DKkL9rAN.js} +1 -1
- package/dist/{kmeans-87ExSUNZ.js.map → kmeans-DKkL9rAN.js.map} +1 -1
- package/dist/ops-djAsQQSh.cjs +277 -0
- package/dist/ops-djAsQQSh.cjs.map +1 -0
- package/dist/ops-upIi6JIi.js +212 -0
- package/dist/ops-upIi6JIi.js.map +1 -0
- package/dist/priority-queue-BIiD1L0k.cjs +148 -0
- package/dist/priority-queue-BIiD1L0k.cjs.map +1 -0
- package/dist/priority-queue-CFDd5cBg.js +143 -0
- package/dist/priority-queue-CFDd5cBg.js.map +1 -0
- package/dist/ranking/index.cjs +43 -0
- package/dist/ranking/index.js +4 -0
- package/dist/ranking/mi/index.cjs +581 -0
- package/dist/ranking/mi/index.cjs.map +1 -0
- package/dist/ranking/mi/index.js +555 -0
- package/dist/ranking/mi/index.js.map +1 -0
- package/dist/ranking-3ez5m67U.js +1016 -0
- package/dist/ranking-3ez5m67U.js.map +1 -0
- package/dist/ranking-DVvajgUZ.cjs +1093 -0
- package/dist/ranking-DVvajgUZ.cjs.map +1 -0
- package/dist/seeds/index.cjs +1 -1
- package/dist/seeds/index.js +1 -1
- package/dist/structures/index.cjs +2 -143
- package/dist/structures/index.js +1 -142
- package/dist/utils/index.cjs +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils-BodeE2Mo.js +22 -0
- package/dist/utils-BodeE2Mo.js.map +1 -0
- package/dist/utils-CDtCcsyF.cjs +33 -0
- package/dist/utils-CDtCcsyF.cjs.map +1 -0
- package/package.json +3 -1
- package/dist/async/index.cjs.map +0 -1
- package/dist/async/index.js.map +0 -1
- package/dist/gpu/context.d.ts +0 -118
- package/dist/gpu/context.d.ts.map +0 -1
- package/dist/gpu/context.unit.test.d.ts +0 -2
- package/dist/gpu/context.unit.test.d.ts.map +0 -1
- package/dist/gpu/index.cjs.map +0 -1
- package/dist/gpu/index.js.map +0 -1
- package/dist/graph/index.cjs.map +0 -1
- package/dist/graph/index.js.map +0 -1
- package/dist/index/index.cjs.map +0 -1
- package/dist/index/index.js.map +0 -1
- package/dist/structures/index.cjs.map +0 -1
- package/dist/structures/index.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ranking-3ez5m67U.js","names":[],"sources":["../src/ranking/parse.ts","../src/ranking/baselines/utils.ts","../src/ranking/baselines/shortest.ts","../src/ranking/baselines/degree-sum.ts","../src/ranking/baselines/widest-path.ts","../src/ranking/baselines/jaccard-arithmetic.ts","../src/ranking/baselines/pagerank.ts","../src/ranking/baselines/betweenness.ts","../src/ranking/baselines/katz.ts","../src/ranking/baselines/communicability.ts","../src/ranking/baselines/resistance-distance.ts","../src/ranking/baselines/random-ranking.ts","../src/ranking/baselines/hitting-time.ts"],"sourcesContent":["/**\n * PARSE (Path-Aware Ranking via Salience Estimation).\n *\n * Ranks discovered paths by computing geometric mean of edge MI scores.\n * Path salience = (∏ MI(uᵢ, uᵢ₊₁))^(1/|path|)\n *\n * This ranking is length-unbiased: shorter paths with strong edges\n * can outrank longer paths with weak edges.\n *\n * @module ranking/parse\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport type { AsyncReadableGraph } from \"../graph/async-interfaces\";\nimport type { ExpansionPath } from \"../expansion/types\";\nimport type { MIFunction, AsyncMIFunction } from \"./mi/types\";\nimport { jaccard } from \"./mi/jaccard\";\nimport { jaccardAsync } from \"./mi/jaccard\";\n\n/**\n * Configuration for PARSE ranking.\n */\nexport interface PARSEConfig<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n> {\n\t/** MI function to use (default: jaccard) */\n\treadonly mi?: MIFunction<N, E>;\n\t/** Minimum epsilon for MI (default: 1e-10) */\n\treadonly epsilon?: number;\n\t/** Whether to include salience scores in result (default: true) */\n\treadonly includeSalience?: boolean;\n}\n\n/**\n * A ranked path with salience score.\n */\nexport interface RankedPath extends ExpansionPath {\n\t/** Salience score (geometric mean of edge MI) */\n\treadonly salience: number;\n}\n\n/**\n * Result of PARSE ranking.\n */\nexport interface PARSEResult {\n\t/** Paths ranked by salience (highest first) */\n\treadonly paths: readonly RankedPath[];\n\t/** Ranking statistics */\n\treadonly stats: {\n\t\t/** Total paths ranked */\n\t\treadonly pathsRanked: number;\n\t\t/** Mean salience */\n\t\treadonly meanSalience: number;\n\t\t/** Median salience */\n\t\treadonly medianSalience: number;\n\t\t/** Maximum salience */\n\t\treadonly maxSalience: number;\n\t\t/** Minimum salience */\n\t\treadonly minSalience: number;\n\t\t/** Ranking duration in milliseconds */\n\t\treadonly durationMs: number;\n\t};\n}\n\n/**\n * Rank paths using PARSE (Path-Aware Ranking via Salience Estimation).\n *\n * Computes geometric mean of edge MI scores for each path,\n * then sorts by salience (highest first).\n *\n * @param graph - Source graph\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths with statistics\n */\nexport function parse<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: PARSEConfig<N, E>,\n): PARSEResult {\n\tconst startTime = performance.now();\n\n\tconst { mi = jaccard, epsilon = 1e-10 } = config ?? {};\n\n\tconst rankedPaths: RankedPath[] = [];\n\n\tfor (const path of paths) {\n\t\tconst salience = computePathSalience(graph, path, mi, epsilon);\n\t\trankedPaths.push({\n\t\t\t...path,\n\t\t\tsalience,\n\t\t});\n\t}\n\n\t// Sort by salience descending\n\trankedPaths.sort((a, b) => b.salience - a.salience);\n\n\tconst endTime = performance.now();\n\n\t// Compute statistics\n\tconst saliences = rankedPaths.map((p) => p.salience);\n\tconst meanSalience =\n\t\tsaliences.length > 0\n\t\t\t? saliences.reduce((a, b) => a + b, 0) / saliences.length\n\t\t\t: 0;\n\tconst sortedSaliences = [...saliences].sort((a, b) => a - b);\n\tconst mid = Math.floor(sortedSaliences.length / 2);\n\tconst medianSalience =\n\t\tsortedSaliences.length > 0\n\t\t\t? sortedSaliences.length % 2 !== 0\n\t\t\t\t? (sortedSaliences[mid] ?? 0)\n\t\t\t\t: ((sortedSaliences[mid - 1] ?? 0) + (sortedSaliences[mid] ?? 0)) / 2\n\t\t\t: 0;\n\tconst maxSalience =\n\t\tsortedSaliences.length > 0\n\t\t\t? (sortedSaliences[sortedSaliences.length - 1] ?? 0)\n\t\t\t: 0;\n\tconst minSalience =\n\t\tsortedSaliences.length > 0 ? (sortedSaliences[0] ?? 0) : 0;\n\n\treturn {\n\t\tpaths: rankedPaths,\n\t\tstats: {\n\t\t\tpathsRanked: rankedPaths.length,\n\t\t\tmeanSalience,\n\t\t\tmedianSalience,\n\t\t\tmaxSalience,\n\t\t\tminSalience,\n\t\t\tdurationMs: endTime - startTime,\n\t\t},\n\t};\n}\n\n/**\n * Configuration for async PARSE ranking.\n */\nexport interface AsyncPARSEConfig<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n> {\n\t/** Async MI function to use (default: jaccardAsync) */\n\treadonly mi?: AsyncMIFunction<N, E>;\n\t/** Minimum epsilon for MI (default: 1e-10) */\n\treadonly epsilon?: number;\n}\n\n/**\n * Rank paths using async PARSE (Path-Aware Ranking via Salience Estimation).\n *\n * Async variant suitable for use with remote or lazy graph data sources.\n * Computes geometric mean of edge MI scores for each path using Promise.all\n * for parallelism, then sorts by salience (highest first).\n *\n * @param graph - Async source graph\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths with statistics\n */\nexport async function parseAsync<N extends NodeData, E extends EdgeData>(\n\tgraph: AsyncReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: AsyncPARSEConfig<N, E>,\n): Promise<PARSEResult> {\n\tconst startTime = performance.now();\n\n\tconst { mi = jaccardAsync, epsilon = 1e-10 } = config ?? {};\n\n\tconst rankedPaths: RankedPath[] = [];\n\n\tfor (const path of paths) {\n\t\tconst salience = await computePathSalienceAsync(graph, path, mi, epsilon);\n\t\trankedPaths.push({\n\t\t\t...path,\n\t\t\tsalience,\n\t\t});\n\t}\n\n\t// Sort by salience descending\n\trankedPaths.sort((a, b) => b.salience - a.salience);\n\n\tconst endTime = performance.now();\n\n\t// Compute statistics\n\tconst saliences = rankedPaths.map((p) => p.salience);\n\tconst meanSalience =\n\t\tsaliences.length > 0\n\t\t\t? saliences.reduce((a, b) => a + b, 0) / saliences.length\n\t\t\t: 0;\n\tconst sortedSaliences = [...saliences].sort((a, b) => a - b);\n\tconst mid = Math.floor(sortedSaliences.length / 2);\n\tconst medianSalience =\n\t\tsortedSaliences.length > 0\n\t\t\t? sortedSaliences.length % 2 !== 0\n\t\t\t\t? (sortedSaliences[mid] ?? 0)\n\t\t\t\t: ((sortedSaliences[mid - 1] ?? 0) + (sortedSaliences[mid] ?? 0)) / 2\n\t\t\t: 0;\n\tconst maxSalience =\n\t\tsortedSaliences.length > 0\n\t\t\t? (sortedSaliences[sortedSaliences.length - 1] ?? 0)\n\t\t\t: 0;\n\tconst minSalience =\n\t\tsortedSaliences.length > 0 ? (sortedSaliences[0] ?? 0) : 0;\n\n\treturn {\n\t\tpaths: rankedPaths,\n\t\tstats: {\n\t\t\tpathsRanked: rankedPaths.length,\n\t\t\tmeanSalience,\n\t\t\tmedianSalience,\n\t\t\tmaxSalience,\n\t\t\tminSalience,\n\t\t\tdurationMs: endTime - startTime,\n\t\t},\n\t};\n}\n\n/**\n * Compute salience for a single path asynchronously.\n *\n * Uses geometric mean of edge MI scores for length-unbiased ranking.\n * Edge MI values are computed in parallel via Promise.all.\n */\nasync function computePathSalienceAsync<N extends NodeData, E extends EdgeData>(\n\tgraph: AsyncReadableGraph<N, E>,\n\tpath: ExpansionPath,\n\tmi: AsyncMIFunction<N, E>,\n\tepsilon: number,\n): Promise<number> {\n\tconst nodes = path.nodes;\n\n\tif (nodes.length < 2) {\n\t\treturn epsilon;\n\t}\n\n\t// Compute MI for each edge in parallel\n\tconst edgeMIs = await Promise.all(\n\t\tnodes.slice(0, -1).map((source, i) => {\n\t\t\tconst target = nodes[i + 1];\n\t\t\tif (target !== undefined) {\n\t\t\t\treturn mi(graph, source, target);\n\t\t\t}\n\t\t\treturn Promise.resolve(epsilon);\n\t\t}),\n\t);\n\n\tlet productMi = 1;\n\tlet edgeCount = 0;\n\n\tfor (const edgeMi of edgeMIs) {\n\t\tproductMi *= Math.max(epsilon, edgeMi);\n\t\tedgeCount++;\n\t}\n\n\tif (edgeCount === 0) {\n\t\treturn epsilon;\n\t}\n\n\t// Geometric mean\n\tconst salience = Math.pow(productMi, 1 / edgeCount);\n\treturn Math.max(epsilon, Math.min(1, salience));\n}\n\n/**\n * Compute salience for a single path.\n *\n * Uses geometric mean of edge MI scores for length-unbiased ranking.\n */\nfunction computePathSalience<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpath: ExpansionPath,\n\tmi: MIFunction<N, E>,\n\tepsilon: number,\n): number {\n\tconst nodes = path.nodes;\n\n\tif (nodes.length < 2) {\n\t\treturn epsilon;\n\t}\n\n\t// Compute MI for each edge\n\tlet productMi = 1;\n\tlet edgeCount = 0;\n\n\tfor (let i = 0; i < nodes.length - 1; i++) {\n\t\tconst source = nodes[i];\n\t\tconst target = nodes[i + 1];\n\n\t\tif (source !== undefined && target !== undefined) {\n\t\t\tconst edgeMi = mi(graph, source, target);\n\t\t\tproductMi *= Math.max(epsilon, edgeMi);\n\t\t\tedgeCount++;\n\t\t}\n\t}\n\n\tif (edgeCount === 0) {\n\t\treturn epsilon;\n\t}\n\n\t// Geometric mean\n\tconst salience = Math.pow(productMi, 1 / edgeCount);\n\treturn Math.max(epsilon, Math.min(1, salience));\n}\n","/**\n * Shared utilities for baseline ranking methods.\n *\n * @packageDocumentation\n */\n\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineResult, ScoredPath } from \"./types\";\n\n/**\n * Normalise a set of scored paths and return them sorted highest-first.\n *\n * All scores are normalised relative to the maximum observed score.\n * When `includeScores` is false, raw (un-normalised) scores are preserved.\n * Handles degenerate cases: empty input and all-zero scores.\n *\n * @param paths - Original paths in input order\n * @param scored - Paths paired with their computed scores\n * @param method - Method name to embed in the result\n * @param includeScores - When true, normalise scores to [0, 1]; when false, keep raw scores\n * @returns BaselineResult with ranked paths\n */\nexport function normaliseAndRank(\n\tpaths: readonly ExpansionPath[],\n\tscored: readonly { readonly path: ExpansionPath; readonly score: number }[],\n\tmethod: string,\n\tincludeScores: boolean,\n): BaselineResult {\n\tif (scored.length === 0) {\n\t\treturn { paths: [], method };\n\t}\n\n\tconst maxScore = Math.max(...scored.map((s) => s.score));\n\n\t// Handle zero-max case: all paths get score 0\n\tif (maxScore === 0) {\n\t\treturn {\n\t\t\tpaths: paths.map((path) => ({ ...path, score: 0 })),\n\t\t\tmethod,\n\t\t};\n\t}\n\n\tconst ranked: ScoredPath[] = scored\n\t\t.map(({ path, score }) => ({\n\t\t\t...path,\n\t\t\tscore: includeScores ? score / maxScore : score,\n\t\t}))\n\t\t.sort((a, b) => b.score - a.score);\n\n\treturn { paths: ranked, method };\n}\n","/**\n * Shortest path baseline ranking.\n *\n * Ranks paths by length (shorter = higher score).\n * Score = 1 / length (normalised).\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineConfig, BaselineResult } from \"./types\";\nimport { normaliseAndRank } from \"./utils\";\n\n/**\n * Rank paths by length (shortest first).\n *\n * Score = 1 / path_length, normalised to [0, 1].\n *\n * @param _graph - Source graph (unused for length ranking)\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths (shortest first)\n */\nexport function shortest<N extends NodeData, E extends EdgeData>(\n\t_graph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: BaselineConfig,\n): BaselineResult {\n\tconst { includeScores = true } = config ?? {};\n\n\tif (paths.length === 0) {\n\t\treturn {\n\t\t\tpaths: [],\n\t\t\tmethod: \"shortest\",\n\t\t};\n\t}\n\n\t// Compute raw scores (1 / length)\n\tconst scored: { path: ExpansionPath; score: number }[] = paths.map(\n\t\t(path) => ({\n\t\t\tpath,\n\t\t\tscore: 1 / path.nodes.length,\n\t\t}),\n\t);\n\n\treturn normaliseAndRank(paths, scored, \"shortest\", includeScores);\n}\n","/**\n * Degree-Sum baseline ranking.\n *\n * Ranks paths by sum of node degrees.\n * Higher degree nodes may indicate more connected (central) nodes.\n * Score = sum(deg(v) for v in path), normalised to [0, 1].\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineConfig, BaselineResult } from \"./types\";\nimport { normaliseAndRank } from \"./utils\";\n\n/**\n * Rank paths by sum of node degrees.\n *\n * @param graph - Source graph\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths (highest degree-sum first)\n */\nexport function degreeSum<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: BaselineConfig,\n): BaselineResult {\n\tconst { includeScores = true } = config ?? {};\n\n\tif (paths.length === 0) {\n\t\treturn {\n\t\t\tpaths: [],\n\t\t\tmethod: \"degree-sum\",\n\t\t};\n\t}\n\n\t// Compute raw scores (sum of degrees)\n\tconst scored: { path: ExpansionPath; score: number }[] = paths.map((path) => {\n\t\tlet degreeSum = 0;\n\t\tfor (const nodeId of path.nodes) {\n\t\t\tdegreeSum += graph.degree(nodeId);\n\t\t}\n\t\treturn { path, score: degreeSum };\n\t});\n\n\treturn normaliseAndRank(paths, scored, \"degree-sum\", includeScores);\n}\n","/**\n * Widest-Path baseline ranking.\n *\n * Ranks paths by bottleneck similarity (minimum edge salience).\n * Uses Jaccard similarity as the edge salience metric.\n * Score = min(jaccard(u, v) for each edge (u,v) in path).\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineConfig, BaselineResult } from \"./types\";\nimport { jaccard } from \"../mi/jaccard\";\nimport { normaliseAndRank } from \"./utils\";\n\n/**\n * Rank paths by widest bottleneck (minimum edge similarity).\n *\n * @param graph - Source graph\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths (highest bottleneck first)\n */\nexport function widestPath<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: BaselineConfig,\n): BaselineResult {\n\tconst { includeScores = true } = config ?? {};\n\n\tif (paths.length === 0) {\n\t\treturn {\n\t\t\tpaths: [],\n\t\t\tmethod: \"widest-path\",\n\t\t};\n\t}\n\n\t// Compute raw scores (minimum edge similarity per path)\n\tconst scored: { path: ExpansionPath; score: number }[] = paths.map((path) => {\n\t\tif (path.nodes.length < 2) {\n\t\t\t// Single-node path: no edges\n\t\t\treturn { path, score: 1 };\n\t\t}\n\n\t\tlet minSimilarity = Number.POSITIVE_INFINITY;\n\t\tfor (let i = 0; i < path.nodes.length - 1; i++) {\n\t\t\tconst source = path.nodes[i];\n\t\t\tconst target = path.nodes[i + 1];\n\t\t\tif (source === undefined || target === undefined) continue;\n\n\t\t\tconst edgeSimilarity = jaccard(graph, source, target);\n\t\t\tminSimilarity = Math.min(minSimilarity, edgeSimilarity);\n\t\t}\n\n\t\t// If no edges were found, default to 1\n\t\tconst score =\n\t\t\tminSimilarity === Number.POSITIVE_INFINITY ? 1 : minSimilarity;\n\t\treturn { path, score };\n\t});\n\n\treturn normaliseAndRank(paths, scored, \"widest-path\", includeScores);\n}\n","/**\n * Jaccard-Arithmetic baseline ranking.\n *\n * Ranks paths by arithmetic mean of edge Jaccard similarities.\n * Contrast with PARSE which uses geometric mean.\n * Score = (1/k) * sum(jaccard(u, v) for each edge (u,v)).\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineConfig, BaselineResult } from \"./types\";\nimport { jaccard } from \"../mi/jaccard\";\nimport { normaliseAndRank } from \"./utils\";\n\n/**\n * Rank paths by arithmetic mean of edge Jaccard similarities.\n *\n * @param graph - Source graph\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths (highest arithmetic mean first)\n */\nexport function jaccardArithmetic<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: BaselineConfig,\n): BaselineResult {\n\tconst { includeScores = true } = config ?? {};\n\n\tif (paths.length === 0) {\n\t\treturn {\n\t\t\tpaths: [],\n\t\t\tmethod: \"jaccard-arithmetic\",\n\t\t};\n\t}\n\n\t// Compute raw scores (arithmetic mean of edge similarities)\n\tconst scored: { path: ExpansionPath; score: number }[] = paths.map((path) => {\n\t\tif (path.nodes.length < 2) {\n\t\t\t// Single-node path: no edges, score = 1\n\t\t\treturn { path, score: 1 };\n\t\t}\n\n\t\tlet similaritySum = 0;\n\t\tlet edgeCount = 0;\n\n\t\tfor (let i = 0; i < path.nodes.length - 1; i++) {\n\t\t\tconst source = path.nodes[i];\n\t\t\tconst target = path.nodes[i + 1];\n\t\t\tif (source === undefined || target === undefined) continue;\n\n\t\t\tconst edgeSimilarity = jaccard(graph, source, target);\n\t\t\tsimilaritySum += edgeSimilarity;\n\t\t\tedgeCount++;\n\t\t}\n\n\t\t// Arithmetic mean\n\t\tconst score = edgeCount > 0 ? similaritySum / edgeCount : 1;\n\t\treturn { path, score };\n\t});\n\n\treturn normaliseAndRank(paths, scored, \"jaccard-arithmetic\", includeScores);\n}\n","/**\n * PageRank baseline ranking.\n *\n * Computes PageRank centrality for all nodes, then sums PR values per path.\n * Uses power iteration: r(v) = (1-d)/N + d * sum(r(u)/deg_out(u) for u->v)\n * Parameters: d=0.85 (damping factor), tolerance=1e-6, max 100 iterations.\n * Score = sum(pagerank(v) for v in path), normalised to [0, 1].\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineConfig, BaselineResult } from \"./types\";\nimport { normaliseAndRank } from \"./utils\";\n\n/**\n * Compute PageRank centrality for all nodes using power iteration.\n *\n * @param graph - Source graph\n * @param damping - Damping factor (default 0.85)\n * @param tolerance - Convergence tolerance (default 1e-6)\n * @param maxIterations - Maximum iterations (default 100)\n * @returns Map of node ID to PageRank value\n */\nfunction computePageRank<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tdamping = 0.85,\n\ttolerance = 1e-6,\n\tmaxIterations = 100,\n): Map<string, number> {\n\tconst nodes = Array.from(graph.nodeIds());\n\tconst n = nodes.length;\n\n\tif (n === 0) {\n\t\treturn new Map();\n\t}\n\n\t// Initialise ranks uniformly\n\tconst ranks = new Map<string, number>();\n\tconst newRanks = new Map<string, number>();\n\tfor (const nodeId of nodes) {\n\t\tranks.set(nodeId, 1 / n);\n\t\tnewRanks.set(nodeId, 0);\n\t}\n\n\t// Power iteration\n\tlet isCurrentRanks = true; // Track which map is current\n\n\tfor (let iteration = 0; iteration < maxIterations; iteration++) {\n\t\tlet maxChange = 0;\n\t\tconst currMap = isCurrentRanks ? ranks : newRanks;\n\t\tconst nextMap = isCurrentRanks ? newRanks : ranks;\n\n\t\tfor (const nodeId of nodes) {\n\t\t\t// Sum contributions from incoming neighbours\n\t\t\tlet incomingSum = 0;\n\n\t\t\tfor (const incomingId of graph.neighbours(nodeId, \"in\")) {\n\t\t\t\tconst incomingRank = currMap.get(incomingId) ?? 0;\n\t\t\t\tconst outDegree = graph.degree(incomingId);\n\t\t\t\tif (outDegree > 0) {\n\t\t\t\t\tincomingSum += incomingRank / outDegree;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// PageRank formula\n\t\t\tconst newRank = (1 - damping) / n + damping * incomingSum;\n\t\t\tnextMap.set(nodeId, newRank);\n\n\t\t\t// Track convergence\n\t\t\tconst oldRank = currMap.get(nodeId) ?? 0;\n\t\t\tmaxChange = Math.max(maxChange, Math.abs(newRank - oldRank));\n\t\t}\n\n\t\t// Check convergence before swapping\n\t\tif (maxChange < tolerance) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// Swap buffers and clear the old current map for next iteration\n\t\tisCurrentRanks = !isCurrentRanks;\n\t\tcurrMap.clear();\n\t}\n\n\treturn isCurrentRanks ? ranks : newRanks;\n}\n\n/**\n * Rank paths by sum of PageRank scores.\n *\n * @param graph - Source graph\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths (highest PageRank sum first)\n */\nexport function pagerank<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: BaselineConfig,\n): BaselineResult {\n\tconst { includeScores = true } = config ?? {};\n\n\tif (paths.length === 0) {\n\t\treturn {\n\t\t\tpaths: [],\n\t\t\tmethod: \"pagerank\",\n\t\t};\n\t}\n\n\t// Compute PageRank\n\tconst ranks = computePageRank(graph);\n\n\t// Score paths by sum of node ranks\n\tconst scored: { path: ExpansionPath; score: number }[] = paths.map((path) => {\n\t\tlet prSum = 0;\n\t\tfor (const nodeId of path.nodes) {\n\t\t\tprSum += ranks.get(nodeId) ?? 0;\n\t\t}\n\t\treturn { path, score: prSum };\n\t});\n\n\treturn normaliseAndRank(paths, scored, \"pagerank\", includeScores);\n}\n","/**\n * Betweenness baseline ranking.\n *\n * Computes betweenness centrality using Brandes algorithm O(|V||E|).\n * Score = sum(betweenness(v) for v in path), normalised to [0, 1].\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineConfig, BaselineResult } from \"./types\";\nimport { normaliseAndRank } from \"./utils\";\n\n/**\n * Compute betweenness centrality for all nodes using Brandes algorithm.\n *\n * @param graph - Source graph\n * @returns Map of node ID to betweenness value\n */\nfunction computeBetweenness<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n): Map<string, number> {\n\tconst nodes = Array.from(graph.nodeIds());\n\tconst betweenness = new Map<string, number>();\n\n\t// Initialise all betweenness to 0\n\tfor (const nodeId of nodes) {\n\t\tbetweenness.set(nodeId, 0);\n\t}\n\n\t// For each node as source\n\tfor (const source of nodes) {\n\t\t// BFS to find shortest paths\n\t\tconst predecessors = new Map<string, string[]>();\n\t\tconst distance = new Map<string, number>();\n\t\tconst sigma = new Map<string, number>();\n\t\tconst queue: string[] = [];\n\n\t\t// Initialise\n\t\tfor (const nodeId of nodes) {\n\t\t\tpredecessors.set(nodeId, []);\n\t\t\tdistance.set(nodeId, -1);\n\t\t\tsigma.set(nodeId, 0);\n\t\t}\n\n\t\tdistance.set(source, 0);\n\t\tsigma.set(source, 1);\n\t\tqueue.push(source);\n\n\t\t// BFS\n\t\tfor (const v of queue) {\n\t\t\tconst vDist = distance.get(v) ?? -1;\n\t\t\tconst neighbours = graph.neighbours(v);\n\n\t\t\tfor (const w of neighbours) {\n\t\t\t\tconst wDist = distance.get(w) ?? -1;\n\n\t\t\t\t// First time seeing w?\n\t\t\t\tif (wDist < 0) {\n\t\t\t\t\tdistance.set(w, vDist + 1);\n\t\t\t\t\tqueue.push(w);\n\t\t\t\t}\n\n\t\t\t\t// Shortest path to w through v?\n\t\t\t\tif (wDist === vDist + 1) {\n\t\t\t\t\tconst wSigma = sigma.get(w) ?? 0;\n\t\t\t\t\tconst vSigma = sigma.get(v) ?? 0;\n\t\t\t\t\tsigma.set(w, wSigma + vSigma);\n\n\t\t\t\t\tconst wPred = predecessors.get(w) ?? [];\n\t\t\t\t\twPred.push(v);\n\t\t\t\t\tpredecessors.set(w, wPred);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Accumulation\n\t\tconst delta = new Map<string, number>();\n\t\tfor (const nodeId of nodes) {\n\t\t\tdelta.set(nodeId, 0);\n\t\t}\n\n\t\t// Process in reverse order of distance\n\t\tconst sorted = [...nodes].sort((a, b) => {\n\t\t\tconst aD = distance.get(a) ?? -1;\n\t\t\tconst bD = distance.get(b) ?? -1;\n\t\t\treturn bD - aD;\n\t\t});\n\n\t\tfor (const w of sorted) {\n\t\t\tif (w === source) continue;\n\n\t\t\tconst wDelta = delta.get(w) ?? 0;\n\t\t\tconst wSigma = sigma.get(w) ?? 0;\n\n\t\t\tconst wPred = predecessors.get(w) ?? [];\n\t\t\tfor (const v of wPred) {\n\t\t\t\tconst vSigma = sigma.get(v) ?? 0;\n\t\t\t\tconst vDelta = delta.get(v) ?? 0;\n\n\t\t\t\tif (wSigma > 0) {\n\t\t\t\t\tdelta.set(v, vDelta + (vSigma / wSigma) * (1 + wDelta));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (w !== source) {\n\t\t\t\tconst current = betweenness.get(w) ?? 0;\n\t\t\t\tbetweenness.set(w, current + wDelta);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn betweenness;\n}\n\n/**\n * Rank paths by sum of betweenness scores.\n *\n * @param graph - Source graph\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths (highest betweenness sum first)\n */\nexport function betweenness<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: BaselineConfig,\n): BaselineResult {\n\tconst { includeScores = true } = config ?? {};\n\n\tif (paths.length === 0) {\n\t\treturn {\n\t\t\tpaths: [],\n\t\t\tmethod: \"betweenness\",\n\t\t};\n\t}\n\n\t// Compute betweenness\n\tconst bcMap = computeBetweenness(graph);\n\n\t// Score paths by sum of betweenness\n\tconst scored: { path: ExpansionPath; score: number }[] = paths.map((path) => {\n\t\tlet bcSum = 0;\n\t\tfor (const nodeId of path.nodes) {\n\t\t\tbcSum += bcMap.get(nodeId) ?? 0;\n\t\t}\n\t\treturn { path, score: bcSum };\n\t});\n\n\treturn normaliseAndRank(paths, scored, \"betweenness\", includeScores);\n}\n","/**\n * Katz baseline ranking.\n *\n * Truncated Katz centrality: score(s,t) = sum_{k=1}^{K} beta^k * walks_k(s,t)\n * Parameters: K=5 (truncation depth), beta=0.005 (safe damping < 1/lambda_1).\n * For path scoring: score(P) = katz(P.start, P.end), normalised to [0, 1].\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineConfig, BaselineResult } from \"./types\";\nimport { normaliseAndRank } from \"./utils\";\n\n/**\n * Compute truncated Katz centrality between two nodes.\n *\n * Uses iterative matrix-vector products to avoid full matrix powers.\n * score(s,t) = sum_{k=1}^{K} beta^k * walks_k(s,t)\n *\n * @param graph - Source graph\n * @param source - Source node ID\n * @param target - Target node ID\n * @param k - Truncation depth (default 5)\n * @param beta - Attenuation factor (default 0.005)\n * @returns Katz score\n */\nfunction computeKatz<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: string,\n\ttarget: string,\n\tk = 5,\n\tbeta = 0.005,\n): number {\n\tconst nodes = Array.from(graph.nodeIds());\n\tconst nodeToIdx = new Map<string, number>();\n\tnodes.forEach((nodeId, idx) => {\n\t\tnodeToIdx.set(nodeId, idx);\n\t});\n\n\tconst n = nodes.length;\n\tif (n === 0) {\n\t\treturn 0;\n\t}\n\n\tconst sourceIdx = nodeToIdx.get(source);\n\tconst targetIdx = nodeToIdx.get(target);\n\n\tif (sourceIdx === undefined || targetIdx === undefined) {\n\t\treturn 0;\n\t}\n\n\t// Current column of A^depth (number of walks of length depth from each node to target)\n\tlet walks = new Float64Array(n);\n\twalks[targetIdx] = 1; // Base case: walks[target] = 1\n\n\tlet katzScore = 0;\n\n\t// Iterate from depth 1 to k\n\tfor (let depth = 1; depth <= k; depth++) {\n\t\t// Multiply by adjacency matrix: walks_next[i] = sum_j A[i,j] * walks[j]\n\t\tconst walksNext = new Float64Array(n);\n\n\t\tfor (const sourceNode of nodes) {\n\t\t\tconst srcIdx = nodeToIdx.get(sourceNode);\n\t\t\tif (srcIdx === undefined) continue;\n\n\t\t\tconst neighbours = graph.neighbours(sourceNode);\n\t\t\tfor (const neighbourId of neighbours) {\n\t\t\t\tconst nIdx = nodeToIdx.get(neighbourId);\n\t\t\t\tif (nIdx === undefined) continue;\n\n\t\t\t\twalksNext[srcIdx] = (walksNext[srcIdx] ?? 0) + (walks[nIdx] ?? 0);\n\t\t\t}\n\t\t}\n\n\t\t// Add contribution: beta^depth * walks_depth[source]\n\t\tconst walkCount = walksNext[sourceIdx] ?? 0;\n\t\tkatzScore += Math.pow(beta, depth) * walkCount;\n\n\t\twalks = walksNext;\n\t}\n\n\treturn katzScore;\n}\n\n/**\n * Rank paths by Katz centrality between endpoints.\n *\n * @param graph - Source graph\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths (highest Katz score first)\n */\nexport function katz<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: BaselineConfig,\n): BaselineResult {\n\tconst { includeScores = true } = config ?? {};\n\n\tif (paths.length === 0) {\n\t\treturn {\n\t\t\tpaths: [],\n\t\t\tmethod: \"katz\",\n\t\t};\n\t}\n\n\t// Score paths by Katz between endpoints\n\tconst scored: { path: ExpansionPath; score: number }[] = paths.map((path) => {\n\t\tconst source = path.nodes[0];\n\t\tconst target = path.nodes[path.nodes.length - 1];\n\n\t\tif (source === undefined || target === undefined) {\n\t\t\treturn { path, score: 0 };\n\t\t}\n\n\t\tconst katzScore = computeKatz(graph, source, target);\n\t\treturn { path, score: katzScore };\n\t});\n\n\treturn normaliseAndRank(paths, scored, \"katz\", includeScores);\n}\n","/**\n * Communicability baseline ranking.\n *\n * Computes communicability between nodes using truncated Taylor series.\n * (e^A)_{s,t} ≈ sum_{k=0}^{15} A^k_{s,t} / k!\n * For path scoring: score(P) = communicability(P.start, P.end), normalised to [0, 1].\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineConfig, BaselineResult } from \"./types\";\nimport { normaliseAndRank } from \"./utils\";\n\n/**\n * Compute truncated communicability between two nodes.\n *\n * Uses Taylor series expansion: (e^A)_{s,t} ≈ sum_{k=0}^{K} A^k_{s,t} / k!\n *\n * @param graph - Source graph\n * @param source - Source node ID\n * @param target - Target node ID\n * @param k - Truncation depth (default 15)\n * @returns Communicability score\n */\nfunction computeCommunicability<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: string,\n\ttarget: string,\n\tk = 15,\n): number {\n\tconst nodes = Array.from(graph.nodeIds());\n\tconst nodeToIdx = new Map<string, number>();\n\tnodes.forEach((nodeId, idx) => {\n\t\tnodeToIdx.set(nodeId, idx);\n\t});\n\n\tconst n = nodes.length;\n\tif (n === 0) {\n\t\treturn 0;\n\t}\n\n\tconst sourceIdx = nodeToIdx.get(source);\n\tconst targetIdx = nodeToIdx.get(target);\n\n\tif (sourceIdx === undefined || targetIdx === undefined) {\n\t\treturn 0;\n\t}\n\n\t// Current column of A^depth\n\tlet walks = new Float64Array(n);\n\twalks[targetIdx] = 1; // Base case: walks[target] = 1\n\n\t// Compute sum: sum_{k=0}^{K} A^k_{s,t} / k!\n\tlet commScore = walks[sourceIdx] ?? 0; // k=0 term (identity matrix): A^0 = I, so [I]_{s,t} = delta_{s,t}\n\n\tlet factorial = 1;\n\n\t// Iterate from k=1 to k\n\tfor (let depth = 1; depth <= k; depth++) {\n\t\t// Multiply by adjacency matrix: walks_next[i] = sum_j A[i,j] * walks[j]\n\t\tconst walksNext = new Float64Array(n);\n\n\t\tfor (const fromNode of nodes) {\n\t\t\tconst fromIdx = nodeToIdx.get(fromNode);\n\t\t\tif (fromIdx === undefined) continue;\n\n\t\t\tconst neighbours = graph.neighbours(fromNode);\n\t\t\tfor (const toNodeId of neighbours) {\n\t\t\t\tconst toIdx = nodeToIdx.get(toNodeId);\n\t\t\t\tif (toIdx === undefined) continue;\n\n\t\t\t\twalksNext[fromIdx] = (walksNext[fromIdx] ?? 0) + (walks[toIdx] ?? 0);\n\t\t\t}\n\t\t}\n\n\t\tfactorial *= depth;\n\n\t\t// Add contribution: A^depth[s,t] / k!\n\t\tcommScore += (walksNext[sourceIdx] ?? 0) / factorial;\n\n\t\twalks = walksNext;\n\t}\n\n\treturn commScore;\n}\n\n/**\n * Rank paths by communicability between endpoints.\n *\n * @param graph - Source graph\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths (highest communicability first)\n */\nexport function communicability<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: BaselineConfig,\n): BaselineResult {\n\tconst { includeScores = true } = config ?? {};\n\n\tif (paths.length === 0) {\n\t\treturn {\n\t\t\tpaths: [],\n\t\t\tmethod: \"communicability\",\n\t\t};\n\t}\n\n\t// Score paths by communicability between endpoints\n\tconst scored: { path: ExpansionPath; score: number }[] = paths.map((path) => {\n\t\tconst source = path.nodes[0];\n\t\tconst target = path.nodes[path.nodes.length - 1];\n\n\t\tif (source === undefined || target === undefined) {\n\t\t\treturn { path, score: 0 };\n\t\t}\n\n\t\tconst commScore = computeCommunicability(graph, source, target);\n\t\treturn { path, score: commScore };\n\t});\n\n\treturn normaliseAndRank(paths, scored, \"communicability\", includeScores);\n}\n","/**\n * Resistance-Distance baseline ranking.\n *\n * Computes effective resistance via Laplacian pseudoinverse (dense, small graphs only).\n * For path scoring: score(P) = 1 / resistance(P.start, P.end), normalised to [0, 1].\n * Size guard: throws if nodeCount > 5000 (O(n^3) complexity).\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineConfig, BaselineResult } from \"./types\";\nimport { normaliseAndRank } from \"./utils\";\n\n/**\n * Compute effective resistance between two nodes via Laplacian pseudoinverse.\n *\n * Resistance = L^+_{s,s} + L^+_{t,t} - 2*L^+_{s,t}\n * where L^+ is the pseudoinverse of the Laplacian matrix.\n *\n * @param graph - Source graph\n * @param source - Source node ID\n * @param target - Target node ID\n * @returns Effective resistance\n */\nfunction computeResistance<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: string,\n\ttarget: string,\n): number {\n\tconst nodes = Array.from(graph.nodeIds());\n\tconst nodeToIdx = new Map<string, number>();\n\tnodes.forEach((nodeId, idx) => {\n\t\tnodeToIdx.set(nodeId, idx);\n\t});\n\n\tconst n = nodes.length;\n\n\tif (n === 0 || n > 5000) {\n\t\tthrow new Error(\n\t\t\t`Cannot compute resistance distance: graph too large (${String(n)} nodes). Maximum 5000.`,\n\t\t);\n\t}\n\n\tconst sourceIdx = nodeToIdx.get(source);\n\tconst targetIdx = nodeToIdx.get(target);\n\n\tif (sourceIdx === undefined || targetIdx === undefined) {\n\t\treturn 0;\n\t}\n\n\t// Build Laplacian matrix: L = D - A\n\tconst L: number[][] = Array.from({ length: n }, () =>\n\t\tArray.from({ length: n }, () => 0),\n\t);\n\n\tfor (let i = 0; i < n; i++) {\n\t\tconst nodeId = nodes[i];\n\t\tif (nodeId === undefined) continue;\n\n\t\tconst degree = graph.degree(nodeId);\n\t\tconst row = L[i];\n\t\tif (row !== undefined) {\n\t\t\trow[i] = degree; // Diagonal\n\t\t}\n\n\t\tconst neighbours = graph.neighbours(nodeId);\n\t\tfor (const neighbourId of neighbours) {\n\t\t\tconst j = nodeToIdx.get(neighbourId);\n\t\t\tif (j !== undefined && row !== undefined) {\n\t\t\t\trow[j] = -1; // Off-diagonal\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compute pseudoinverse using Moore-Penrose approach (simplified)\n\t// For small graphs, use LU decomposition with diagonal adjustment\n\tconst Lpinv = pinv(L);\n\n\t// Resistance = L^+_{s,s} + L^+_{t,t} - 2*L^+_{s,t}\n\tconst resistance =\n\t\t(Lpinv[sourceIdx]?.[sourceIdx] ?? 0) +\n\t\t(Lpinv[targetIdx]?.[targetIdx] ?? 0) -\n\t\t2 * (Lpinv[sourceIdx]?.[targetIdx] ?? 0);\n\n\t// Clamp to positive (numerical stability)\n\treturn Math.max(resistance, 1e-10);\n}\n\n/**\n * Compute Moore-Penrose pseudoinverse of a matrix.\n * Simplified implementation for small dense matrices.\n *\n * @param A - Square matrix\n * @returns Pseudoinverse A^+\n */\nfunction pinv(A: number[][]): number[][] {\n\tconst n = A.length;\n\tif (n === 0) return [];\n\n\t// Create copy for singular value computation\n\tconst M = A.map((row) => [...row]);\n\n\t// Simplified: add small regularisation to diagonal before inversion\n\tconst epsilon = 1e-10;\n\tfor (let i = 0; i < n; i++) {\n\t\tconst row = M[i];\n\t\tif (row !== undefined) {\n\t\t\trow[i] = (row[i] ?? 0) + epsilon;\n\t\t}\n\t}\n\n\t// Gaussian elimination with partial pivoting to compute inverse\n\tconst Minv = gaussianInverse(M);\n\n\treturn Minv;\n}\n\n/**\n * Compute matrix inverse using Gaussian elimination with partial pivoting.\n *\n * @param A - Matrix to invert\n * @returns Inverted matrix\n */\nfunction gaussianInverse(A: number[][]): number[][] {\n\tconst n = A.length;\n\n\t// Create augmented matrix [A | I]\n\tconst aug: number[][] = A.map((row, i) => {\n\t\tconst identity: number[] = Array.from({ length: n }, (_, j) =>\n\t\t\ti === j ? 1 : 0,\n\t\t);\n\t\tconst combined: number[] = [...row, ...identity];\n\t\treturn combined;\n\t});\n\n\t// Forward elimination with partial pivoting\n\tfor (let col = 0; col < n; col++) {\n\t\t// Find pivot\n\t\tlet maxRow = col;\n\t\tfor (let row = col + 1; row < n; row++) {\n\t\t\tconst currentRow = aug[row];\n\t\t\tconst maxRowRef = aug[maxRow];\n\t\t\tif (\n\t\t\t\tcurrentRow !== undefined &&\n\t\t\t\tmaxRowRef !== undefined &&\n\t\t\t\tMath.abs(currentRow[col] ?? 0) > Math.abs(maxRowRef[col] ?? 0)\n\t\t\t) {\n\t\t\t\tmaxRow = row;\n\t\t\t}\n\t\t}\n\n\t\t// Swap rows\n\t\tconst currentCol = aug[col];\n\t\tconst maxRowAug = aug[maxRow];\n\t\tif (currentCol !== undefined && maxRowAug !== undefined) {\n\t\t\taug[col] = maxRowAug;\n\t\t\taug[maxRow] = currentCol;\n\t\t}\n\n\t\t// Scale pivot row\n\t\tconst pivotRow = aug[col];\n\t\tconst pivot = pivotRow?.[col];\n\t\tif (pivot === undefined || Math.abs(pivot) < 1e-12) {\n\t\t\tcontinue; // Skip singular column\n\t\t}\n\n\t\tif (pivotRow !== undefined) {\n\t\t\tfor (let j = col; j < 2 * n; j++) {\n\t\t\t\tpivotRow[j] = (pivotRow[j] ?? 0) / pivot;\n\t\t\t}\n\t\t}\n\n\t\t// Eliminate below and above\n\t\tfor (let row = 0; row < n; row++) {\n\t\t\tif (row === col) continue;\n\n\t\t\tconst eliminationRow = aug[row];\n\t\t\tconst factor = eliminationRow?.[col] ?? 0;\n\t\t\tif (eliminationRow !== undefined && pivotRow !== undefined) {\n\t\t\t\tfor (let j = col; j < 2 * n; j++) {\n\t\t\t\t\teliminationRow[j] =\n\t\t\t\t\t\t(eliminationRow[j] ?? 0) - factor * (pivotRow[j] ?? 0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Extract inverse (right half of augmented matrix)\n\tconst Ainv: number[][] = [];\n\tfor (let i = 0; i < n; i++) {\n\t\tconst row = aug[i];\n\t\tAinv[i] = (row?.slice(n) ?? []).map((v) => v);\n\t}\n\n\treturn Ainv;\n}\n\n/**\n * Rank paths by reciprocal of resistance distance between endpoints.\n *\n * @param graph - Source graph\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths (highest conductance first)\n */\nexport function resistanceDistance<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: BaselineConfig,\n): BaselineResult {\n\tconst { includeScores = true } = config ?? {};\n\n\tif (paths.length === 0) {\n\t\treturn {\n\t\t\tpaths: [],\n\t\t\tmethod: \"resistance-distance\",\n\t\t};\n\t}\n\n\t// Check graph size\n\tconst nodeCount = Array.from(graph.nodeIds()).length;\n\tif (nodeCount > 5000) {\n\t\tthrow new Error(\n\t\t\t`Cannot rank paths: graph too large (${String(nodeCount)} nodes). Resistance distance requires O(n^3) computation; maximum 5000 nodes.`,\n\t\t);\n\t}\n\n\t// Score paths by conductance (1 / resistance)\n\tconst scored: { path: ExpansionPath; score: number }[] = paths.map((path) => {\n\t\tconst source = path.nodes[0];\n\t\tconst target = path.nodes[path.nodes.length - 1];\n\n\t\tif (source === undefined || target === undefined) {\n\t\t\treturn { path, score: 0 };\n\t\t}\n\n\t\tconst resistance = computeResistance(graph, source, target);\n\t\t// Score = conductance = 1 / resistance\n\t\tconst score = 1 / resistance;\n\t\treturn { path, score };\n\t});\n\n\treturn normaliseAndRank(paths, scored, \"resistance-distance\", includeScores);\n}\n","/**\n * Random-Ranking baseline.\n *\n * Null hypothesis baseline: ranks paths by seeded random scores.\n * Uses deterministic hash for reproducibility.\n * Score = seededRandom(nodes.join(','), seed), normalised to [0, 1].\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineConfig, BaselineResult } from \"./types\";\nimport { normaliseAndRank } from \"./utils\";\n\n/**\n * Configuration for random ranking.\n */\ninterface RandomRankingConfig extends BaselineConfig {\n\t/** Random seed for deterministic reproducibility */\n\treadonly seed?: number;\n}\n\n/**\n * Deterministic seeded random number generator.\n * Uses FNV-1a-like hash for input → [0, 1] output.\n *\n * @param input - String to hash\n * @param seed - Random seed for reproducibility\n * @returns Deterministic random value in [0, 1]\n */\nfunction seededRandom(input: string, seed = 0): number {\n\tlet h = seed;\n\tfor (let i = 0; i < input.length; i++) {\n\t\th = Math.imul(h ^ input.charCodeAt(i), 0x9e3779b9);\n\n\t\th ^= h >>> 16;\n\t}\n\n\treturn (h >>> 0) / 0xffffffff;\n}\n\n/**\n * Rank paths randomly (null hypothesis baseline).\n *\n * @param _graph - Source graph (unused)\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths (randomly ordered)\n */\nexport function randomRanking<N extends NodeData, E extends EdgeData>(\n\t_graph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: RandomRankingConfig,\n): BaselineResult {\n\tconst { includeScores = true, seed = 0 } = config ?? {};\n\n\tif (paths.length === 0) {\n\t\treturn {\n\t\t\tpaths: [],\n\t\t\tmethod: \"random\",\n\t\t};\n\t}\n\n\t// Score paths by seeded random hash of node list\n\tconst scored: { path: ExpansionPath; score: number }[] = paths.map((path) => {\n\t\tconst nodesKey = path.nodes.join(\",\");\n\t\tconst score = seededRandom(nodesKey, seed);\n\t\treturn { path, score };\n\t});\n\n\treturn normaliseAndRank(paths, scored, \"random\", includeScores);\n}\n","/**\n * Hitting-time ranking baseline.\n *\n * Ranks paths by the inverse of the expected number of steps\n * in a random walk from source to target.\n *\n * Score = 1 / hittingTime(source, target)\n *\n * Two computation modes:\n * - Approximate: Monte Carlo random walk simulation (default, efficient for large graphs)\n * - Exact: Fundamental matrix approach (for small graphs)\n * - Auto: Automatic mode selection (switches at ~100 nodes)\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineConfig, BaselineResult } from \"./types\";\nimport { normaliseAndRank } from \"./utils\";\n\n/**\n * Configuration for hitting-time ranking.\n */\ninterface HittingTimeConfig extends BaselineConfig {\n\t/** Computation mode: \"exact\", \"approximate\", or \"auto\" (default: \"auto\") */\n\treadonly mode?: \"exact\" | \"approximate\" | \"auto\";\n\t/** Number of Monte Carlo walks for approximate mode (default: 1000) */\n\treadonly walks?: number;\n\t/** Maximum steps per walk (default: 10000) */\n\treadonly maxSteps?: number;\n\t/** Random seed for reproducibility (default: 42) */\n\treadonly seed?: number;\n}\n\n/**\n * Seeded deterministic random number generator (LCG).\n * Suitable for reproducible random walk simulation.\n */\nclass SeededRNG {\n\tprivate state: number;\n\n\tconstructor(seed: number) {\n\t\tthis.state = seed;\n\t}\n\n\t/**\n\t * Generate next pseudorandom value in [0, 1).\n\t */\n\tnext(): number {\n\t\t// Linear congruential generator: standard MINSTD parameters\n\t\tthis.state = (this.state * 1103515245 + 12345) & 0x7fffffff;\n\t\treturn this.state / 0x7fffffff;\n\t}\n}\n\n/**\n * Compute hitting time via Monte Carlo random walk simulation.\n *\n * @param graph - Source graph\n * @param source - Source node ID\n * @param target - Target node ID\n * @param walks - Number of walks to simulate\n * @param maxSteps - Maximum steps per walk\n * @param rng - Seeded RNG instance\n * @returns Average hitting time across walks\n */\nfunction computeHittingTimeApproximate<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: string,\n\ttarget: string,\n\twalks: number,\n\tmaxSteps: number,\n\trng: SeededRNG,\n): number {\n\tif (source === target) {\n\t\treturn 0; // Hitting time from a node to itself is 0\n\t}\n\n\tlet totalSteps = 0;\n\tlet successfulWalks = 0;\n\n\tfor (let w = 0; w < walks; w++) {\n\t\tlet current: string = source;\n\t\tlet steps = 0;\n\n\t\twhile (current !== target && steps < maxSteps) {\n\t\t\tconst neighbours = Array.from(graph.neighbours(current));\n\t\t\tif (neighbours.length === 0) {\n\t\t\t\t// Stuck in sink node\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Uniformly choose next neighbour\n\t\t\tconst nextIdx = Math.floor(rng.next() * neighbours.length);\n\t\t\tconst nextNode = neighbours[nextIdx];\n\t\t\tif (nextNode === undefined) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcurrent = nextNode;\n\t\t\tsteps++;\n\t\t}\n\n\t\tif (current === target) {\n\t\t\ttotalSteps += steps;\n\t\t\tsuccessfulWalks++;\n\t\t}\n\t}\n\n\t// Return average if any walks succeeded\n\tif (successfulWalks > 0) {\n\t\treturn totalSteps / successfulWalks;\n\t}\n\n\t// Return maxSteps as estimate if no walks succeeded\n\treturn maxSteps;\n}\n\n/**\n * Compute hitting time via exact fundamental matrix method.\n *\n * For small graphs, computes exact expected hitting times using\n * the fundamental matrix of the random walk.\n *\n * @param graph - Source graph\n * @param source - Source node ID\n * @param target - Target node ID\n * @returns Exact hitting time (or approximation if convergence fails)\n */\nfunction computeHittingTimeExact<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: string,\n\ttarget: string,\n): number {\n\tif (source === target) {\n\t\treturn 0;\n\t}\n\n\tconst nodes = Array.from(graph.nodeIds());\n\tconst nodeToIdx = new Map<string, number>();\n\tnodes.forEach((nodeId, idx) => {\n\t\tnodeToIdx.set(nodeId, idx);\n\t});\n\n\tconst n = nodes.length;\n\tconst sourceIdx = nodeToIdx.get(source);\n\tconst targetIdx = nodeToIdx.get(target);\n\n\tif (sourceIdx === undefined || targetIdx === undefined) {\n\t\treturn 0;\n\t}\n\n\t// Build transition matrix P with absorbing target\n\tconst P: number[][] = [];\n\tfor (let i = 0; i < n; i++) {\n\t\tconst row: number[] = [];\n\t\tfor (let j = 0; j < n; j++) {\n\t\t\trow[j] = 0;\n\t\t}\n\t\tP[i] = row;\n\t}\n\n\tfor (const nodeId of nodes) {\n\t\tconst idx = nodeToIdx.get(nodeId);\n\t\tif (idx === undefined) continue;\n\n\t\tconst pRow = P[idx];\n\t\tif (pRow === undefined) continue;\n\n\t\tif (idx === targetIdx) {\n\t\t\t// Target is absorbing state\n\t\t\tpRow[idx] = 1;\n\t\t} else {\n\t\t\tconst neighbours = Array.from(graph.neighbours(nodeId));\n\t\t\tconst degree = neighbours.length;\n\n\t\t\tif (degree > 0) {\n\t\t\t\tfor (const neighbourId of neighbours) {\n\t\t\t\t\tconst nIdx = nodeToIdx.get(neighbourId);\n\t\t\t\t\tif (nIdx !== undefined) {\n\t\t\t\t\t\tpRow[nIdx] = 1 / degree;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compute fundamental matrix N = (I - Q)^(-1)\n\t// where Q is the submatrix of P excluding the absorbing state\n\tconst transientIndices: number[] = [];\n\n\tfor (let i = 0; i < n; i++) {\n\t\tif (i !== targetIdx) {\n\t\t\ttransientIndices.push(i);\n\t\t}\n\t}\n\n\tconst m = transientIndices.length;\n\tconst Q: number[][] = [];\n\tfor (let i = 0; i < m; i++) {\n\t\tconst row: number[] = [];\n\t\tfor (let j = 0; j < m; j++) {\n\t\t\trow[j] = 0;\n\t\t}\n\t\tQ[i] = row;\n\t}\n\n\tfor (let i = 0; i < m; i++) {\n\t\tconst qRow = Q[i];\n\t\tif (qRow === undefined) continue;\n\t\tconst origI = transientIndices[i];\n\t\tif (origI === undefined) continue;\n\t\tconst pRow = P[origI];\n\t\tif (pRow === undefined) continue;\n\n\t\tfor (let j = 0; j < m; j++) {\n\t\t\tconst origJ = transientIndices[j];\n\t\t\tif (origJ === undefined) continue;\n\t\t\tqRow[j] = pRow[origJ] ?? 0;\n\t\t}\n\t}\n\n\t// Compute I - Q\n\tconst IMQ: number[][] = [];\n\tfor (let i = 0; i < m; i++) {\n\t\tconst row: number[] = [];\n\t\tfor (let j = 0; j < m; j++) {\n\t\t\trow[j] = i === j ? 1 : 0;\n\t\t}\n\t\tIMQ[i] = row;\n\t}\n\n\tfor (let i = 0; i < m; i++) {\n\t\tconst imqRow = IMQ[i];\n\t\tif (imqRow === undefined) continue;\n\t\tconst qRow = Q[i];\n\n\t\tfor (let j = 0; j < m; j++) {\n\t\t\tconst qVal = qRow?.[j] ?? 0;\n\t\t\timqRow[j] = (i === j ? 1 : 0) - qVal;\n\t\t}\n\t}\n\n\t// Invert (I - Q) using Gaussian elimination\n\tconst N = invertMatrix(IMQ);\n\n\tif (N === null) {\n\t\t// Fallback if inversion fails\n\t\treturn 1;\n\t}\n\n\t// Hitting time from source to target = sum of row corresponding to source\n\tconst sourceTransientIdx = transientIndices.indexOf(sourceIdx);\n\tif (sourceTransientIdx < 0) {\n\t\treturn 0; // Source is already the target\n\t}\n\n\tlet hittingTime = 0;\n\tconst row = N[sourceTransientIdx];\n\tif (row !== undefined) {\n\t\tfor (const val of row) {\n\t\t\thittingTime += val;\n\t\t}\n\t}\n\n\treturn hittingTime;\n}\n\n/**\n * Invert a square matrix using Gaussian elimination with partial pivoting.\n *\n * @param matrix - Input matrix (n × n)\n * @returns Inverted matrix, or null if singular\n */\nfunction invertMatrix(matrix: number[][]): number[][] | null {\n\tconst n = matrix.length;\n\tconst aug: number[][] = [];\n\n\t// Create augmented matrix [A | I]\n\tfor (let i = 0; i < n; i++) {\n\t\tconst row: number[] = [];\n\t\tconst matRow = matrix[i];\n\n\t\tfor (let j = 0; j < n; j++) {\n\t\t\trow[j] = matRow?.[j] ?? 0;\n\t\t}\n\t\tfor (let j = 0; j < n; j++) {\n\t\t\trow[n + j] = i === j ? 1 : 0;\n\t\t}\n\t\taug[i] = row;\n\t}\n\n\t// Forward elimination with partial pivoting\n\tfor (let col = 0; col < n; col++) {\n\t\t// Find pivot\n\t\tlet pivotRow = col;\n\t\tconst pivotCol = aug[pivotRow];\n\t\tif (pivotCol === undefined) return null;\n\n\t\tfor (let row = col + 1; row < n; row++) {\n\t\t\tconst currRowVal = aug[row]?.[col] ?? 0;\n\t\t\tconst pivotRowVal = pivotCol[col] ?? 0;\n\t\t\tif (Math.abs(currRowVal) > Math.abs(pivotRowVal)) {\n\t\t\t\tpivotRow = row;\n\t\t\t}\n\t\t}\n\n\t\t// Check for singular matrix\n\t\tconst augPivot = aug[pivotRow];\n\t\tif (augPivot === undefined || Math.abs(augPivot[col] ?? 0) < 1e-10) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Swap rows\n\t\t[aug[col], aug[pivotRow]] = [aug[pivotRow] ?? [], aug[col] ?? []];\n\n\t\t// Scale pivot row\n\t\tconst scaledPivotRow = aug[col];\n\t\tif (scaledPivotRow === undefined) return null;\n\t\tconst pivot = scaledPivotRow[col] ?? 1;\n\n\t\tfor (let j = 0; j < 2 * n; j++) {\n\t\t\tscaledPivotRow[j] = (scaledPivotRow[j] ?? 0) / pivot;\n\t\t}\n\n\t\t// Eliminate column below pivot\n\t\tfor (let row = col + 1; row < n; row++) {\n\t\t\tconst currRow = aug[row];\n\t\t\tif (currRow === undefined) continue;\n\t\t\tconst factor = currRow[col] ?? 0;\n\n\t\t\tfor (let j = 0; j < 2 * n; j++) {\n\t\t\t\tcurrRow[j] = (currRow[j] ?? 0) - factor * (scaledPivotRow[j] ?? 0);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Back substitution\n\tfor (let col = n - 1; col > 0; col--) {\n\t\tconst colRow = aug[col];\n\t\tif (colRow === undefined) return null;\n\n\t\tfor (let row = col - 1; row >= 0; row--) {\n\t\t\tconst currRow = aug[row];\n\t\t\tif (currRow === undefined) continue;\n\n\t\t\tconst factor = currRow[col] ?? 0;\n\t\t\tfor (let j = 0; j < 2 * n; j++) {\n\t\t\t\tcurrRow[j] = (currRow[j] ?? 0) - factor * (colRow[j] ?? 0);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Extract inverse from augmented matrix\n\tconst inv: number[][] = [];\n\tfor (let i = 0; i < n; i++) {\n\t\tconst row: number[] = [];\n\t\tfor (let j = 0; j < n; j++) {\n\t\t\trow[j] = 0;\n\t\t}\n\t\tinv[i] = row;\n\t}\n\n\tfor (let i = 0; i < n; i++) {\n\t\tconst invRow = inv[i];\n\t\tif (invRow === undefined) continue;\n\t\tconst augRow = aug[i];\n\t\tif (augRow === undefined) continue;\n\n\t\tfor (let j = 0; j < n; j++) {\n\t\t\tinvRow[j] = augRow[n + j] ?? 0;\n\t\t}\n\t}\n\n\treturn inv;\n}\n\n/**\n * Rank paths by inverse hitting time between endpoints.\n *\n * @param graph - Source graph\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths (highest inverse hitting time first)\n */\nexport function hittingTime<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: HittingTimeConfig,\n): BaselineResult {\n\tconst {\n\t\tincludeScores = true,\n\t\tmode = \"auto\",\n\t\twalks = 1000,\n\t\tmaxSteps = 10000,\n\t\tseed = 42,\n\t} = config ?? {};\n\n\tif (paths.length === 0) {\n\t\treturn {\n\t\t\tpaths: [],\n\t\t\tmethod: \"hitting-time\",\n\t\t};\n\t}\n\n\t// Choose computation mode\n\tconst nodeCount = Array.from(graph.nodeIds()).length;\n\tconst actualMode =\n\t\tmode === \"auto\" ? (nodeCount < 100 ? \"exact\" : \"approximate\") : mode;\n\n\tconst rng = new SeededRNG(seed);\n\n\t// Score paths by inverse hitting time between endpoints\n\tconst scored: { path: ExpansionPath; score: number }[] = paths.map((path) => {\n\t\tconst source = path.nodes[0];\n\t\tconst target = path.nodes[path.nodes.length - 1];\n\n\t\tif (source === undefined || target === undefined) {\n\t\t\treturn { path, score: 0 };\n\t\t}\n\n\t\tconst ht =\n\t\t\tactualMode === \"exact\"\n\t\t\t\t? computeHittingTimeExact(graph, source, target)\n\t\t\t\t: computeHittingTimeApproximate(\n\t\t\t\t\t\tgraph,\n\t\t\t\t\t\tsource,\n\t\t\t\t\t\ttarget,\n\t\t\t\t\t\twalks,\n\t\t\t\t\t\tmaxSteps,\n\t\t\t\t\t\trng,\n\t\t\t\t\t);\n\n\t\t// Use inverse: shorter hitting time = higher score\n\t\tconst score = ht > 0 ? 1 / ht : 0;\n\t\treturn { path, score };\n\t});\n\n\t// Guard against non-finite scores before normalisation\n\tconst maxScore = Math.max(...scored.map((s) => s.score));\n\tif (!Number.isFinite(maxScore)) {\n\t\treturn {\n\t\t\tpaths: paths.map((path) => ({ ...path, score: 0 })),\n\t\t\tmethod: \"hitting-time\",\n\t\t};\n\t}\n\n\treturn normaliseAndRank(paths, scored, \"hitting-time\", includeScores);\n}\n"],"mappings":"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"}
|