Skip to content

Commit f41652c

Browse files
committed
fix(tools): prevent stack overflow in treewidth validator
- Add depth tracking to Bron-Kerbosch algorithm in findMaxCliqueSize - Add depth tracking to Bron-Kerbosch algorithm in findMaxCliqueSizeInSet - When recursion depth exceeds 100, return conservative estimate - Prevents RangeError: Maximum call stack size exceeded on large dense graphs - All 539 graph-gen tests now passing
1 parent ff376b3 commit f41652c

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

packages/graph-gen/src/validation/treewidth-validator.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,17 @@ const findMaxCliqueSizeInSet = (vertices: Set<string>, adjacency: Map<string, st
167167
}
168168

169169
let maxSize = 0;
170+
const MAX_DEPTH = 100; // Prevent stack overflow on large graphs
170171

171172
// Bron-Kerbosch with pivot
172-
const bronKerbosch = (R: Set<string>, P: Set<string>, X: Set<string>): void => {
173+
const bronKerbosch = (R: Set<string>, P: Set<string>, X: Set<string>, depth: number = 0): void => {
174+
if (depth > MAX_DEPTH) {
175+
// Depth limit exceeded, return conservative estimate
176+
// For dense graphs with many vertices, max clique is likely all vertices
177+
maxSize = Math.max(maxSize, Math.min(vertices.size, R.size + P.size));
178+
return;
179+
}
180+
173181
if (P.size === 0 && X.size === 0) {
174182
// R is a maximal clique
175183
maxSize = Math.max(maxSize, R.size);
@@ -206,7 +214,7 @@ const findMaxCliqueSizeInSet = (vertices: Set<string>, adjacency: Map<string, st
206214
const newP = new Set([...P].filter(n => vNeighbors.has(n)));
207215
const newX = new Set([...X].filter(n => vNeighbors.has(n)));
208216

209-
bronKerbosch(newR, newP, newX);
217+
bronKerbosch(newR, newP, newX, depth + 1);
210218

211219
P.delete(v);
212220
X.add(v);
@@ -245,9 +253,16 @@ export const findMaxCliqueSize = (nodes: TestNode[], edges: TestEdge[], directed
245253
const adjacency = buildAdjacencyList(nodes, edges, false);
246254

247255
let maxSize = 0;
256+
const MAX_DEPTH = 100; // Prevent stack overflow on large graphs
248257

249258
// Bron-Kerbosch with pivot
250-
const bronKerbosch = (R: Set<string>, P: Set<string>, X: Set<string>): void => {
259+
const bronKerbosch = (R: Set<string>, P: Set<string>, X: Set<string>, depth: number = 0): void => {
260+
if (depth > MAX_DEPTH) {
261+
// Depth limit exceeded, return conservative estimate
262+
maxSize = Math.max(maxSize, Math.min(nodes.length, R.size + P.size));
263+
return;
264+
}
265+
251266
if (P.size === 0 && X.size === 0) {
252267
// R is a maximal clique
253268
maxSize = Math.max(maxSize, R.size);
@@ -284,7 +299,7 @@ export const findMaxCliqueSize = (nodes: TestNode[], edges: TestEdge[], directed
284299
const newP = new Set([...P].filter(n => vNeighbors.has(n)));
285300
const newX = new Set([...X].filter(n => vNeighbors.has(n)));
286301

287-
bronKerbosch(newR, newP, newX);
302+
bronKerbosch(newR, newP, newX, depth + 1);
288303

289304
P.delete(v);
290305
X.add(v);

0 commit comments

Comments
 (0)