graphwise 1.9.1 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +42 -19
- package/dist/index/index.js +11 -9
- 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/crest.d.ts +48 -0
- package/dist/seeds/crest.d.ts.map +1 -0
- package/dist/seeds/crest.unit.test.d.ts +2 -0
- package/dist/seeds/crest.unit.test.d.ts.map +1 -0
- package/dist/seeds/crisp.d.ts +57 -0
- package/dist/seeds/crisp.d.ts.map +1 -0
- package/dist/seeds/crisp.unit.test.d.ts +2 -0
- package/dist/seeds/crisp.unit.test.d.ts.map +1 -0
- package/dist/seeds/grasp-gpu.d.ts +40 -0
- package/dist/seeds/grasp-gpu.d.ts.map +1 -0
- package/dist/seeds/index.cjs +715 -5
- package/dist/seeds/index.cjs.map +1 -1
- package/dist/seeds/index.d.ts +4 -0
- package/dist/seeds/index.d.ts.map +1 -1
- package/dist/seeds/index.js +712 -6
- package/dist/seeds/index.js.map +1 -1
- package/dist/seeds/spine.d.ts +50 -0
- package/dist/seeds/spine.d.ts.map +1 -0
- package/dist/seeds/spine.unit.test.d.ts +2 -0
- package/dist/seeds/spine.unit.test.d.ts.map +1 -0
- package/dist/seeds/stride.d.ts +55 -0
- package/dist/seeds/stride.d.ts.map +1 -0
- package/dist/seeds/stride.unit.test.d.ts +2 -0
- package/dist/seeds/stride.unit.test.d.ts.map +1 -0
- 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
package/dist/seeds/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/seeds/grasp.ts","../../src/seeds/stratified.ts"],"sourcesContent":["/**\n * GRASP — Graph-agnostic Representative Seed pAir Sampling.\n *\n * Novel blind structural seed selection algorithm that selects structurally\n * representative seed pairs without requiring domain knowledge or loading\n * the full graph into memory.\n *\n * Three phases:\n * 1. Reservoir sampling — stream edges, maintain reservoir of N nodes\n * 2. Structural feature computation — log-degree, clustering coeff, approx PageRank\n * 3. Mini-batch K-means clustering, then sample pairs within and across clusters\n *\n * @packageDocumentation\n */\n\nimport type { ReadableGraph, NodeId } from \"../graph\";\nimport type { Seed } from \"../schemas/index\";\nimport {\n\tminiBatchKMeans,\n\tzScoreNormalise,\n\ttype LabelledFeature,\n\ttype FeatureVector3D,\n} from \"../utils/kmeans\";\n\n/**\n * Configuration options for GRASP seed selection.\n */\nexport interface GraspOptions {\n\t/** Number of clusters for K-means (default: 100) */\n\treadonly nClusters?: number;\n\t/** Number of pairs to sample per cluster (default: 10) */\n\treadonly pairsPerCluster?: number;\n\t/** Ratio of within-cluster pairs vs cross-cluster pairs (default: 0.5) */\n\treadonly withinClusterRatio?: number;\n\t/** Reservoir sample size (default: 200000) */\n\treadonly sampleSize?: number;\n\t/** Random seed for reproducibility (default: 42) */\n\treadonly rngSeed?: number;\n\t/** Number of PageRank iterations for feature computation (default: 10) */\n\treadonly pagerankIterations?: number;\n}\n\n/**\n * A sampled seed pair with structural metadata.\n */\nexport interface GraspSeedPair {\n\t/** Source seed */\n\treadonly source: Seed;\n\t/** Target seed */\n\treadonly target: Seed;\n\t/** Euclidean distance in feature space */\n\treadonly featureDistance: number;\n\t/** Whether both seeds are from the same cluster */\n\treadonly sameCluster: boolean;\n\t/** Cluster index of source (or -1 if unclustered) */\n\treadonly sourceCluster: number;\n\t/** Cluster index of target (or -1 if unclustered) */\n\treadonly targetCluster: number;\n}\n\n/**\n * Result of GRASP seed selection.\n */\nexport interface GraspResult {\n\t/** Sampled seed pairs */\n\treadonly pairs: readonly GraspSeedPair[];\n\t/** Number of clusters used */\n\treadonly nClusters: number;\n\t/** Total nodes sampled */\n\treadonly sampledNodeCount: number;\n\t/** Features computed for sampled nodes */\n\treadonly features: readonly LabelledFeature[];\n\t/** Cluster assignments (nodeId -> cluster index) */\n\treadonly clusterAssignments: ReadonlyMap<string, number>;\n}\n\n/** Default configuration values */\nconst DEFAULTS = {\n\tnClusters: 100,\n\tpairsPerCluster: 10,\n\twithinClusterRatio: 0.5,\n\tsampleSize: 200000,\n\trngSeed: 42,\n\tpagerankIterations: 10,\n} as const;\n\n/**\n * Simple seeded pseudo-random number generator using mulberry32.\n */\nfunction createRNG(seed: number): () => number {\n\tlet state = seed >>> 0;\n\treturn (): number => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = Math.imul(state ^ (state >>> 15), state | 1);\n\t\tt = (t ^ (t >>> 7)) * (t | 0x61c88647);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/**\n * Reservoir sampling (Vitter's Algorithm R) for streaming node selection.\n *\n * Maintains a uniform sample of nodes as edges are streamed, without\n * requiring the full graph in memory.\n */\nfunction reservoirSample(\n\tgraph: ReadableGraph,\n\tsampleSize: number,\n\trng: () => number,\n): { nodeIds: Set<NodeId>; neighbourMap: Map<NodeId, Set<NodeId>> } {\n\tconst reservoir: NodeId[] = [];\n\tconst neighbourMap = new Map<NodeId, Set<NodeId>>();\n\tconst inReservoir = new Set<NodeId>();\n\n\t// Track total nodes seen for reservoir probability\n\tlet nodesSeen = 0;\n\n\t// Stream all edges and sample nodes\n\tfor (const edge of graph.edges()) {\n\t\t// Process source node\n\t\tconst source = edge.source;\n\t\tif (!inReservoir.has(source)) {\n\t\t\tnodesSeen++;\n\t\t\tif (reservoir.length < sampleSize) {\n\t\t\t\treservoir.push(source);\n\t\t\t\tinReservoir.add(source);\n\t\t\t\tneighbourMap.set(source, new Set<NodeId>());\n\t\t\t} else {\n\t\t\t\t// Reservoir sampling: replace with probability sampleSize/nodesSeen\n\t\t\t\tconst j = Math.floor(rng() * nodesSeen);\n\t\t\t\tif (j < sampleSize) {\n\t\t\t\t\tconst oldNode = reservoir[j];\n\t\t\t\t\tif (oldNode !== undefined) {\n\t\t\t\t\t\tinReservoir.delete(oldNode);\n\t\t\t\t\t\tneighbourMap.delete(oldNode);\n\t\t\t\t\t}\n\t\t\t\t\treservoir[j] = source;\n\t\t\t\t\tinReservoir.add(source);\n\t\t\t\t\tneighbourMap.set(source, new Set<NodeId>());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Process target node\n\t\tconst target = edge.target;\n\t\tif (!inReservoir.has(target)) {\n\t\t\tnodesSeen++;\n\t\t\tif (reservoir.length < sampleSize) {\n\t\t\t\treservoir.push(target);\n\t\t\t\tinReservoir.add(target);\n\t\t\t\tneighbourMap.set(target, new Set<NodeId>());\n\t\t\t} else {\n\t\t\t\tconst j = Math.floor(rng() * nodesSeen);\n\t\t\t\tif (j < sampleSize) {\n\t\t\t\t\tconst oldNode = reservoir[j];\n\t\t\t\t\tif (oldNode !== undefined) {\n\t\t\t\t\t\tinReservoir.delete(oldNode);\n\t\t\t\t\t\tneighbourMap.delete(oldNode);\n\t\t\t\t\t}\n\t\t\t\t\treservoir[j] = target;\n\t\t\t\t\tinReservoir.add(target);\n\t\t\t\t\tneighbourMap.set(target, new Set<NodeId>());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Store neighbour relationships for sampled nodes\n\t\tif (inReservoir.has(source) && inReservoir.has(target)) {\n\t\t\tconst sourceNeighbours = neighbourMap.get(source);\n\t\t\tconst targetNeighbours = neighbourMap.get(target);\n\t\t\tsourceNeighbours?.add(target);\n\t\t\ttargetNeighbours?.add(source);\n\t\t}\n\t}\n\n\treturn { nodeIds: inReservoir, neighbourMap };\n}\n\n/**\n * Compute approximate PageRank scores using power iteration on the reservoir subgraph.\n *\n * This is an approximation since it only considers the sampled nodes and their\n * connections within the reservoir, not the full graph.\n */\nfunction approximatePageRank(\n\tnodeIds: Set<NodeId>,\n\tneighbourMap: Map<NodeId, Set<NodeId>>,\n\titerations: number,\n\tdampingFactor = 0.85,\n): Map<NodeId, number> {\n\tconst n = nodeIds.size;\n\tif (n === 0) return new Map();\n\n\tconst nodeIdList = [...nodeIds];\n\tconst nodeIndex = new Map(nodeIdList.map((id, i) => [id, i] as const));\n\n\t// Initialise PageRank scores uniformly\n\tconst scores = new Float64Array(n).fill(1 / n);\n\tconst newScores = new Float64Array(n);\n\n\t// Power iteration\n\tfor (let iter = 0; iter < iterations; iter++) {\n\t\tnewScores.fill((1 - dampingFactor) / n);\n\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst nodeId = nodeIdList[i];\n\t\t\tif (nodeId === undefined) continue;\n\n\t\t\tconst neighbours = neighbourMap.get(nodeId);\n\t\t\tif (neighbours === undefined) continue;\n\n\t\t\tconst outDegree = neighbours.size;\n\t\t\tif (outDegree === 0) continue;\n\n\t\t\tconst contribution = (dampingFactor * (scores[i] ?? 0)) / outDegree;\n\n\t\t\tfor (const neighbour of neighbours) {\n\t\t\t\tconst neighbourIdx = nodeIndex.get(neighbour);\n\t\t\t\tif (neighbourIdx !== undefined) {\n\t\t\t\t\tnewScores[neighbourIdx] =\n\t\t\t\t\t\t(newScores[neighbourIdx] ?? 0) + contribution;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Swap buffers\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tscores[i] = newScores[i] ?? 0;\n\t\t}\n\t}\n\n\t// Build result map\n\tconst result = new Map<NodeId, number>();\n\tfor (let i = 0; i < n; i++) {\n\t\tconst nodeId = nodeIdList[i];\n\t\tconst score = scores[i];\n\t\tif (nodeId !== undefined && score !== undefined) {\n\t\t\tresult.set(nodeId, score);\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Compute structural features for sampled nodes.\n *\n * Features:\n * - f1: log(deg(v) + 1) — scale-normalised connectivity\n * - f2: clustering_coefficient(v) — local density\n * - f3: approx_pagerank(v) — positional importance\n */\nfunction computeFeatures(\n\tgraph: ReadableGraph,\n\tnodeIds: Set<NodeId>,\n\tneighbourMap: Map<NodeId, Set<NodeId>>,\n\tpagerankScores: Map<NodeId, number>,\n): LabelledFeature[] {\n\tconst features: LabelledFeature[] = [];\n\n\tfor (const nodeId of nodeIds) {\n\t\tconst degree = graph.degree(nodeId, \"both\");\n\t\tconst neighbours = neighbourMap.get(nodeId);\n\n\t\t// Compute local clustering coefficient using neighbour map\n\t\tlet clusteringCoef = 0;\n\t\tif (neighbours !== undefined && neighbours.size >= 2) {\n\t\t\tlet triangleCount = 0;\n\t\t\tconst neighbourList = [...neighbours];\n\n\t\t\tfor (let i = 0; i < neighbourList.length; i++) {\n\t\t\t\tfor (let j = i + 1; j < neighbourList.length; j++) {\n\t\t\t\t\tconst u = neighbourList[i];\n\t\t\t\t\tconst w = neighbourList[j];\n\t\t\t\t\tif (u !== undefined && w !== undefined) {\n\t\t\t\t\t\t// Check if u and w are connected\n\t\t\t\t\t\tconst uNeighbours = neighbourMap.get(u);\n\t\t\t\t\t\tif (uNeighbours?.has(w) === true) {\n\t\t\t\t\t\t\ttriangleCount++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst possibleTriangles = (degree * (degree - 1)) / 2;\n\t\t\tclusteringCoef = triangleCount / possibleTriangles;\n\t\t}\n\n\t\tconst pagerank = pagerankScores.get(nodeId) ?? 0;\n\n\t\tfeatures.push({\n\t\t\tnodeId,\n\t\t\tf1: Math.log(degree + 1),\n\t\t\tf2: clusteringCoef,\n\t\t\tf3: pagerank,\n\t\t});\n\t}\n\n\treturn features;\n}\n\n/**\n * Sample seed pairs from clusters.\n *\n * For each cluster, samples a mix of within-cluster and cross-cluster pairs.\n */\nfunction samplePairs(\n\tfeatures: readonly LabelledFeature[],\n\tclusterAssignments: ReadonlyMap<string, number>,\n\tnClusters: number,\n\tpairsPerCluster: number,\n\twithinClusterRatio: number,\n\trng: () => number,\n): GraspSeedPair[] {\n\tconst pairs: GraspSeedPair[] = [];\n\n\t// Group nodes by cluster\n\tconst clusterNodes = new Map<number, LabelledFeature[]>();\n\tfor (const feature of features) {\n\t\tconst cluster = clusterAssignments.get(feature.nodeId);\n\t\tif (cluster === undefined) continue;\n\n\t\tlet nodes = clusterNodes.get(cluster);\n\t\tif (nodes === undefined) {\n\t\t\tnodes = [];\n\t\t\tclusterNodes.set(cluster, nodes);\n\t\t}\n\t\tnodes.push(feature);\n\t}\n\n\tconst withinCount = Math.floor(pairsPerCluster * withinClusterRatio);\n\tconst crossCount = pairsPerCluster - withinCount;\n\n\t// Sample pairs for each cluster\n\tfor (let clusterIdx = 0; clusterIdx < nClusters; clusterIdx++) {\n\t\tconst nodes = clusterNodes.get(clusterIdx);\n\t\tif (nodes === undefined || nodes.length < 2) continue;\n\n\t\t// Within-cluster pairs\n\t\tfor (let i = 0; i < withinCount; i++) {\n\t\t\t// Sample two distinct nodes\n\t\t\tconst idx1 = Math.floor(rng() * nodes.length);\n\t\t\tlet idx2 = Math.floor(rng() * nodes.length);\n\t\t\twhile (idx1 === idx2) {\n\t\t\t\tidx2 = Math.floor(rng() * nodes.length);\n\t\t\t}\n\n\t\t\tconst source = nodes[idx1];\n\t\t\tconst target = nodes[idx2];\n\t\t\tif (source === undefined || target === undefined) continue;\n\n\t\t\tconst distance = computeFeatureDistance(source, target);\n\n\t\t\tpairs.push({\n\t\t\t\tsource: { id: source.nodeId },\n\t\t\t\ttarget: { id: target.nodeId },\n\t\t\t\tfeatureDistance: distance,\n\t\t\t\tsameCluster: true,\n\t\t\t\tsourceCluster: clusterIdx,\n\t\t\t\ttargetCluster: clusterIdx,\n\t\t\t});\n\t\t}\n\n\t\t// Cross-cluster pairs\n\t\tfor (let i = 0; i < crossCount; i++) {\n\t\t\tconst source = nodes[Math.floor(rng() * nodes.length)];\n\t\t\tif (source === undefined) continue;\n\n\t\t\t// Pick a random other cluster\n\t\t\tconst otherClusterIdx = Math.floor(rng() * nClusters);\n\t\t\tif (otherClusterIdx === clusterIdx) continue;\n\n\t\t\tconst otherNodes = clusterNodes.get(otherClusterIdx);\n\t\t\tif (otherNodes === undefined || otherNodes.length === 0) continue;\n\n\t\t\tconst target = otherNodes[Math.floor(rng() * otherNodes.length)];\n\t\t\tif (target === undefined) continue;\n\n\t\t\tconst distance = computeFeatureDistance(source, target);\n\n\t\t\tpairs.push({\n\t\t\t\tsource: { id: source.nodeId },\n\t\t\t\ttarget: { id: target.nodeId },\n\t\t\t\tfeatureDistance: distance,\n\t\t\t\tsameCluster: false,\n\t\t\t\tsourceCluster: clusterIdx,\n\t\t\t\ttargetCluster: otherClusterIdx,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn pairs;\n}\n\n/**\n * Compute Euclidean distance between two feature vectors.\n */\nfunction computeFeatureDistance(\n\ta: FeatureVector3D,\n\tb: FeatureVector3D,\n): number {\n\tconst d1 = a.f1 - b.f1;\n\tconst d2 = a.f2 - b.f2;\n\tconst d3 = a.f3 - b.f3;\n\treturn Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3);\n}\n\n/**\n * GRASP — Graph-agnostic Representative Seed pAir Sampling.\n *\n * Selects structurally representative seed pairs without domain knowledge.\n * The algorithm streams edges, samples nodes via reservoir sampling, computes\n * structural features, clusters nodes, and samples pairs within/across clusters.\n *\n * @param graph - The graph to sample seeds from\n * @param options - Configuration options\n * @returns Sampled seed pairs with structural metadata\n *\n * @example\n * ```typescript\n * const graph = new AdjacencyMapGraph();\n * // ... populate graph ...\n *\n * const result = grasp(graph, {\n * nClusters: 50,\n * pairsPerCluster: 20,\n * sampleSize: 100000,\n * });\n *\n * console.log(`Sampled ${result.pairs.length} pairs from ${result.sampledNodeCount} nodes`);\n * ```\n */\nexport function grasp(\n\tgraph: ReadableGraph,\n\toptions: GraspOptions = {},\n): GraspResult {\n\tconst config = {\n\t\t...DEFAULTS,\n\t\t...options,\n\t};\n\n\tconst rng = createRNG(config.rngSeed);\n\n\t// Phase 1: Reservoir sampling\n\tconst { nodeIds, neighbourMap } = reservoirSample(\n\t\tgraph,\n\t\tconfig.sampleSize,\n\t\trng,\n\t);\n\n\t// Phase 2: Approximate PageRank on reservoir subgraph\n\tconst pagerankScores = approximatePageRank(\n\t\tnodeIds,\n\t\tneighbourMap,\n\t\tconfig.pagerankIterations,\n\t);\n\n\t// Phase 2: Compute structural features\n\tlet features = computeFeatures(graph, nodeIds, neighbourMap, pagerankScores);\n\n\t// Normalise features\n\tif (features.length > 0) {\n\t\tfeatures = zScoreNormalise(features);\n\t}\n\n\t// Phase 3: K-means clustering\n\tconst k = Math.min(config.nClusters, features.length);\n\tconst kmeansResult = miniBatchKMeans(features, {\n\t\tk,\n\t\tseed: config.rngSeed,\n\t\tmaxIterations: 100,\n\t});\n\n\t// Phase 3: Sample pairs\n\tconst pairs = samplePairs(\n\t\tfeatures,\n\t\tkmeansResult.assignments,\n\t\tkmeansResult.k,\n\t\tconfig.pairsPerCluster,\n\t\tconfig.withinClusterRatio,\n\t\trng,\n\t);\n\n\treturn {\n\t\tpairs,\n\t\tnClusters: kmeansResult.k,\n\t\tsampledNodeCount: nodeIds.size,\n\t\tfeatures,\n\t\tclusterAssignments: kmeansResult.assignments,\n\t};\n}\n","/**\n * Stratified seed selection — legacy human-defined strata.\n *\n * Requires user-provided field/type classifications. This is included for comparison\n * and for users who have domain metadata.\n *\n * @packageDocumentation\n */\n\nimport type { ReadableGraph, NodeId } from \"../graph/index\";\nimport type { Seed } from \"../schemas/index\";\n\n/**\n * Field classification function type.\n * User provides a function that returns the field name for a node.\n */\nexport type FieldClassifier = (node: {\n\tid: NodeId;\n\ttype?: string;\n}) => string | undefined;\n\n/**\n * Stratum definition for seed pair selection.\n */\nexport interface StratumDefinition {\n\treadonly name: string;\n\treadonly description: string;\n\treadonly predicate: (\n\t\tsource: { id: NodeId; type?: string },\n\t\ttarget: { id: NodeId; type?: string },\n\t) => boolean;\n}\n\n/**\n * Stratum with sampled seed pairs.\n */\nexport interface StratumResult {\n\treadonly name: string;\n\treadonly pairs: readonly SeedPair[];\n}\n\n/**\n * A seed pair with stratum metadata.\n */\nexport interface SeedPair {\n\treadonly source: Seed;\n\treadonly target: Seed;\n\treadonly stratum: string;\n\treadonly sameField: boolean;\n}\n\n/**\n * Result of stratified seed selection.\n */\nexport interface StratifiedResult {\n\treadonly strata: readonly StratumResult[];\n\treadonly totalPairs: number;\n\treadonly errors: readonly Error[];\n}\n\n/**\n * Configuration for stratified seed selection.\n */\nexport interface StratifiedOptions {\n\t/** Function to classify nodes by field */\n\treadonly fieldClassifier: FieldClassifier;\n\t/** Number of pairs to sample per stratum */\n\treadonly pairsPerStratum?: number;\n\t/** Random seed for reproducibility */\n\treadonly rngSeed?: number;\n\t/** Custom stratum definitions */\n\treadonly customStrata?: readonly StratumDefinition[];\n}\n\n/** Default values */\nconst DEFAULTS = {\n\tpairsPerStratum: 10,\n\trngSeed: 42,\n} as const;\n\n/**\n * Simple seeded pseudo-random number generator using mulberry32.\n */\nfunction createRNG(seed: number): () => number {\n\tlet state = seed >>> 0;\n\treturn (): number => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = Math.imul(state ^ (state >>> 15), state | 1);\n\t\tt = (t ^ (t >>> 7)) * (t | 0x61c88647);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/**\n * Stratified seed selection algorithm.\n *\n * @param graph - The graph to sample seeds from\n * @param options - Configuration options including field classifier\n * @returns Stratified selection result\n *\n * @example\n * ```typescript\n * const graph = new AdjacencyMapGraph();\n * // ... populate graph ...\n *\n * const result = stratified(graph, {\n * fieldClassifier: (node) => node.type === 'paper' ? 'computer-science' : undefined,\n * pairsPerStratum: 20,\n * });\n *\n * for (const stratum of result.strata) {\n * console.log(`${stratum.name}: ${stratum.pairs.length} pairs`);\n * }\n * ```\n */\nexport function stratified(\n\tgraph: ReadableGraph,\n\toptions: StratifiedOptions,\n): StratifiedResult {\n\tconst {\n\t\tfieldClassifier,\n\t\tpairsPerStratum = DEFAULTS.pairsPerStratum,\n\t\trngSeed = DEFAULTS.rngSeed,\n\t\tcustomStrata,\n\t} = options;\n\n\tconst rng = createRNG(rngSeed);\n\tconst strataDefinitions = customStrata ?? [];\n\n\t// Collect all nodes with their field classifications\n\tconst nodesWithFields: { id: NodeId; type?: string; field?: string }[] = [];\n\n\tfor (const nodeId of graph.nodeIds()) {\n\t\tconst node = graph.getNode(nodeId);\n\t\tif (node === undefined) continue;\n\n\t\tconst classifierInput: { id: NodeId; type?: string } =\n\t\t\tnode.type !== undefined\n\t\t\t\t? { id: nodeId, type: node.type }\n\t\t\t\t: { id: nodeId };\n\t\tconst field = fieldClassifier(classifierInput);\n\t\tif (field === undefined) continue;\n\n\t\tconst nodeWithField: { id: NodeId; type?: string; field: string } =\n\t\t\tnode.type !== undefined\n\t\t\t\t? { id: nodeId, type: node.type, field }\n\t\t\t\t: { id: nodeId, field };\n\t\tnodesWithFields.push(nodeWithField);\n\t}\n\n\tconst errors: Error[] = [];\n\tconst strataResults: StratumResult[] = [];\n\n\t// Process each stratum\n\tfor (const stratum of strataDefinitions) {\n\t\tconst pairs: SeedPair[] = [];\n\t\tconst eligiblePairs: {\n\t\t\tsource: { id: NodeId; type?: string };\n\t\t\ttarget: { id: NodeId; type?: string };\n\t\t}[] = [];\n\n\t\t// Find all node pairs that match this stratum\n\t\tfor (let i = 0; i < nodesWithFields.length; i++) {\n\t\t\tconst source = nodesWithFields[i];\n\t\t\tif (source === undefined) continue;\n\n\t\t\tfor (let j = i + 1; j < nodesWithFields.length; j++) {\n\t\t\t\tif (j === i) continue;\n\t\t\t\tconst target = nodesWithFields[j];\n\t\t\t\tif (target === undefined) continue;\n\n\t\t\t\tif (stratum.predicate(source, target)) {\n\t\t\t\t\teligiblePairs.push({ source, target });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Sample pairs from eligible pairs\n\t\tconst numToSample = Math.min(pairsPerStratum, eligiblePairs.length);\n\t\tfor (let i = 0; i < numToSample; i++) {\n\t\t\tconst idx = Math.floor(rng() * eligiblePairs.length);\n\t\t\tconst pair = eligiblePairs[idx];\n\t\t\tif (pair === undefined) continue;\n\n\t\t\tconst sourceField = fieldClassifier(pair.source);\n\t\t\tconst targetField = fieldClassifier(pair.target);\n\n\t\t\tpairs.push({\n\t\t\t\tsource: { id: pair.source.id },\n\t\t\t\ttarget: { id: pair.target.id },\n\t\t\t\tstratum: stratum.name,\n\t\t\t\tsameField: sourceField === targetField,\n\t\t\t});\n\t\t}\n\n\t\tstrataResults.push({\n\t\t\tname: stratum.name,\n\t\t\tpairs,\n\t\t});\n\t}\n\n\t// Collect errors for empty strata\n\tfor (const stratum of strataDefinitions) {\n\t\tconst result = strataResults.find((r) => r.name === stratum.name);\n\t\tif (result === undefined || result.pairs.length === 0) {\n\t\t\terrors.push(new Error(`No pairs found for stratum: ${stratum.name}`));\n\t\t}\n\t}\n\n\tconst totalPairs = strataResults.reduce((sum, r) => sum + r.pairs.length, 0);\n\n\treturn {\n\t\tstrata: strataResults,\n\t\ttotalPairs,\n\t\terrors,\n\t};\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/seeds/crisp.ts","../../src/seeds/crest.ts","../../src/seeds/grasp.ts","../../src/seeds/spine.ts","../../src/seeds/stride.ts","../../src/seeds/stratified.ts"],"sourcesContent":["/**\n * CRISP — Connectivity-Rich Informed Seed Pairing.\n *\n * Selects diverse seed pairs with high path potential using:\n * - BFS distance filtering (target 2–4 hops)\n * - Common neighbour scoring (prefer pairs with shared neighbourhood)\n * - Jaccard diversity (avoid redundant pairs)\n *\n * Originally implemented in Python experiments, now a first-class\n * seed selection method in graphwise.\n *\n * Time Complexity: O(nPairs * sampleSize * (V + E)) for BFS per candidate\n * Space Complexity: O(V) per BFS\n *\n * @packageDocumentation\n */\n\nimport type { ReadableGraph, NodeId } from \"../graph\";\nimport type { Seed } from \"../schemas/index\";\n\n/**\n * Configuration options for CRISP seed selection.\n */\nexport interface CrispOptions {\n\t/** Number of seed pairs to select (default: 100) */\n\treadonly nPairs?: number;\n\t/** Random seed for reproducibility (default: 42) */\n\treadonly rngSeed?: number;\n\t/** Minimum BFS distance to consider (default: 2) */\n\treadonly minDistance?: number;\n\t/** Maximum BFS distance to consider (default: 4) */\n\treadonly maxDistance?: number;\n\t/** Minimum common neighbours required (default: 2) */\n\treadonly minCommonNeighbours?: number;\n\t/** Jaccard diversity threshold for greedy selection (default: 0.5) */\n\treadonly diversityThreshold?: number;\n\t/** Number of candidate pairs to sample before greedy selection (default: 5000) */\n\treadonly sampleSize?: number;\n}\n\n/**\n * A seed pair selected by CRISP with connectivity metadata.\n */\nexport interface CrispSeedPair {\n\t/** Source seed */\n\treadonly source: Seed;\n\t/** Target seed */\n\treadonly target: Seed;\n\t/** BFS distance between source and target */\n\treadonly distance: number;\n\t/** Common neighbour count */\n\treadonly commonNeighbours: number;\n\t/** Connectivity score */\n\treadonly score: number;\n}\n\n/**\n * Result of CRISP seed selection.\n */\nexport interface CrispResult {\n\t/** Selected seed pairs */\n\treadonly pairs: readonly CrispSeedPair[];\n}\n\n/** Default configuration values */\nconst DEFAULTS = {\n\tnPairs: 100,\n\trngSeed: 42,\n\tminDistance: 2,\n\tmaxDistance: 4,\n\tminCommonNeighbours: 2,\n\tdiversityThreshold: 0.5,\n\tsampleSize: 5000,\n} as const;\n\n/**\n * Simple seeded pseudo-random number generator using mulberry32.\n */\nfunction createRNG(seed: number): () => number {\n\tlet state = seed >>> 0;\n\treturn (): number => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = Math.imul(state ^ (state >>> 15), state | 1);\n\t\tt = (t ^ (t >>> 7)) * (t | 0x61c88647);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/**\n * Compute shortest-path distance between two nodes via BFS.\n * Returns -1 if no path exists.\n */\nfunction bfsDistance(\n\tgraph: ReadableGraph,\n\tsource: NodeId,\n\ttarget: NodeId,\n): number {\n\tif (source === target) return 0;\n\n\tconst visited = new Set<NodeId>([source]);\n\tconst queue: { node: NodeId; dist: number }[] = [{ node: source, dist: 0 }];\n\n\twhile (queue.length > 0) {\n\t\tconst item = queue.shift();\n\t\tif (!item) break;\n\t\tconst { node, dist } = item;\n\n\t\tfor (const neighbour of graph.neighbours(node)) {\n\t\t\tif (neighbour === target) return dist + 1;\n\t\t\tif (!visited.has(neighbour)) {\n\t\t\t\tvisited.add(neighbour);\n\t\t\t\tqueue.push({ node: neighbour, dist: dist + 1 });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn -1;\n}\n\n/**\n * Get the 1-hop neighbour set of a node.\n */\nfunction neighbourSet(graph: ReadableGraph, node: NodeId): Set<NodeId> {\n\treturn new Set(graph.neighbours(node));\n}\n\n/**\n * Count common neighbours between two nodes.\n */\nfunction commonNeighbours(graph: ReadableGraph, a: NodeId, b: NodeId): number {\n\tconst na = neighbourSet(graph, a);\n\tconst nb = neighbourSet(graph, b);\n\tlet count = 0;\n\tfor (const n of na) {\n\t\tif (nb.has(n)) count++;\n\t}\n\treturn count;\n}\n\n/**\n * Compute Jaccard similarity between two sets.\n */\nfunction jaccard<T>(a: Set<T>, b: Set<T>): number {\n\tlet intersection = 0;\n\tfor (const x of a) {\n\t\tif (b.has(x)) intersection++;\n\t}\n\tconst union = new Set([...a, ...b]).size;\n\treturn union === 0 ? 0 : intersection / union;\n}\n\n/**\n * Compute distance score peaking at distance 3.\n * Score ranges from 0 to 1, with maximum at dist=3.\n */\nfunction distanceScore(dist: number): number {\n\treturn 1.0 - Math.abs(dist - 3.0) / 3.0;\n}\n\n/**\n * CRISP — Connectivity-Rich Informed Seed Pairing.\n *\n * Samples random node pairs and scores them by common neighbour count\n * and BFS distance (preferring 2–4 hops, peaking at 3). Greedy\n * selection with Jaccard diversity ensures selected pairs are\n * spread across different structural regions.\n *\n * @param graph - The graph to sample seeds from\n * @param options - Configuration options\n * @returns Selected seed pairs with connectivity metadata\n */\nexport function crisp(\n\tgraph: ReadableGraph,\n\toptions: CrispOptions = {},\n): CrispResult {\n\tconst config = { ...DEFAULTS, ...options };\n\tconst rng = createRNG(config.rngSeed);\n\n\tconst allNodes = [...graph.nodeIds()];\n\n\tif (allNodes.length < 2) {\n\t\treturn { pairs: [] };\n\t}\n\n\tif (allNodes.length < 4) {\n\t\tconst a = allNodes[0];\n\t\tconst b = allNodes[1];\n\t\tif (a !== undefined && b !== undefined) {\n\t\t\treturn {\n\t\t\t\tpairs: [\n\t\t\t\t\t{\n\t\t\t\t\t\tsource: { id: a },\n\t\t\t\t\t\ttarget: { id: b },\n\t\t\t\t\t\tdistance: 1,\n\t\t\t\t\t\tcommonNeighbours: 0,\n\t\t\t\t\t\tscore: 0,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t}\n\t\treturn { pairs: [] };\n\t}\n\n\t// Phase 1: Sample and score candidate pairs\n\tconst candidates: {\n\t\tscore: number;\n\t\tdistance: number;\n\t\tcommonNeighbours: number;\n\t\ta: NodeId;\n\t\tb: NodeId;\n\t}[] = [];\n\tconst sampledPairs = new Set<string>();\n\n\tconst maxAttempts = config.sampleSize * 10;\n\tlet attempts = 0;\n\n\twhile (sampledPairs.size < config.sampleSize && attempts < maxAttempts) {\n\t\tattempts++;\n\t\tconst a = allNodes[Math.floor(rng() * allNodes.length)];\n\t\tconst b = allNodes[Math.floor(rng() * allNodes.length)];\n\t\tif (a === undefined || b === undefined || a === b) continue;\n\n\t\tconst pairKey = a < b ? `${a}|${b}` : `${b}|${a}`;\n\t\tif (sampledPairs.has(pairKey)) continue;\n\t\tsampledPairs.add(pairKey);\n\n\t\tconst dist = bfsDistance(graph, a, b);\n\t\tif (dist < config.minDistance || dist > config.maxDistance) continue;\n\n\t\tconst cn = commonNeighbours(graph, a, b);\n\t\tif (cn < config.minCommonNeighbours) continue;\n\n\t\t// Score: prefer higher common neighbours and mid-range distance\n\t\tconst distScore = distanceScore(dist);\n\t\tconst score = cn * (1.0 + distScore);\n\t\tcandidates.push({ score, distance: dist, commonNeighbours: cn, a, b });\n\t}\n\n\t// Phase 1.5: Relax constraints if not enough candidates\n\tif (candidates.length < config.nPairs) {\n\t\tfor (const pairKey of sampledPairs) {\n\t\t\tconst parts = pairKey.split(\"|\");\n\t\t\tif (parts.length !== 2) continue;\n\t\t\tconst a = parts[0];\n\t\t\tconst b = parts[1];\n\t\t\tif (a === undefined || b === undefined) continue;\n\t\t\tconst dist = bfsDistance(graph, a, b);\n\t\t\tif (dist < 1 || dist > 6) continue;\n\n\t\t\tconst cn = commonNeighbours(graph, a, b);\n\t\t\tconst score = cn + 0.1;\n\t\t\tcandidates.push({ score, distance: dist, commonNeighbours: cn, a, b });\n\t\t}\n\t}\n\n\t// Sort by score descending\n\tcandidates.sort((x, y) => y.score - x.score);\n\n\t// Phase 2: Greedy selection with Jaccard diversity\n\tconst selected: CrispSeedPair[] = [];\n\tconst selectedPairKeys = new Set<string>();\n\n\tfor (const { score, distance, commonNeighbours, a, b } of candidates) {\n\t\tif (selected.length >= config.nPairs) break;\n\n\t\tconst pairKey = a < b ? `${a}|${b}` : `${b}|${a}`;\n\t\tif (selectedPairKeys.has(pairKey)) continue;\n\n\t\tconst aNbrs = neighbourSet(graph, a);\n\t\tconst bNbrs = neighbourSet(graph, b);\n\n\t\tlet isDiverse = true;\n\t\tfor (const prev of selected) {\n\t\t\tconst paNbrs = neighbourSet(graph, prev.source.id);\n\t\t\tconst pbNbrs = neighbourSet(graph, prev.target.id);\n\n\t\t\tif (\n\t\t\t\tjaccard(aNbrs, paNbrs) >= config.diversityThreshold &&\n\t\t\t\tjaccard(bNbrs, pbNbrs) >= config.diversityThreshold\n\t\t\t) {\n\t\t\t\tisDiverse = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!isDiverse) continue;\n\n\t\tselectedPairKeys.add(pairKey);\n\t\tselected.push({\n\t\t\tsource: { id: a },\n\t\t\ttarget: { id: b },\n\t\t\tdistance,\n\t\t\tcommonNeighbours,\n\t\t\tscore,\n\t\t});\n\t}\n\n\t// Phase 3: Fill shortfall with random pairs\n\tlet fillAttempts = 0;\n\twhile (\n\t\tselected.length < config.nPairs &&\n\t\tallNodes.length >= 2 &&\n\t\tfillAttempts < config.nPairs * 20\n\t) {\n\t\tfillAttempts++;\n\t\tconst i1 = Math.floor(rng() * allNodes.length);\n\t\tconst i2 = Math.floor(rng() * allNodes.length);\n\t\tconst a = allNodes[i1];\n\t\tconst b = allNodes[i2];\n\t\tif (a === undefined || b === undefined || a === b) continue;\n\n\t\tconst pairKey = a < b ? `${a}|${b}` : `${b}|${a}`;\n\t\tif (selectedPairKeys.has(pairKey)) continue;\n\n\t\tselectedPairKeys.add(pairKey);\n\t\tselected.push({\n\t\t\tsource: { id: a },\n\t\t\ttarget: { id: b },\n\t\t\tdistance: 0,\n\t\t\tcommonNeighbours: 0,\n\t\t\tscore: 0,\n\t\t});\n\t}\n\n\treturn { pairs: selected.slice(0, config.nPairs) };\n}\n","/**\n * CREST — Community-Revealing Edge Sampling Technique.\n *\n * Selects seed pairs that reveal community structure by computing\n * neighbour overlap ratios. Edges connecting nodes with few shared\n * neighbours relative to their exclusive neighbours indicate\n * community boundaries. Greedy selection with Jaccard diversity\n * ensures structural spread.\n *\n * Blind: uses only local neighbourhood queries.\n * No global statistics, no type metadata, no ground truth required.\n *\n * @packageDocumentation\n */\n\nimport type { ReadableGraph, NodeId } from \"../graph\";\nimport type { Seed } from \"../schemas/index\";\n\n/**\n * Configuration options for CREST seed selection.\n */\nexport interface CrestOptions {\n\t/** Number of seed pairs to select (default: 100) */\n\treadonly nPairs?: number;\n\t/** Random seed for reproducibility (default: 42) */\n\treadonly rngSeed?: number;\n\t/** Jaccard diversity threshold for greedy selection (default: 0.5) */\n\treadonly diversityThreshold?: number;\n\t/** Number of candidate pairs to sample before greedy selection (default: 5000) */\n\treadonly sampleSize?: number;\n}\n\n/**\n * A seed pair selected by CREST with bridge score metadata.\n */\nexport interface CrestSeedPair {\n\t/** Source seed */\n\treadonly source: Seed;\n\t/** Target seed */\n\treadonly target: Seed;\n\t/** Bridge score: ratio of exclusive to shared neighbours */\n\treadonly bridgeScore: number;\n}\n\n/**\n * Result of CREST seed selection.\n */\nexport interface CrestResult {\n\t/** Selected seed pairs */\n\treadonly pairs: readonly CrestSeedPair[];\n}\n\n/** Default configuration values */\nconst DEFAULTS = {\n\tnPairs: 100,\n\trngSeed: 42,\n\tdiversityThreshold: 0.5,\n\tsampleSize: 5000,\n} as const;\n\n/**\n * Simple seeded pseudo-random number generator using mulberry32.\n */\nfunction createRNG(seed: number): () => number {\n\tlet state = seed >>> 0;\n\treturn (): number => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = Math.imul(state ^ (state >>> 15), state | 1);\n\t\tt = (t ^ (t >>> 7)) * (t | 0x61c88647);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/**\n * Compute community-bridge score for a pair of nodes.\n *\n * High score = pair connects different communities.\n * Ratio = exclusive_neighbours / shared_neighbours.\n *\n * Nodes with many shared neighbours are in the same dense community.\n * Nodes with few shared neighbours relative to exclusive ones span communities.\n */\nfunction bridgeScore(\n\taNbrs: Set<NodeId>,\n\tbNbrs: Set<NodeId>,\n\tbId: NodeId,\n\taId: NodeId,\n): number {\n\tconst shared = [...aNbrs].filter((x) => bNbrs.has(x)).length;\n\tconst exclusiveA = [...aNbrs].filter(\n\t\t(x) => !bNbrs.has(x) && x !== bId,\n\t).length;\n\tconst exclusiveB = [...bNbrs].filter(\n\t\t(x) => !aNbrs.has(x) && x !== aId,\n\t).length;\n\tconst exclusive = exclusiveA + exclusiveB;\n\n\tif (shared === 0) return 1.0 / Math.max(exclusive, 1);\n\treturn exclusive / shared;\n}\n\n/**\n * Compute Jaccard similarity between two sets.\n */\nfunction jaccard<T>(a: Set<T>, b: Set<T>): number {\n\tconst intersection = [...a].filter((x) => b.has(x)).length;\n\tconst union = new Set([...a, ...b]).size;\n\treturn union === 0 ? 0 : intersection / union;\n}\n\n/**\n * CREST — Community-Revealing Edge Sampling Technique.\n *\n * Samples random node pairs and scores them by the ratio of exclusive\n * to shared neighbours. Pairs with high ratios connect different\n * communities (few shared neighbours, many exclusive). Greedy\n * selection with Jaccard diversity ensures selected pairs are\n * spread across different structural regions.\n *\n * @param graph - The graph to sample seeds from\n * @param options - Configuration options\n * @returns Selected seed pairs with bridge score metadata\n */\nexport function crest(\n\tgraph: ReadableGraph,\n\toptions: CrestOptions = {},\n): CrestResult {\n\tconst config = { ...DEFAULTS, ...options };\n\tconst rng = createRNG(config.rngSeed);\n\n\tconst allNodes = [...graph.nodeIds()];\n\n\tif (allNodes.length < 2) {\n\t\treturn { pairs: [] };\n\t}\n\n\t// Phase 1: Sample and score candidate pairs\n\tconst candidates: { score: number; a: NodeId; b: NodeId }[] = [];\n\tconst sampledPairs = new Set<string>();\n\n\tconst maxAttempts = config.sampleSize * 10;\n\tlet attempts = 0;\n\n\twhile (sampledPairs.size < config.sampleSize && attempts < maxAttempts) {\n\t\tattempts++;\n\t\tconst a = allNodes[Math.floor(rng() * allNodes.length)];\n\t\tconst b = allNodes[Math.floor(rng() * allNodes.length)];\n\t\tif (a === undefined || b === undefined || a === b) continue;\n\n\t\tconst pairKey = a < b ? `${a}|${b}` : `${b}|${a}`;\n\t\tif (sampledPairs.has(pairKey)) continue;\n\t\tsampledPairs.add(pairKey);\n\n\t\tconst aNbrs = new Set(graph.neighbours(a));\n\t\tconst bNbrs = new Set(graph.neighbours(b));\n\t\tconst score = bridgeScore(aNbrs, bNbrs, b, a);\n\t\tcandidates.push({ score, a, b });\n\t}\n\n\t// Sort by bridge score descending (high = crosses communities)\n\tcandidates.sort((x, y) => y.score - x.score);\n\n\t// Phase 2: Greedy selection with Jaccard diversity\n\tconst selected: CrestSeedPair[] = [];\n\tconst selectedPairKeys = new Set<string>();\n\n\tfor (const { score, a, b } of candidates) {\n\t\tif (selected.length >= config.nPairs) break;\n\n\t\tconst pairKey = a < b ? `${a}|${b}` : `${b}|${a}`;\n\t\tif (selectedPairKeys.has(pairKey)) continue;\n\n\t\tconst aNbrs = new Set(graph.neighbours(a));\n\t\tconst bNbrs = new Set(graph.neighbours(b));\n\n\t\tlet isDiverse = true;\n\t\tfor (const prev of selected) {\n\t\t\tconst paNbrs = new Set(graph.neighbours(prev.source.id));\n\t\t\tif (jaccard(aNbrs, paNbrs) >= config.diversityThreshold) {\n\t\t\t\tconst pbNbrs = new Set(graph.neighbours(prev.target.id));\n\t\t\t\tif (jaccard(bNbrs, pbNbrs) >= config.diversityThreshold) {\n\t\t\t\t\tisDiverse = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!isDiverse) continue;\n\n\t\tselectedPairKeys.add(pairKey);\n\t\tselected.push({\n\t\t\tsource: { id: a },\n\t\t\ttarget: { id: b },\n\t\t\tbridgeScore: score,\n\t\t});\n\t}\n\n\t// Fill shortfall with random pairs\n\tlet fillAttempts = 0;\n\twhile (\n\t\tselected.length < config.nPairs &&\n\t\tallNodes.length >= 2 &&\n\t\tfillAttempts < config.nPairs * 20\n\t) {\n\t\tfillAttempts++;\n\t\tconst i1 = Math.floor(rng() * allNodes.length);\n\t\tconst i2 = Math.floor(rng() * allNodes.length);\n\t\tconst a = allNodes[i1];\n\t\tconst b = allNodes[i2];\n\t\tif (a === undefined || b === undefined || a === b) continue;\n\n\t\tconst pairKey = a < b ? `${a}|${b}` : `${b}|${a}`;\n\t\tif (selectedPairKeys.has(pairKey)) continue;\n\n\t\tselectedPairKeys.add(pairKey);\n\t\tselected.push({\n\t\t\tsource: { id: a },\n\t\t\ttarget: { id: b },\n\t\t\tbridgeScore: 0,\n\t\t});\n\t}\n\n\treturn { pairs: selected.slice(0, config.nPairs) };\n}\n","/**\n * GRASP — Graph-agnostic Representative Seed pAir Sampling.\n *\n * Novel blind structural seed selection algorithm that selects structurally\n * representative seed pairs without requiring domain knowledge or loading\n * the full graph into memory.\n *\n * Three phases:\n * 1. Reservoir sampling — stream edges, maintain reservoir of N nodes\n * 2. Structural feature computation — log-degree, clustering coeff, approx PageRank\n * 3. Mini-batch K-means clustering, then sample pairs within and across clusters\n *\n * @packageDocumentation\n */\n\nimport type { ReadableGraph, NodeId } from \"../graph\";\nimport type { Seed } from \"../schemas/index\";\nimport {\n\tminiBatchKMeans,\n\tzScoreNormalise,\n\ttype LabelledFeature,\n\ttype FeatureVector3D,\n} from \"../utils/kmeans\";\n\n/**\n * Configuration options for GRASP seed selection.\n */\nexport interface GraspOptions {\n\t/** Number of clusters for K-means (default: 100) */\n\treadonly nClusters?: number;\n\t/** Number of pairs to sample per cluster (default: 10) */\n\treadonly pairsPerCluster?: number;\n\t/** Ratio of within-cluster pairs vs cross-cluster pairs (default: 0.5) */\n\treadonly withinClusterRatio?: number;\n\t/** Reservoir sample size (default: 200000) */\n\treadonly sampleSize?: number;\n\t/** Random seed for reproducibility (default: 42) */\n\treadonly rngSeed?: number;\n\t/** Number of PageRank iterations for feature computation (default: 10) */\n\treadonly pagerankIterations?: number;\n}\n\n/**\n * A sampled seed pair with structural metadata.\n */\nexport interface GraspSeedPair {\n\t/** Source seed */\n\treadonly source: Seed;\n\t/** Target seed */\n\treadonly target: Seed;\n\t/** Euclidean distance in feature space */\n\treadonly featureDistance: number;\n\t/** Whether both seeds are from the same cluster */\n\treadonly sameCluster: boolean;\n\t/** Cluster index of source (or -1 if unclustered) */\n\treadonly sourceCluster: number;\n\t/** Cluster index of target (or -1 if unclustered) */\n\treadonly targetCluster: number;\n}\n\n/**\n * Result of GRASP seed selection.\n */\nexport interface GraspResult {\n\t/** Sampled seed pairs */\n\treadonly pairs: readonly GraspSeedPair[];\n\t/** Number of clusters used */\n\treadonly nClusters: number;\n\t/** Total nodes sampled */\n\treadonly sampledNodeCount: number;\n\t/** Features computed for sampled nodes */\n\treadonly features: readonly LabelledFeature[];\n\t/** Cluster assignments (nodeId -> cluster index) */\n\treadonly clusterAssignments: ReadonlyMap<string, number>;\n}\n\n/** Default configuration values */\nconst DEFAULTS = {\n\tnClusters: 100,\n\tpairsPerCluster: 10,\n\twithinClusterRatio: 0.5,\n\tsampleSize: 200000,\n\trngSeed: 42,\n\tpagerankIterations: 10,\n} as const;\n\n/**\n * Simple seeded pseudo-random number generator using mulberry32.\n */\nfunction createRNG(seed: number): () => number {\n\tlet state = seed >>> 0;\n\treturn (): number => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = Math.imul(state ^ (state >>> 15), state | 1);\n\t\tt = (t ^ (t >>> 7)) * (t | 0x61c88647);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/**\n * Reservoir sampling (Vitter's Algorithm R) for streaming node selection.\n *\n * Maintains a uniform sample of nodes as edges are streamed, without\n * requiring the full graph in memory.\n */\nfunction reservoirSample(\n\tgraph: ReadableGraph,\n\tsampleSize: number,\n\trng: () => number,\n): { nodeIds: Set<NodeId>; neighbourMap: Map<NodeId, Set<NodeId>> } {\n\tconst reservoir: NodeId[] = [];\n\tconst neighbourMap = new Map<NodeId, Set<NodeId>>();\n\tconst inReservoir = new Set<NodeId>();\n\n\t// Track total nodes seen for reservoir probability\n\tlet nodesSeen = 0;\n\n\t// Stream all edges and sample nodes\n\tfor (const edge of graph.edges()) {\n\t\t// Process source node\n\t\tconst source = edge.source;\n\t\tif (!inReservoir.has(source)) {\n\t\t\tnodesSeen++;\n\t\t\tif (reservoir.length < sampleSize) {\n\t\t\t\treservoir.push(source);\n\t\t\t\tinReservoir.add(source);\n\t\t\t\tneighbourMap.set(source, new Set<NodeId>());\n\t\t\t} else {\n\t\t\t\t// Reservoir sampling: replace with probability sampleSize/nodesSeen\n\t\t\t\tconst j = Math.floor(rng() * nodesSeen);\n\t\t\t\tif (j < sampleSize) {\n\t\t\t\t\tconst oldNode = reservoir[j];\n\t\t\t\t\tif (oldNode !== undefined) {\n\t\t\t\t\t\tinReservoir.delete(oldNode);\n\t\t\t\t\t\tneighbourMap.delete(oldNode);\n\t\t\t\t\t}\n\t\t\t\t\treservoir[j] = source;\n\t\t\t\t\tinReservoir.add(source);\n\t\t\t\t\tneighbourMap.set(source, new Set<NodeId>());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Process target node\n\t\tconst target = edge.target;\n\t\tif (!inReservoir.has(target)) {\n\t\t\tnodesSeen++;\n\t\t\tif (reservoir.length < sampleSize) {\n\t\t\t\treservoir.push(target);\n\t\t\t\tinReservoir.add(target);\n\t\t\t\tneighbourMap.set(target, new Set<NodeId>());\n\t\t\t} else {\n\t\t\t\tconst j = Math.floor(rng() * nodesSeen);\n\t\t\t\tif (j < sampleSize) {\n\t\t\t\t\tconst oldNode = reservoir[j];\n\t\t\t\t\tif (oldNode !== undefined) {\n\t\t\t\t\t\tinReservoir.delete(oldNode);\n\t\t\t\t\t\tneighbourMap.delete(oldNode);\n\t\t\t\t\t}\n\t\t\t\t\treservoir[j] = target;\n\t\t\t\t\tinReservoir.add(target);\n\t\t\t\t\tneighbourMap.set(target, new Set<NodeId>());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Store neighbour relationships for sampled nodes\n\t\tif (inReservoir.has(source) && inReservoir.has(target)) {\n\t\t\tconst sourceNeighbours = neighbourMap.get(source);\n\t\t\tconst targetNeighbours = neighbourMap.get(target);\n\t\t\tsourceNeighbours?.add(target);\n\t\t\ttargetNeighbours?.add(source);\n\t\t}\n\t}\n\n\treturn { nodeIds: inReservoir, neighbourMap };\n}\n\n/**\n * Compute approximate PageRank scores using power iteration on the reservoir subgraph.\n *\n * This is an approximation since it only considers the sampled nodes and their\n * connections within the reservoir, not the full graph.\n */\nfunction approximatePageRank(\n\tnodeIds: Set<NodeId>,\n\tneighbourMap: Map<NodeId, Set<NodeId>>,\n\titerations: number,\n\tdampingFactor = 0.85,\n): Map<NodeId, number> {\n\tconst n = nodeIds.size;\n\tif (n === 0) return new Map();\n\n\tconst nodeIdList = [...nodeIds];\n\tconst nodeIndex = new Map(nodeIdList.map((id, i) => [id, i] as const));\n\n\t// Initialise PageRank scores uniformly\n\tconst scores = new Float64Array(n).fill(1 / n);\n\tconst newScores = new Float64Array(n);\n\n\t// Power iteration\n\tfor (let iter = 0; iter < iterations; iter++) {\n\t\tnewScores.fill((1 - dampingFactor) / n);\n\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst nodeId = nodeIdList[i];\n\t\t\tif (nodeId === undefined) continue;\n\n\t\t\tconst neighbours = neighbourMap.get(nodeId);\n\t\t\tif (neighbours === undefined) continue;\n\n\t\t\tconst outDegree = neighbours.size;\n\t\t\tif (outDegree === 0) continue;\n\n\t\t\tconst contribution = (dampingFactor * (scores[i] ?? 0)) / outDegree;\n\n\t\t\tfor (const neighbour of neighbours) {\n\t\t\t\tconst neighbourIdx = nodeIndex.get(neighbour);\n\t\t\t\tif (neighbourIdx !== undefined) {\n\t\t\t\t\tnewScores[neighbourIdx] =\n\t\t\t\t\t\t(newScores[neighbourIdx] ?? 0) + contribution;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Swap buffers\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tscores[i] = newScores[i] ?? 0;\n\t\t}\n\t}\n\n\t// Build result map\n\tconst result = new Map<NodeId, number>();\n\tfor (let i = 0; i < n; i++) {\n\t\tconst nodeId = nodeIdList[i];\n\t\tconst score = scores[i];\n\t\tif (nodeId !== undefined && score !== undefined) {\n\t\t\tresult.set(nodeId, score);\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Compute structural features for sampled nodes.\n *\n * Features:\n * - f1: log(deg(v) + 1) — scale-normalised connectivity\n * - f2: clustering_coefficient(v) — local density\n * - f3: approx_pagerank(v) — positional importance\n */\nfunction computeFeatures(\n\tgraph: ReadableGraph,\n\tnodeIds: Set<NodeId>,\n\tneighbourMap: Map<NodeId, Set<NodeId>>,\n\tpagerankScores: Map<NodeId, number>,\n): LabelledFeature[] {\n\tconst features: LabelledFeature[] = [];\n\n\tfor (const nodeId of nodeIds) {\n\t\tconst degree = graph.degree(nodeId, \"both\");\n\t\tconst neighbours = neighbourMap.get(nodeId);\n\n\t\t// Compute local clustering coefficient using neighbour map\n\t\tlet clusteringCoef = 0;\n\t\tif (neighbours !== undefined && neighbours.size >= 2) {\n\t\t\tlet triangleCount = 0;\n\t\t\tconst neighbourList = [...neighbours];\n\n\t\t\tfor (let i = 0; i < neighbourList.length; i++) {\n\t\t\t\tfor (let j = i + 1; j < neighbourList.length; j++) {\n\t\t\t\t\tconst u = neighbourList[i];\n\t\t\t\t\tconst w = neighbourList[j];\n\t\t\t\t\tif (u !== undefined && w !== undefined) {\n\t\t\t\t\t\t// Check if u and w are connected\n\t\t\t\t\t\tconst uNeighbours = neighbourMap.get(u);\n\t\t\t\t\t\tif (uNeighbours?.has(w) === true) {\n\t\t\t\t\t\t\ttriangleCount++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst possibleTriangles = (degree * (degree - 1)) / 2;\n\t\t\tclusteringCoef = triangleCount / possibleTriangles;\n\t\t}\n\n\t\tconst pagerank = pagerankScores.get(nodeId) ?? 0;\n\n\t\tfeatures.push({\n\t\t\tnodeId,\n\t\t\tf1: Math.log(degree + 1),\n\t\t\tf2: clusteringCoef,\n\t\t\tf3: pagerank,\n\t\t});\n\t}\n\n\treturn features;\n}\n\n/**\n * Sample seed pairs from clusters.\n *\n * For each cluster, samples a mix of within-cluster and cross-cluster pairs.\n */\nfunction samplePairs(\n\tfeatures: readonly LabelledFeature[],\n\tclusterAssignments: ReadonlyMap<string, number>,\n\tnClusters: number,\n\tpairsPerCluster: number,\n\twithinClusterRatio: number,\n\trng: () => number,\n): GraspSeedPair[] {\n\tconst pairs: GraspSeedPair[] = [];\n\n\t// Group nodes by cluster\n\tconst clusterNodes = new Map<number, LabelledFeature[]>();\n\tfor (const feature of features) {\n\t\tconst cluster = clusterAssignments.get(feature.nodeId);\n\t\tif (cluster === undefined) continue;\n\n\t\tlet nodes = clusterNodes.get(cluster);\n\t\tif (nodes === undefined) {\n\t\t\tnodes = [];\n\t\t\tclusterNodes.set(cluster, nodes);\n\t\t}\n\t\tnodes.push(feature);\n\t}\n\n\tconst withinCount = Math.floor(pairsPerCluster * withinClusterRatio);\n\tconst crossCount = pairsPerCluster - withinCount;\n\n\t// Sample pairs for each cluster\n\tfor (let clusterIdx = 0; clusterIdx < nClusters; clusterIdx++) {\n\t\tconst nodes = clusterNodes.get(clusterIdx);\n\t\tif (nodes === undefined || nodes.length < 2) continue;\n\n\t\t// Within-cluster pairs\n\t\tfor (let i = 0; i < withinCount; i++) {\n\t\t\t// Sample two distinct nodes\n\t\t\tconst idx1 = Math.floor(rng() * nodes.length);\n\t\t\tlet idx2 = Math.floor(rng() * nodes.length);\n\t\t\twhile (idx1 === idx2) {\n\t\t\t\tidx2 = Math.floor(rng() * nodes.length);\n\t\t\t}\n\n\t\t\tconst source = nodes[idx1];\n\t\t\tconst target = nodes[idx2];\n\t\t\tif (source === undefined || target === undefined) continue;\n\n\t\t\tconst distance = computeFeatureDistance(source, target);\n\n\t\t\tpairs.push({\n\t\t\t\tsource: { id: source.nodeId },\n\t\t\t\ttarget: { id: target.nodeId },\n\t\t\t\tfeatureDistance: distance,\n\t\t\t\tsameCluster: true,\n\t\t\t\tsourceCluster: clusterIdx,\n\t\t\t\ttargetCluster: clusterIdx,\n\t\t\t});\n\t\t}\n\n\t\t// Cross-cluster pairs\n\t\tfor (let i = 0; i < crossCount; i++) {\n\t\t\tconst source = nodes[Math.floor(rng() * nodes.length)];\n\t\t\tif (source === undefined) continue;\n\n\t\t\t// Pick a random other cluster\n\t\t\tconst otherClusterIdx = Math.floor(rng() * nClusters);\n\t\t\tif (otherClusterIdx === clusterIdx) continue;\n\n\t\t\tconst otherNodes = clusterNodes.get(otherClusterIdx);\n\t\t\tif (otherNodes === undefined || otherNodes.length === 0) continue;\n\n\t\t\tconst target = otherNodes[Math.floor(rng() * otherNodes.length)];\n\t\t\tif (target === undefined) continue;\n\n\t\t\tconst distance = computeFeatureDistance(source, target);\n\n\t\t\tpairs.push({\n\t\t\t\tsource: { id: source.nodeId },\n\t\t\t\ttarget: { id: target.nodeId },\n\t\t\t\tfeatureDistance: distance,\n\t\t\t\tsameCluster: false,\n\t\t\t\tsourceCluster: clusterIdx,\n\t\t\t\ttargetCluster: otherClusterIdx,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn pairs;\n}\n\n/**\n * Compute Euclidean distance between two feature vectors.\n */\nfunction computeFeatureDistance(\n\ta: FeatureVector3D,\n\tb: FeatureVector3D,\n): number {\n\tconst d1 = a.f1 - b.f1;\n\tconst d2 = a.f2 - b.f2;\n\tconst d3 = a.f3 - b.f3;\n\treturn Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3);\n}\n\n/**\n * GRASP — Graph-agnostic Representative Seed pAir Sampling.\n *\n * Selects structurally representative seed pairs without domain knowledge.\n * The algorithm streams edges, samples nodes via reservoir sampling, computes\n * structural features, clusters nodes, and samples pairs within/across clusters.\n *\n * @param graph - The graph to sample seeds from\n * @param options - Configuration options\n * @returns Sampled seed pairs with structural metadata\n *\n * @example\n * ```typescript\n * const graph = new AdjacencyMapGraph();\n * // ... populate graph ...\n *\n * const result = grasp(graph, {\n * nClusters: 50,\n * pairsPerCluster: 20,\n * sampleSize: 100000,\n * });\n *\n * console.log(`Sampled ${result.pairs.length} pairs from ${result.sampledNodeCount} nodes`);\n * ```\n */\nexport function grasp(\n\tgraph: ReadableGraph,\n\toptions: GraspOptions = {},\n): GraspResult {\n\tconst config = {\n\t\t...DEFAULTS,\n\t\t...options,\n\t};\n\n\tconst rng = createRNG(config.rngSeed);\n\n\t// Phase 1: Reservoir sampling\n\tconst { nodeIds, neighbourMap } = reservoirSample(\n\t\tgraph,\n\t\tconfig.sampleSize,\n\t\trng,\n\t);\n\n\t// Phase 2: Approximate PageRank on reservoir subgraph\n\tconst pagerankScores = approximatePageRank(\n\t\tnodeIds,\n\t\tneighbourMap,\n\t\tconfig.pagerankIterations,\n\t);\n\n\t// Phase 2: Compute structural features\n\tlet features = computeFeatures(graph, nodeIds, neighbourMap, pagerankScores);\n\n\t// Normalise features\n\tif (features.length > 0) {\n\t\tfeatures = zScoreNormalise(features);\n\t}\n\n\t// Phase 3: K-means clustering\n\tconst k = Math.min(config.nClusters, features.length);\n\tconst kmeansResult = miniBatchKMeans(features, {\n\t\tk,\n\t\tseed: config.rngSeed,\n\t\tmaxIterations: 100,\n\t});\n\n\t// Phase 3: Sample pairs\n\tconst pairs = samplePairs(\n\t\tfeatures,\n\t\tkmeansResult.assignments,\n\t\tkmeansResult.k,\n\t\tconfig.pairsPerCluster,\n\t\tconfig.withinClusterRatio,\n\t\trng,\n\t);\n\n\treturn {\n\t\tpairs,\n\t\tnClusters: kmeansResult.k,\n\t\tsampledNodeCount: nodeIds.size,\n\t\tfeatures,\n\t\tclusterAssignments: kmeansResult.assignments,\n\t};\n}\n","/**\n * SPINE — Structural Position-Informed Node Extraction.\n *\n * Selects seed pairs using 2-hop degree distribution skewness. Nodes whose\n * 2-hop neighbourhood has skewed degree distributions sit at structurally\n * heterogeneous positions (diverse local topology). Pairs are selected by\n * matching nodes with high skewness (diverse positions) against nodes\n * with low skewness (uniform positions), ensuring exploration spans\n * structurally varied terrain.\n *\n * Blind: uses only local neighbourhood queries.\n * No global statistics, no type metadata, no ground truth required.\n *\n * @packageDocumentation\n */\n\nimport type { ReadableGraph, NodeId } from \"../graph\";\nimport type { Seed } from \"../schemas/index\";\n\n/**\n * Configuration options for SPINE seed selection.\n */\nexport interface SpineOptions {\n\t/** Number of seed pairs to select (default: 100) */\n\treadonly nPairs?: number;\n\t/** Random seed for reproducibility (default: 42) */\n\treadonly rngSeed?: number;\n\t/** Jaccard diversity threshold for greedy selection (default: 0.5) */\n\treadonly diversityThreshold?: number;\n}\n\n/**\n * A seed pair selected by SPINE with skewness metadata.\n */\nexport interface SpineSeedPair {\n\t/** Source seed */\n\treadonly source: Seed;\n\t/** Target seed */\n\treadonly target: Seed;\n\t/** Skewness of source node's 2-hop degree distribution */\n\treadonly sourceSkewness: number;\n\t/** Skewness of target node's 2-hop degree distribution */\n\treadonly targetSkewness: number;\n}\n\n/**\n * Result of SPINE seed selection.\n */\nexport interface SpineResult {\n\t/** Selected seed pairs */\n\treadonly pairs: readonly SpineSeedPair[];\n\t/** Skewness scores for all nodes */\n\treadonly skewness: ReadonlyMap<string, number>;\n}\n\n/** Default configuration values */\nconst DEFAULTS = {\n\tnPairs: 100,\n\trngSeed: 42,\n\tdiversityThreshold: 0.5,\n} as const;\n\n/**\n * Simple seeded pseudo-random number generator using mulberry32.\n */\nfunction createRNG(seed: number): () => number {\n\tlet state = seed >>> 0;\n\treturn (): number => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = Math.imul(state ^ (state >>> 15), state | 1);\n\t\tt = (t ^ (t >>> 7)) * (t | 0x61c88647);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/**\n * Compute skewness of the 2-hop degree distribution for a node.\n *\n * For each neighbour u of node, collect the degree of u.\n * Skewness = E[(X - μ)³] / σ³ where X is the degree distribution.\n *\n * High skewness = neighbour degrees are heavily concentrated at one end.\n * Low skewness = neighbour degrees are relatively uniform.\n *\n * Returns 0.0 for nodes with fewer than 3 neighbours.\n */\nfunction degreeSkewness(graph: ReadableGraph, node: NodeId): number {\n\tconst neighbours = [...graph.neighbours(node)];\n\tif (neighbours.length < 3) return 0;\n\n\t// Collect degrees of neighbours (2-hop degree distribution)\n\tconst degrees = neighbours.map((n) => graph.degree(n, \"both\"));\n\tconst n = degrees.length;\n\tconst mean = degrees.reduce((s, d) => s + d, 0) / n;\n\tconst variance = degrees.reduce((s, d) => s + (d - mean) ** 2, 0) / n;\n\n\tif (variance < 1e-10) return 0;\n\n\tconst std = Math.sqrt(variance);\n\tconst moment3 = degrees.reduce((s, d) => s + (d - mean) ** 3, 0) / n;\n\treturn moment3 / std ** 3;\n}\n\n/**\n * Compute Jaccard similarity between two sets.\n */\nfunction jaccard<T>(a: Set<T>, b: Set<T>): number {\n\tconst intersection = [...a].filter((x) => b.has(x)).length;\n\tconst union = new Set([...a, ...b]).size;\n\treturn union === 0 ? 0 : intersection / union;\n}\n\n/**\n * SPINE — Structural Position-Informed Node Extraction.\n *\n * Computes 2-hop degree distribution skewness for each node. Nodes with\n * high positive skewness have structurally diverse neighbours (hub-periphery\n * mix), while nodes with low skewness have uniform neighbours. Pairs\n * connecting high-skewness and low-skewness nodes explore structurally\n * varied terrain.\n *\n * @param graph - The graph to sample seeds from\n * @param options - Configuration options\n * @returns Selected seed pairs with skewness metadata\n */\nexport function spine(\n\tgraph: ReadableGraph,\n\toptions: SpineOptions = {},\n): SpineResult {\n\tconst config = { ...DEFAULTS, ...options };\n\tconst rng = createRNG(config.rngSeed);\n\n\tconst allNodes = [...graph.nodeIds()];\n\n\tif (allNodes.length < 2) {\n\t\treturn { pairs: [], skewness: new Map() };\n\t}\n\n\t// Phase 1: Compute skewness for all nodes\n\tconst skewnessMap = new Map<NodeId, number>();\n\tfor (const node of allNodes) {\n\t\tskewnessMap.set(node, degreeSkewness(graph, node));\n\t}\n\n\t// Phase 2: Categorise by skewness terciles\n\tconst sortedNodes = [...allNodes].sort(\n\t\t(a, b) => (skewnessMap.get(a) ?? 0) - (skewnessMap.get(b) ?? 0),\n\t);\n\tconst n = sortedNodes.length;\n\n\tconst lowSkew = sortedNodes.slice(0, Math.floor(n / 3));\n\tconst midSkew = sortedNodes.slice(Math.floor(n / 3), Math.floor((2 * n) / 3));\n\tconst highSkew = sortedNodes.slice(Math.floor((2 * n) / 3));\n\n\t// Phase 3: Generate candidate pairs (cross-skewness preferred)\n\tconst candidates: { score: number; a: NodeId; b: NodeId }[] = [];\n\tconst sampleSize = Math.max(config.nPairs * 20, 200);\n\n\t// High-low pairs (most diverse signal)\n\tfor (let i = 0; i < sampleSize; i++) {\n\t\tif (!highSkew.length || !lowSkew.length) break;\n\t\tconst a = highSkew[Math.floor(rng() * highSkew.length)];\n\t\tconst b = lowSkew[Math.floor(rng() * lowSkew.length)];\n\t\tif (a === undefined || b === undefined || a === b) continue;\n\t\tconst skA = skewnessMap.get(a) ?? 0;\n\t\tconst skB = skewnessMap.get(b) ?? 0;\n\t\tcandidates.push({ score: Math.abs(skA - skB), a, b });\n\t}\n\n\t// High-mid and mid-low pairs\n\tconst halfSample = Math.floor(sampleSize / 2);\n\tfor (let i = 0; i < halfSample; i++) {\n\t\tif (midSkew.length && highSkew.length) {\n\t\t\tconst a = highSkew[Math.floor(rng() * highSkew.length)];\n\t\t\tconst b = midSkew[Math.floor(rng() * midSkew.length)];\n\t\t\tif (a !== undefined && b !== undefined && a !== b) {\n\t\t\t\tconst skA = skewnessMap.get(a) ?? 0;\n\t\t\t\tconst skB = skewnessMap.get(b) ?? 0;\n\t\t\t\tcandidates.push({ score: Math.abs(skA - skB) * 0.8, a, b });\n\t\t\t}\n\t\t}\n\t\tif (midSkew.length && lowSkew.length) {\n\t\t\tconst a = midSkew[Math.floor(rng() * midSkew.length)];\n\t\t\tconst b = lowSkew[Math.floor(rng() * lowSkew.length)];\n\t\t\tif (a !== undefined && b !== undefined && a !== b) {\n\t\t\t\tconst skA = skewnessMap.get(a) ?? 0;\n\t\t\t\tconst skB = skewnessMap.get(b) ?? 0;\n\t\t\t\tcandidates.push({ score: Math.abs(skA - skB) * 0.8, a, b });\n\t\t\t}\n\t\t}\n\t}\n\n\t// Same-category pairs for within-structure coverage\n\tconst quarterSample = Math.floor(sampleSize / 4);\n\tfor (let i = 0; i < quarterSample; i++) {\n\t\tif (highSkew.length >= 2) {\n\t\t\tconst i1 = Math.floor(rng() * highSkew.length);\n\t\t\tlet i2 = Math.floor(rng() * highSkew.length);\n\t\t\twhile (i1 === i2) i2 = Math.floor(rng() * highSkew.length);\n\t\t\tconst a = highSkew[i1];\n\t\t\tconst b = highSkew[i2];\n\t\t\tif (a !== undefined && b !== undefined) {\n\t\t\t\tconst skA = skewnessMap.get(a) ?? 0;\n\t\t\t\tconst skB = skewnessMap.get(b) ?? 0;\n\t\t\t\tcandidates.push({ score: Math.abs(skA - skB) * 0.5, a, b });\n\t\t\t}\n\t\t}\n\t}\n\n\tcandidates.sort((x, y) => y.score - x.score);\n\n\t// Phase 4: Greedy selection with Jaccard diversity\n\tconst selected: SpineSeedPair[] = [];\n\tconst selectedPairKeys = new Set<string>();\n\n\tfor (const { a, b } of candidates) {\n\t\tif (selected.length >= config.nPairs) break;\n\n\t\tconst pairKey = a < b ? `${a}|${b}` : `${b}|${a}`;\n\t\tif (selectedPairKeys.has(pairKey)) continue;\n\n\t\tconst aNbrs = new Set(graph.neighbours(a));\n\t\tconst bNbrs = new Set(graph.neighbours(b));\n\n\t\tlet isDiverse = true;\n\t\tfor (const prev of selected) {\n\t\t\tconst paNbrs = new Set(graph.neighbours(prev.source.id));\n\t\t\tif (jaccard(aNbrs, paNbrs) >= config.diversityThreshold) {\n\t\t\t\tconst pbNbrs = new Set(graph.neighbours(prev.target.id));\n\t\t\t\tif (jaccard(bNbrs, pbNbrs) >= config.diversityThreshold) {\n\t\t\t\t\tisDiverse = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!isDiverse) continue;\n\n\t\tselectedPairKeys.add(pairKey);\n\t\tselected.push({\n\t\t\tsource: { id: a },\n\t\t\ttarget: { id: b },\n\t\t\tsourceSkewness: skewnessMap.get(a) ?? 0,\n\t\t\ttargetSkewness: skewnessMap.get(b) ?? 0,\n\t\t});\n\t}\n\n\t// Fill shortfall\n\tlet fillAttempts = 0;\n\twhile (\n\t\tselected.length < config.nPairs &&\n\t\tallNodes.length >= 2 &&\n\t\tfillAttempts < config.nPairs * 20\n\t) {\n\t\tfillAttempts++;\n\t\tconst i1 = Math.floor(rng() * allNodes.length);\n\t\tconst i2 = Math.floor(rng() * allNodes.length);\n\t\tconst a = allNodes[i1];\n\t\tconst b = allNodes[i2];\n\t\tif (a === undefined || b === undefined || a === b) continue;\n\n\t\tconst pairKey = a < b ? `${a}|${b}` : `${b}|${a}`;\n\t\tif (selectedPairKeys.has(pairKey)) continue;\n\n\t\tselectedPairKeys.add(pairKey);\n\t\tselected.push({\n\t\t\tsource: { id: a },\n\t\t\ttarget: { id: b },\n\t\t\tsourceSkewness: skewnessMap.get(a) ?? 0,\n\t\t\ttargetSkewness: skewnessMap.get(b) ?? 0,\n\t\t});\n\t}\n\n\treturn {\n\t\tpairs: selected.slice(0, config.nPairs),\n\t\tskewness: skewnessMap,\n\t};\n}\n","/**\n * STRIDE — Shortest-TRIangle Diversity seed selection.\n *\n * Selects diverse seed pairs using local triad (closed 3-cycle) counting.\n * Nodes are categorised by triad density: core (high), periphery (low),\n * bridge (medium). Pairs spanning different categories capture structural\n * diversity.\n *\n * Blind: uses only local neighbourhood queries (O(d²) per node).\n * No global statistics, no type metadata, no ground truth required.\n *\n * @packageDocumentation\n */\n\nimport type { ReadableGraph, NodeId } from \"../graph\";\nimport type { Seed } from \"../schemas/index\";\n\n/**\n * Configuration options for STRIDE seed selection.\n */\nexport interface StrideOptions {\n\t/** Number of seed pairs to select (default: 100) */\n\treadonly nPairs?: number;\n\t/** Random seed for reproducibility (default: 42) */\n\treadonly rngSeed?: number;\n\t/** Jaccard diversity threshold for greedy selection (default: 0.5) */\n\treadonly diversityThreshold?: number;\n}\n\n/**\n * A seed pair selected by STRIDE with triad metadata.\n */\nexport interface StrideSeedPair {\n\t/** Source seed */\n\treadonly source: Seed;\n\t/** Target seed */\n\treadonly target: Seed;\n\t/** Triad count of source node */\n\treadonly sourceTriads: number;\n\t/** Triad count of target node */\n\treadonly targetTriads: number;\n\t/** Category of source: \"core\" | \"bridge\" | \"periphery\" */\n\treadonly sourceCategory: string;\n\t/** Category of target: \"core\" | \"bridge\" | \"periphery\" */\n\treadonly targetCategory: string;\n}\n\n/**\n * Result of STRIDE seed selection.\n */\nexport interface StrideResult {\n\t/** Selected seed pairs */\n\treadonly pairs: readonly StrideSeedPair[];\n\t/** Triad counts for all nodes */\n\treadonly triadCounts: ReadonlyMap<string, number>;\n\t/** Category assignments */\n\treadonly categories: ReadonlyMap<string, string>;\n}\n\n/** Default configuration values */\nconst DEFAULTS = {\n\tnPairs: 100,\n\trngSeed: 42,\n\tdiversityThreshold: 0.5,\n} as const;\n\n/**\n * Simple seeded pseudo-random number generator using mulberry32.\n */\nfunction createRNG(seed: number): () => number {\n\tlet state = seed >>> 0;\n\treturn (): number => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = Math.imul(state ^ (state >>> 15), state | 1);\n\t\tt = (t ^ (t >>> 7)) * (t | 0x61c88647);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/**\n * Count closed triads (3-cycles) involving a node.\n *\n * A triad is a triple (node, u, v) where u and v are both neighbours\n * of node AND u-v is an edge.\n */\nfunction countTriads(graph: ReadableGraph, node: NodeId): number {\n\tconst neighbours = [...graph.neighbours(node)];\n\tif (neighbours.length < 2) return 0;\n\n\tconst neighbourSet = new Set(neighbours);\n\tlet count = 0;\n\n\tfor (let i = 0; i < neighbours.length; i++) {\n\t\tfor (let j = i + 1; j < neighbours.length; j++) {\n\t\t\tconst u = neighbours[i];\n\t\t\tconst v = neighbours[j];\n\t\t\tif (u !== undefined && v !== undefined) {\n\t\t\t\tconst uNeighbours = new Set(graph.neighbours(u));\n\t\t\t\tif (uNeighbours.has(v) && neighbourSet.has(v)) {\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn count;\n}\n\n/**\n * Classify a node by triad count into core/bridge/periphery.\n */\nfunction triadCategory(triadCount: number, p33: number, p66: number): string {\n\tif (triadCount <= p33) return \"periphery\";\n\tif (triadCount <= p66) return \"bridge\";\n\treturn \"core\";\n}\n\n/**\n * Compute Jaccard similarity between two sets.\n */\nfunction jaccard<T>(a: Set<T>, b: Set<T>): number {\n\tconst intersection = [...a].filter((x) => b.has(x)).length;\n\tconst union = new Set([...a, ...b]).size;\n\treturn union === 0 ? 0 : intersection / union;\n}\n\n/**\n * STRIDE — Shortest-TRIangle Diversity seed selection.\n *\n * Nodes are categorised by local triad count into core, bridge, and\n * periphery. Pairs spanning different categories capture structural\n * diversity: core-periphery pairs traverse community interiors to\n * boundaries, bridge-bridge pairs span community gaps.\n *\n * @param graph - The graph to sample seeds from\n * @param options - Configuration options\n * @returns Selected seed pairs with triad metadata\n */\nexport function stride(\n\tgraph: ReadableGraph,\n\toptions: StrideOptions = {},\n): StrideResult {\n\tconst config = { ...DEFAULTS, ...options };\n\tconst rng = createRNG(config.rngSeed);\n\n\tconst allNodes = [...graph.nodeIds()];\n\n\tif (allNodes.length < 2) {\n\t\treturn { pairs: [], triadCounts: new Map(), categories: new Map() };\n\t}\n\n\t// Phase 1: Compute triad counts\n\tconst triadCounts = new Map<NodeId, number>();\n\tfor (const node of allNodes) {\n\t\ttriadCounts.set(node, countTriads(graph, node));\n\t}\n\n\t// Phase 2: Compute tercile thresholds\n\tconst countsSorted = [...triadCounts.values()].sort((a, b) => a - b);\n\tconst n = countsSorted.length;\n\tconst p33 = countsSorted[Math.floor(n / 3)] ?? 0;\n\tconst p66 = countsSorted[Math.floor((2 * n) / 3)] ?? 0;\n\n\t// Phase 3: Categorise nodes\n\tconst categories = new Map<NodeId, string>();\n\tconst categoryGroups = new Map<string, NodeId[]>();\n\n\tfor (const [node, tc] of triadCounts) {\n\t\tconst cat = triadCategory(tc, p33, p66);\n\t\tcategories.set(node, cat);\n\t\tlet group = categoryGroups.get(cat);\n\t\tif (group === undefined) {\n\t\t\tgroup = [];\n\t\t\tcategoryGroups.set(cat, group);\n\t\t}\n\t\tgroup.push(node);\n\t}\n\n\t// Phase 4: Generate cross-category candidate pairs\n\tconst catNames = [\"core\", \"bridge\", \"periphery\"] as const;\n\tconst candidates: { score: number; a: NodeId; b: NodeId }[] = [];\n\n\tfor (const catA of catNames) {\n\t\tfor (const catB of catNames) {\n\t\t\tconst groupA = categoryGroups.get(catA);\n\t\t\tconst groupB = categoryGroups.get(catB);\n\t\t\tif (groupA === undefined || groupB === undefined) continue;\n\t\t\tconst aLen = groupA.length;\n\t\t\tconst bLen = groupB.length;\n\t\t\tif (aLen === 0 || bLen === 0) continue;\n\n\t\t\tconst crossBonus = catA === catB ? 0 : 1;\n\t\t\tconst sampleSize = Math.max(config.nPairs * 3, 30);\n\n\t\t\tfor (let s = 0; s < sampleSize; s++) {\n\t\t\t\tconst a = groupA[Math.floor(rng() * groupA.length)];\n\t\t\t\tconst b =\n\t\t\t\t\tcatA === catB\n\t\t\t\t\t\t? groupA[Math.floor(rng() * groupA.length)]\n\t\t\t\t\t\t: groupB[Math.floor(rng() * groupB.length)];\n\n\t\t\t\tif (a === undefined || b === undefined || a === b) continue;\n\n\t\t\t\tconst tcA = triadCounts.get(a) ?? 0;\n\t\t\t\tconst tcB = triadCounts.get(b) ?? 0;\n\t\t\t\tconst contrast = Math.abs(tcA - tcB);\n\t\t\t\tconst score = contrast + crossBonus * Math.max(tcA, tcB, 1);\n\n\t\t\t\tcandidates.push({ score, a, b });\n\t\t\t}\n\t\t}\n\t}\n\n\tcandidates.sort((x, y) => y.score - x.score);\n\n\t// Phase 5: Greedy selection with Jaccard diversity\n\tconst selected: StrideSeedPair[] = [];\n\tconst selectedPairKeys = new Set<string>();\n\n\tfor (const candidate of candidates) {\n\t\tconst { a, b } = candidate;\n\t\tif (selected.length >= config.nPairs) break;\n\n\t\tconst pairKey = a < b ? `${a}|${b}` : `${b}|${a}`;\n\t\tif (selectedPairKeys.has(pairKey)) continue;\n\n\t\tconst aNbrs = new Set(graph.neighbours(a));\n\t\tconst bNbrs = new Set(graph.neighbours(b));\n\n\t\tlet isDiverse = true;\n\t\tfor (const prev of selected) {\n\t\t\tconst paNbrs = new Set(graph.neighbours(prev.source.id));\n\t\t\tif (jaccard(aNbrs, paNbrs) >= config.diversityThreshold) {\n\t\t\t\tconst pbNbrs = new Set(graph.neighbours(prev.target.id));\n\t\t\t\tif (jaccard(bNbrs, pbNbrs) >= config.diversityThreshold) {\n\t\t\t\t\tisDiverse = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!isDiverse) continue;\n\n\t\tselectedPairKeys.add(pairKey);\n\t\tselected.push({\n\t\t\tsource: { id: a },\n\t\t\ttarget: { id: b },\n\t\t\tsourceTriads: triadCounts.get(a) ?? 0,\n\t\t\ttargetTriads: triadCounts.get(b) ?? 0,\n\t\t\tsourceCategory: categories.get(a) ?? \"periphery\",\n\t\t\ttargetCategory: categories.get(b) ?? \"periphery\",\n\t\t});\n\t}\n\n\t// Fill shortfall with random pairs\n\tlet fillAttempts = 0;\n\twhile (\n\t\tselected.length < config.nPairs &&\n\t\tallNodes.length >= 2 &&\n\t\tfillAttempts < config.nPairs * 20\n\t) {\n\t\tfillAttempts++;\n\t\tconst i1 = Math.floor(rng() * allNodes.length);\n\t\tconst i2 = Math.floor(rng() * allNodes.length);\n\t\tconst a = allNodes[i1];\n\t\tconst b = allNodes[i2];\n\t\tif (a === undefined || b === undefined || a === b) continue;\n\n\t\tconst pairKey = a < b ? `${a}|${b}` : `${b}|${a}`;\n\t\tif (selectedPairKeys.has(pairKey)) continue;\n\n\t\tselectedPairKeys.add(pairKey);\n\t\tselected.push({\n\t\t\tsource: { id: a },\n\t\t\ttarget: { id: b },\n\t\t\tsourceTriads: triadCounts.get(a) ?? 0,\n\t\t\ttargetTriads: triadCounts.get(b) ?? 0,\n\t\t\tsourceCategory: categories.get(a) ?? \"periphery\",\n\t\t\ttargetCategory: categories.get(b) ?? \"periphery\",\n\t\t});\n\t}\n\n\treturn {\n\t\tpairs: selected.slice(0, config.nPairs),\n\t\ttriadCounts,\n\t\tcategories,\n\t};\n}\n","/**\n * Stratified seed selection — legacy human-defined strata.\n *\n * Requires user-provided field/type classifications. This is included for comparison\n * and for users who have domain metadata.\n *\n * @packageDocumentation\n */\n\nimport type { ReadableGraph, NodeId } from \"../graph/index\";\nimport type { Seed } from \"../schemas/index\";\n\n/**\n * Field classification function type.\n * User provides a function that returns the field name for a node.\n */\nexport type FieldClassifier = (node: {\n\tid: NodeId;\n\ttype?: string;\n}) => string | undefined;\n\n/**\n * Stratum definition for seed pair selection.\n */\nexport interface StratumDefinition {\n\treadonly name: string;\n\treadonly description: string;\n\treadonly predicate: (\n\t\tsource: { id: NodeId; type?: string },\n\t\ttarget: { id: NodeId; type?: string },\n\t) => boolean;\n}\n\n/**\n * Stratum with sampled seed pairs.\n */\nexport interface StratumResult {\n\treadonly name: string;\n\treadonly pairs: readonly SeedPair[];\n}\n\n/**\n * A seed pair with stratum metadata.\n */\nexport interface SeedPair {\n\treadonly source: Seed;\n\treadonly target: Seed;\n\treadonly stratum: string;\n\treadonly sameField: boolean;\n}\n\n/**\n * Result of stratified seed selection.\n */\nexport interface StratifiedResult {\n\treadonly strata: readonly StratumResult[];\n\treadonly totalPairs: number;\n\treadonly errors: readonly Error[];\n}\n\n/**\n * Configuration for stratified seed selection.\n */\nexport interface StratifiedOptions {\n\t/** Function to classify nodes by field */\n\treadonly fieldClassifier: FieldClassifier;\n\t/** Number of pairs to sample per stratum */\n\treadonly pairsPerStratum?: number;\n\t/** Random seed for reproducibility */\n\treadonly rngSeed?: number;\n\t/** Custom stratum definitions */\n\treadonly customStrata?: readonly StratumDefinition[];\n}\n\n/** Default values */\nconst DEFAULTS = {\n\tpairsPerStratum: 10,\n\trngSeed: 42,\n} as const;\n\n/**\n * Simple seeded pseudo-random number generator using mulberry32.\n */\nfunction createRNG(seed: number): () => number {\n\tlet state = seed >>> 0;\n\treturn (): number => {\n\t\tstate = (state + 0x6d2b79f5) >>> 0;\n\t\tlet t = Math.imul(state ^ (state >>> 15), state | 1);\n\t\tt = (t ^ (t >>> 7)) * (t | 0x61c88647);\n\t\treturn ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n\t};\n}\n\n/**\n * Stratified seed selection algorithm.\n *\n * @param graph - The graph to sample seeds from\n * @param options - Configuration options including field classifier\n * @returns Stratified selection result\n *\n * @example\n * ```typescript\n * const graph = new AdjacencyMapGraph();\n * // ... populate graph ...\n *\n * const result = stratified(graph, {\n * fieldClassifier: (node) => node.type === 'paper' ? 'computer-science' : undefined,\n * pairsPerStratum: 20,\n * });\n *\n * for (const stratum of result.strata) {\n * console.log(`${stratum.name}: ${stratum.pairs.length} pairs`);\n * }\n * ```\n */\nexport function stratified(\n\tgraph: ReadableGraph,\n\toptions: StratifiedOptions,\n): StratifiedResult {\n\tconst {\n\t\tfieldClassifier,\n\t\tpairsPerStratum = DEFAULTS.pairsPerStratum,\n\t\trngSeed = DEFAULTS.rngSeed,\n\t\tcustomStrata,\n\t} = options;\n\n\tconst rng = createRNG(rngSeed);\n\tconst strataDefinitions = customStrata ?? [];\n\n\t// Collect all nodes with their field classifications\n\tconst nodesWithFields: { id: NodeId; type?: string; field?: string }[] = [];\n\n\tfor (const nodeId of graph.nodeIds()) {\n\t\tconst node = graph.getNode(nodeId);\n\t\tif (node === undefined) continue;\n\n\t\tconst classifierInput: { id: NodeId; type?: string } =\n\t\t\tnode.type !== undefined\n\t\t\t\t? { id: nodeId, type: node.type }\n\t\t\t\t: { id: nodeId };\n\t\tconst field = fieldClassifier(classifierInput);\n\t\tif (field === undefined) continue;\n\n\t\tconst nodeWithField: { id: NodeId; type?: string; field: string } =\n\t\t\tnode.type !== undefined\n\t\t\t\t? { id: nodeId, type: node.type, field }\n\t\t\t\t: { id: nodeId, field };\n\t\tnodesWithFields.push(nodeWithField);\n\t}\n\n\tconst errors: Error[] = [];\n\tconst strataResults: StratumResult[] = [];\n\n\t// Process each stratum\n\tfor (const stratum of strataDefinitions) {\n\t\tconst pairs: SeedPair[] = [];\n\t\tconst eligiblePairs: {\n\t\t\tsource: { id: NodeId; type?: string };\n\t\t\ttarget: { id: NodeId; type?: string };\n\t\t}[] = [];\n\n\t\t// Find all node pairs that match this stratum\n\t\tfor (let i = 0; i < nodesWithFields.length; i++) {\n\t\t\tconst source = nodesWithFields[i];\n\t\t\tif (source === undefined) continue;\n\n\t\t\tfor (let j = i + 1; j < nodesWithFields.length; j++) {\n\t\t\t\tif (j === i) continue;\n\t\t\t\tconst target = nodesWithFields[j];\n\t\t\t\tif (target === undefined) continue;\n\n\t\t\t\tif (stratum.predicate(source, target)) {\n\t\t\t\t\teligiblePairs.push({ source, target });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Sample pairs from eligible pairs\n\t\tconst numToSample = Math.min(pairsPerStratum, eligiblePairs.length);\n\t\tfor (let i = 0; i < numToSample; i++) {\n\t\t\tconst idx = Math.floor(rng() * eligiblePairs.length);\n\t\t\tconst pair = eligiblePairs[idx];\n\t\t\tif (pair === undefined) continue;\n\n\t\t\tconst sourceField = fieldClassifier(pair.source);\n\t\t\tconst targetField = fieldClassifier(pair.target);\n\n\t\t\tpairs.push({\n\t\t\t\tsource: { id: pair.source.id },\n\t\t\t\ttarget: { id: pair.target.id },\n\t\t\t\tstratum: stratum.name,\n\t\t\t\tsameField: sourceField === targetField,\n\t\t\t});\n\t\t}\n\n\t\tstrataResults.push({\n\t\t\tname: stratum.name,\n\t\t\tpairs,\n\t\t});\n\t}\n\n\t// Collect errors for empty strata\n\tfor (const stratum of strataDefinitions) {\n\t\tconst result = strataResults.find((r) => r.name === stratum.name);\n\t\tif (result === undefined || result.pairs.length === 0) {\n\t\t\terrors.push(new Error(`No pairs found for stratum: ${stratum.name}`));\n\t\t}\n\t}\n\n\tconst totalPairs = strataResults.reduce((sum, r) => sum + r.pairs.length, 0);\n\n\treturn {\n\t\tstrata: strataResults,\n\t\ttotalPairs,\n\t\terrors,\n\t};\n}\n"],"mappings":"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"}
|
package/dist/seeds/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/seeds/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/seeds/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC"}
|