Skip to content

Commit ceb179e

Browse files
committed
feat(traversal): add node discovery iteration tracking to novel algorithms
add nodeDiscoveryIteration tracking to entropy-guided, path-preserving, retrospective-salience, intelligent-delayed-termination, and overlap-based expansion algorithms. seeds recorded at iteration 0.
1 parent 2a2d7c4 commit ceb179e

File tree

5 files changed

+60
-0
lines changed

5 files changed

+60
-0
lines changed

src/algorithms/traversal/entropy-guided-expansion.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ export class EntropyGuidedExpansion<T> {
8383
private readonly paths: Array<{ fromSeed: number; toSeed: number; nodes: string[] }> = [];
8484
private readonly sampledEdges = new Set<string>();
8585
private stats: ExpansionStats;
86+
/** Tracks when each node was first discovered (iteration number) */
87+
private readonly nodeDiscoveryIteration = new Map<string, number>();
8688

8789
/** Track which frontier owns each node for O(1) intersection checking */
8890
private readonly nodeToFrontierIndex = new Map<string, number>();
@@ -123,6 +125,9 @@ export class EntropyGuidedExpansion<T> {
123125

124126
// Track which frontier owns this seed
125127
this.nodeToFrontierIndex.set(seed, index);
128+
129+
// Seeds are discovered at iteration 0
130+
this.nodeDiscoveryIteration.set(seed, 0);
126131
}
127132

128133
this.stats = {
@@ -254,6 +259,11 @@ export class EntropyGuidedExpansion<T> {
254259
activeState.visited.add(targetId);
255260
activeState.parents.set(targetId, { parent: node, edge: relationshipType });
256261

262+
// Track first discovery iteration (only if not already discovered)
263+
if (!this.nodeDiscoveryIteration.has(targetId)) {
264+
this.nodeDiscoveryIteration.set(targetId, this.stats.iterations);
265+
}
266+
257267
// Track which frontier owns this node (for O(1) intersection checking)
258268
this.nodeToFrontierIndex.set(targetId, activeIndex);
259269

@@ -298,6 +308,7 @@ export class EntropyGuidedExpansion<T> {
298308
sampledEdges: this.sampledEdges,
299309
visitedPerFrontier,
300310
stats: this.stats,
311+
nodeDiscoveryIteration: this.nodeDiscoveryIteration,
301312
};
302313
}
303314

src/algorithms/traversal/intelligent-delayed-termination.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ export class IntelligentDelayedTermination<T> {
6666
private readonly paths: Array<{ fromSeed: number; toSeed: number; nodes: string[] }> = [];
6767
private readonly sampledEdges = new Set<string>();
6868
private stats: ExpansionStats;
69+
/** Tracks when each node was first discovered (iteration number) */
70+
private readonly nodeDiscoveryIteration = new Map<string, number>();
6971

7072
/** Track which frontier owns each node for O(1) intersection checking */
7173
private readonly nodeToFrontierIndex = new Map<string, number>();
@@ -124,6 +126,9 @@ export class IntelligentDelayedTermination<T> {
124126

125127
// Track which frontier owns this seed
126128
this.nodeToFrontierIndex.set(seed, index);
129+
130+
// Seeds are discovered at iteration 0
131+
this.nodeDiscoveryIteration.set(seed, 0);
127132
}
128133

129134
this.stats = {
@@ -182,6 +187,11 @@ export class IntelligentDelayedTermination<T> {
182187
activeState.visited.add(targetId);
183188
activeState.parents.set(targetId, { parent: node, edge: relationshipType });
184189

190+
// Track first discovery iteration (only if not already discovered)
191+
if (!this.nodeDiscoveryIteration.has(targetId)) {
192+
this.nodeDiscoveryIteration.set(targetId, this.stats.iterations);
193+
}
194+
185195
// Track which frontier owns this node (for O(1) intersection checking)
186196
this.nodeToFrontierIndex.set(targetId, activeIndex);
187197

@@ -238,6 +248,7 @@ export class IntelligentDelayedTermination<T> {
238248
sampledEdges: this.sampledEdges,
239249
visitedPerFrontier,
240250
stats: this.stats,
251+
nodeDiscoveryIteration: this.nodeDiscoveryIteration,
241252
};
242253
}
243254

src/algorithms/traversal/overlap-based/overlap-based-expansion.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ export class OverlapBasedExpansion<T> {
8383
}> = [];
8484
private stats: ExpansionStats;
8585
private iteration = 0;
86+
/** Tracks when each node was first discovered (iteration number) */
87+
private readonly nodeDiscoveryIteration = new Map<string, number>();
8688

8789
/** Track which frontier owns each node for O(1) overlap detection */
8890
private readonly nodeToFrontierIndex = new Map<string, number>();
@@ -126,6 +128,9 @@ export class OverlapBasedExpansion<T> {
126128

127129
// Track which frontier owns this seed
128130
this.nodeToFrontierIndex.set(seed, index);
131+
132+
// Seeds are discovered at iteration 0
133+
this.nodeDiscoveryIteration.set(seed, 0);
129134
}
130135

131136
this.stats = {
@@ -236,6 +241,11 @@ export class OverlapBasedExpansion<T> {
236241
activeState.visited.add(targetId);
237242
activeState.parents.set(targetId, { parent: node, edge: relationshipType });
238243

244+
// Track first discovery iteration (only if not already discovered)
245+
if (!this.nodeDiscoveryIteration.has(targetId)) {
246+
this.nodeDiscoveryIteration.set(targetId, this.iteration);
247+
}
248+
239249
// Update nodeDistances for SphereIntersectionStrategy
240250
if (activeState.nodeDistances) {
241251
const parentDistance = activeState.nodeDistances.get(node) ?? 0;
@@ -336,6 +346,11 @@ export class OverlapBasedExpansion<T> {
336346
frontier.visited.add(targetId);
337347
frontier.parents.set(targetId, { parent: node, edge: relationshipType });
338348

349+
// Track first discovery iteration (only if not already discovered)
350+
if (!this.nodeDiscoveryIteration.has(targetId)) {
351+
this.nodeDiscoveryIteration.set(targetId, this.iteration);
352+
}
353+
339354
// Update nodeDistances for SphereIntersectionStrategy
340355
if (frontier.nodeDistances) {
341356
const parentDistance = frontier.nodeDistances.get(node) ?? 0;
@@ -379,6 +394,7 @@ export class OverlapBasedExpansion<T> {
379394
iterations: this.iteration,
380395
overlapMatrix: this.overlapMatrix,
381396
},
397+
nodeDiscoveryIteration: this.nodeDiscoveryIteration,
382398
};
383399

384400
// Apply between-graph strategy to refine output

src/algorithms/traversal/path-preserving-expansion.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ export class PathPreservingExpansion<T> {
9696
private readonly paths: Array<{ fromSeed: number; toSeed: number; nodes: string[] }> = [];
9797
private readonly sampledEdges = new Set<string>();
9898
private stats: ExpansionStats;
99+
/** Tracks when each node was first discovered (iteration number) */
100+
private readonly nodeDiscoveryIteration = new Map<string, number>();
99101

100102
/** Track which frontier owns each node for O(1) intersection checking */
101103
private readonly nodeToFrontierIndex = new Map<string, number>();
@@ -138,6 +140,9 @@ export class PathPreservingExpansion<T> {
138140

139141
// Track which frontier owns this seed
140142
this.nodeToFrontierIndex.set(seed, index);
143+
144+
// Seeds are discovered at iteration 0
145+
this.nodeDiscoveryIteration.set(seed, 0);
141146
}
142147

143148
this.stats = {
@@ -191,6 +196,11 @@ export class PathPreservingExpansion<T> {
191196
activeState.visited.add(targetId);
192197
activeState.parents.set(targetId, { parent: node, edge: relationshipType });
193198

199+
// Track first discovery iteration (only if not already discovered)
200+
if (!this.nodeDiscoveryIteration.has(targetId)) {
201+
this.nodeDiscoveryIteration.set(targetId, this.stats.iterations);
202+
}
203+
194204
// Track which frontier owns this node (for O(1) intersection checking)
195205
this.nodeToFrontierIndex.set(targetId, activeIndex);
196206

@@ -240,6 +250,7 @@ export class PathPreservingExpansion<T> {
240250
sampledEdges: this.sampledEdges,
241251
visitedPerFrontier,
242252
stats: this.stats,
253+
nodeDiscoveryIteration: this.nodeDiscoveryIteration,
243254
};
244255
}
245256

src/algorithms/traversal/retrospective-salience-expansion.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ export class RetrospectiveSalienceExpansion<T> {
5151
private readonly paths: Array<{ fromSeed: number; toSeed: number; nodes: string[] }> = [];
5252
private readonly sampledEdges = new Set<string>();
5353
private stats: ExpansionStats;
54+
/** Tracks when each node was first discovered (iteration number) */
55+
private readonly nodeDiscoveryIteration = new Map<string, number>();
5456

5557
/** Track which frontier owns each node for O(1) intersection checking */
5658
private readonly nodeToFrontierIndex = new Map<string, number>();
@@ -97,6 +99,9 @@ export class RetrospectiveSalienceExpansion<T> {
9799

98100
// Track which frontier owns this seed
99101
this.nodeToFrontierIndex.set(seed, index);
102+
103+
// Seeds are discovered at iteration 0
104+
this.nodeDiscoveryIteration.set(seed, 0);
100105
}
101106

102107
this.stats = {
@@ -149,6 +154,11 @@ export class RetrospectiveSalienceExpansion<T> {
149154
activeState.visited.add(targetId);
150155
activeState.parents.set(targetId, { parent: node, edge: relationshipType });
151156

157+
// Track first discovery iteration (only if not already discovered)
158+
if (!this.nodeDiscoveryIteration.has(targetId)) {
159+
this.nodeDiscoveryIteration.set(targetId, this.stats.iterations);
160+
}
161+
152162
// Track which frontier owns this node (for O(1) intersection checking)
153163
this.nodeToFrontierIndex.set(targetId, activeIndex);
154164

@@ -202,6 +212,7 @@ export class RetrospectiveSalienceExpansion<T> {
202212
sampledEdges: this.sampledEdges,
203213
visitedPerFrontier,
204214
stats: this.stats,
215+
nodeDiscoveryIteration: this.nodeDiscoveryIteration,
205216
};
206217
}
207218

0 commit comments

Comments
 (0)