Skip to content

Commit ce5e758

Browse files
committed
feat(sut): register salience-prioritised expansion sut
Add salience-prioritised SUT to expansion registry.
1 parent 08040f0 commit ce5e758

1 file changed

Lines changed: 99 additions & 1 deletion

File tree

src/registries/register-suts.ts

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ import { BidirectionalBFS } from "../algorithms/traversal/bidirectional-bfs.js";
1717
import type { DegreePrioritisedExpansionResult } from "../algorithms/traversal/degree-prioritised-expansion.js";
1818
import { DegreePrioritisedExpansion } from "../algorithms/traversal/degree-prioritised-expansion.js";
1919
import type { OverlapBasedExpansionResult } from "../algorithms/traversal/overlap-based/overlap-result.js";
20+
import { computeNodeSalienceFromRankedPaths,SaliencePrioritisedExpansion } from "../algorithms/traversal/salience-prioritised-expansion.js";
2021
import { FrontierBalancedExpansion } from "../experiments/baselines/frontier-balanced.js";
22+
import { registerOverlapSuts } from "./register-overlap-suts.js";
2123
// Re-export overlap-based SUT registration for convenience
22-
export { OVERLAP_SUT_REGISTRATIONS,overlapSutRegistry, registerOverlapSuts } from "./register-overlap-suts.js";
24+
export { OVERLAP_SUT_REGISTRATIONS, overlapSutRegistry, registerOverlapSuts } from "./register-overlap-suts.js";
25+
import { rankPaths } from "../algorithms/pathfinding/path-ranking.js";
2326
import { RandomPriorityExpansion } from "../experiments/baselines/random-priority.js";
2427
import { StandardBfsExpansion } from "../experiments/baselines/standard-bfs.js";
2528
import type { GraphExpander } from "../interfaces/graph-expander.js";
@@ -36,6 +39,9 @@ export interface ExpansionInputs {
3639

3740
/** Seed node IDs for expansion */
3841
seeds: string[];
42+
43+
/** Optional underlying graph for algorithms that need full graph access (e.g., path ranking) */
44+
graph?: import("../algorithms/graph/graph.js").Graph<import("../algorithms/types/graph.js").Node, import("../algorithms/types/graph.js").Edge>;
3945
}
4046

4147
/**
@@ -106,6 +112,15 @@ export const SUT_REGISTRATIONS: Record<string, SutRegistration> = {
106112
tags: ["traversal", "bidirectional", "baseline", "null-hypothesis"],
107113
description: "Bidirectional expansion with random node selection",
108114
},
115+
"salience-prioritised-v1.0.0": {
116+
id: "salience-prioritised-v1.0.0",
117+
name: "Salience-Prioritised Expansion",
118+
version: "1.0.0",
119+
role: "baseline",
120+
config: {} satisfies { topK?: number },
121+
tags: ["traversal", "bidirectional", "salience-aware", "parameter-free"],
122+
description: "Path quality-aware expansion prioritizing nodes by participation in high-salience paths",
123+
},
109124
};
110125

111126
/**
@@ -246,6 +261,80 @@ class RandomPrioritySUT implements SUT<ExpansionInputs, ExpansionResult> {
246261
}
247262
}
248263

264+
/**
265+
* SUT wrapper for Salience-Prioritised Expansion.
266+
*
267+
* **Novel Contribution**: Pre-computes node salience scores from Path Salience ranking
268+
* and uses them to prioritize expansion toward high-quality paths.
269+
*
270+
* This SUT automatically:
271+
* 1. Runs Path Salience ranking on the graph to find top-K salient paths
272+
* 2. Computes node participation scores for those paths
273+
* 3. Uses those scores to drive expansion (higher salience = expanded earlier)
274+
*
275+
* **Config**:
276+
* - topK: Number of top salient paths to use for scoring (default: 10)
277+
*
278+
* **Expected Outcome**: Higher salience coverage than degree-prioritised expansion
279+
* because the expansion naturally gravitates toward nodes that appear in
280+
* high-quality paths.
281+
*/
282+
class SaliencePrioritisedSUT implements SUT<ExpansionInputs, ExpansionResult> {
283+
readonly id = "salience-prioritised-v1.0.0";
284+
readonly config: Readonly<Record<string, unknown>>;
285+
286+
constructor(config?: Record<string, unknown>) {
287+
this.config = { ...config };
288+
}
289+
290+
async run(inputs: ExpansionInputs): Promise<ExpansionResult> {
291+
const { expander, seeds, graph } = inputs;
292+
const topK = typeof this.config?.topK === "number" ? this.config.topK : 10;
293+
294+
// Get the graph for path ranking
295+
// Priority: 1) Use provided graph, 2) Call toGraph() if available, 3) Error
296+
let graphForRanking: import("../algorithms/graph/graph.js").Graph<import("../algorithms/types/graph.js").Node, import("../algorithms/types/graph.js").Edge>;
297+
if (graph) {
298+
graphForRanking = graph;
299+
} else if ("toGraph" in expander && typeof expander.toGraph === "function") {
300+
graphForRanking = await (expander as unknown as { toGraph: () => Promise<typeof graphForRanking> }).toGraph();
301+
} else {
302+
throw new Error("SaliencePrioritisedSUT requires either inputs.graph or expander.toGraph()");
303+
}
304+
305+
// Pre-compute salience scores by running Path Salience ranking
306+
const nodeSalience = new Map<string, number>();
307+
308+
// Run Path Salience for each seed pair to collect top-K paths
309+
for (let index = 0; index < seeds.length; index++) {
310+
for (let index_ = index + 1; index_ < seeds.length; index_++) {
311+
const result = rankPaths(graphForRanking, seeds[index], seeds[index_], {
312+
lambda: 0,
313+
maxPaths: topK * 2, // Get more than needed
314+
shortestOnly: false,
315+
traversalMode: "undirected",
316+
});
317+
318+
if (result.ok && result.value.some) {
319+
const ranked = result.value.value;
320+
// Compute node salience from top-K paths
321+
const topKPaths = ranked.slice(0, topK);
322+
const scores = computeNodeSalienceFromRankedPaths(topKPaths);
323+
324+
// Merge scores (sum across all pairs)
325+
for (const [node, score] of scores) {
326+
nodeSalience.set(node, (nodeSalience.get(node) ?? 0) + score);
327+
}
328+
}
329+
}
330+
}
331+
332+
// Create and run salience-prioritised expansion
333+
const algorithm = new SaliencePrioritisedExpansion(expander, seeds, nodeSalience);
334+
return algorithm.run();
335+
}
336+
}
337+
249338
/**
250339
* Register all expansion SUTs with a registry.
251340
*
@@ -285,6 +374,15 @@ export const registerExpansionSuts = (
285374
(config?: Record<string, unknown>): SUT<ExpansionInputs, ExpansionResult> => new RandomPrioritySUT(config)
286375
);
287376

377+
// Salience-Prioritised (Baseline - path quality-aware expansion)
378+
registry.register(
379+
SUT_REGISTRATIONS["salience-prioritised-v1.0.0"],
380+
(config?: Record<string, unknown>): SUT<ExpansionInputs, ExpansionResult> => new SaliencePrioritisedSUT(config)
381+
);
382+
383+
// Register all 27 overlap-based expansion variants
384+
registerOverlapSuts(registry);
385+
288386
return registry;
289387
};
290388

0 commit comments

Comments
 (0)