Skip to content

Commit 5b8b534

Browse files
committed
fix: fix infinite loops
1 parent bf6ef11 commit 5b8b534

File tree

2 files changed

+25
-23
lines changed

2 files changed

+25
-23
lines changed

src/ssspx/frontier.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,13 @@ def _consume_block_prefix(
150150
idx_block = 0
151151
iterations = 0
152152
max_iterations = len(blocks) * 100 # Safety limit to prevent infinite loops
153-
153+
154154
while got < want and idx_block < len(blocks) and iterations < max_iterations:
155155
iterations += 1
156156
block = blocks[idx_block]
157157
keep: List[Tuple[Vertex, Float]] = []
158158
processed_any = False
159-
159+
160160
for k, v in block:
161161
bestv = self._best.get(k)
162162
if bestv is None or v != bestv:
@@ -171,18 +171,18 @@ def _consume_block_prefix(
171171
processed_any = True
172172
else:
173173
keep.append((k, v))
174-
174+
175175
blocks[idx_block] = keep
176176
if not blocks[idx_block]:
177177
blocks.pop(idx_block)
178178
# Don't increment idx_block since we removed an element
179179
else:
180180
idx_block += 1
181-
181+
182182
# If we didn't process anything useful, break to avoid infinite loop
183183
if not processed_any and not keep:
184184
break
185-
185+
186186
return got
187187

188188
def pull(self) -> Tuple[Set[Vertex], Float]:
@@ -274,14 +274,14 @@ def pull(self) -> Tuple[Set[Vertex], Float]:
274274
s: Set[Vertex] = set()
275275
iterations = 0
276276
max_iterations = len(self._heap) * 2 # Safety limit
277-
277+
278278
while self._heap and len(s) < self.M and iterations < max_iterations:
279279
iterations += 1
280280
val, key = heapq.heappop(self._heap)
281281
if self._best.get(key) != val:
282282
continue # stale
283283
s.add(key)
284-
284+
285285
if not s:
286286
return set(), self.B
287287
x = self._heap[0][0] if self._heap else self.B

src/ssspx/solver.py

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def __init__(
146146
t = min(t, 20)
147147
else:
148148
k = max(1, min(self.cfg.k, 100)) # Safety cap
149-
t = max(1, min(self.cfg.t, 20)) # Safety cap
149+
t = max(1, min(self.cfg.t, 20)) # Safety cap
150150
self.k: int = k
151151
self.t: int = t
152152
self.L: int = max(1, min(math.ceil(math.log2(n) / t), 10)) # Cap levels
@@ -215,23 +215,23 @@ def _base_case(self, B: Float, S: Set[Vertex]) -> Tuple[Float, Set[Vertex]]:
215215
seen: Set[Vertex] = set()
216216
heap: List[Tuple[Float, Vertex]] = [(self.dhat[x], x)]
217217
in_heap: Set[Vertex] = {x}
218-
218+
219219
# Safety limits to prevent infinite loops
220220
iterations = 0
221221
max_iterations = min(self.k * 1000, self.G.n * 10)
222222

223223
while heap and len(U0) < self.k + 1 and iterations < max_iterations:
224224
self.counters["basecase_pops"] += 1
225225
iterations += 1
226-
226+
227227
du, u = heapq.heappop(heap)
228228
in_heap.discard(u)
229229
if du != self.dhat[u] or u in seen:
230230
continue
231231
seen.add(u)
232232
self.complete[u] = True
233233
U0.append(u)
234-
234+
235235
for v, w in self.G.adj[u]:
236236
if self._relax(u, v, w) and self.dhat[u] + w < B:
237237
if v not in in_heap:
@@ -262,32 +262,32 @@ def _find_pivots(self, B: Float, S: Set[Vertex]) -> Tuple[Set[Vertex], Set[Verte
262262
"""
263263
W: Set[Vertex] = set(S)
264264
current: Set[Vertex] = set(S)
265-
265+
266266
# Safety limits for findpivots
267267
iterations = 0
268268
max_iterations = min(self.k * len(S) * 100, self.G.n * 10)
269-
269+
270270
for round_num in range(1, self.k + 1):
271271
if iterations >= max_iterations:
272272
self.counters["iterations_protected"] += 1
273273
break
274-
274+
275275
self.counters["findpivots_rounds"] += 1
276276
nxt: Set[Vertex] = set()
277-
277+
278278
for u in current:
279279
iterations += 1
280280
if iterations >= max_iterations:
281281
break
282-
282+
283283
for v, w in self.G.adj[u]:
284284
if self._relax(u, v, w) and (self.dhat[u] + w < B):
285285
nxt.add(v)
286-
286+
287287
if not nxt:
288288
break
289289
W |= nxt
290-
290+
291291
# Early termination if W gets too large
292292
if len(W) > self.k * max(1, len(S)) * 5: # More generous limit
293293
return set(S), W
@@ -307,7 +307,7 @@ def _find_pivots(self, B: Float, S: Set[Vertex]) -> Tuple[Set[Vertex], Set[Verte
307307
seen: Set[Vertex] = set()
308308
iterations = 0
309309
max_tree_iterations = min(self.k * 10, len(W))
310-
310+
311311
while stack and iterations < max_tree_iterations:
312312
iterations += 1
313313
a = stack.pop()
@@ -332,11 +332,13 @@ def _make_frontier(self, level: int, B: Float) -> FrontierProtocol:
332332
return BlockFrontier(M=M, B=B)
333333
raise ConfigError(f"unknown frontier '{self.cfg.frontier}'")
334334

335-
def _bmssp(self, level: int, B: Float, S: Set[Vertex], depth: int = 0) -> Tuple[Float, Set[Vertex]]:
335+
def _bmssp(
336+
self, level: int, B: Float, S: Set[Vertex], depth: int = 0
337+
) -> Tuple[Float, Set[Vertex]]:
336338
# Prevent excessive recursion
337339
if depth > 50 or level > 20:
338340
return self._base_case(B, S)
339-
341+
340342
if level == 0:
341343
return self._base_case(B, S)
342344

@@ -353,7 +355,7 @@ def _bmssp(self, level: int, B: Float, S: Set[Vertex], depth: int = 0) -> Tuple[
353355
while len(U_accum) < cap and pull_iterations < max_pull_iterations:
354356
self.counters["pulls"] += 1
355357
pull_iterations += 1
356-
358+
357359
S_i, B_i = D.pull()
358360
if not S_i:
359361
Bprime = B
@@ -467,7 +469,7 @@ def path(self, target_original: Vertex) -> List[Vertex]:
467469
seen = set()
468470
iterations = 0
469471
max_iterations = self.G.n * 2 # Safety limit
470-
472+
471473
while cur is not None and iterations < max_iterations:
472474
iterations += 1
473475
chain.append(cur)

0 commit comments

Comments
 (0)