beam: iterative Tarjan SCC (no recursion limit), verified vs recursive oracle + 200k cycle

This commit is contained in:
beam committed 2026-10-24 21:46:31 +00:00
1 parent 0c4629b120
commit 12a48021e3
2 files changed
+98

No files matched your search

+55
View File
@@ -0,0 +1,55 @@
"""Iterative Tarjan strongly connected components (no recursion limit)."""
from __future__ import annotations
from typing import Dict, Iterable, List, Tuple
def scc(adj: Dict[int, Iterable[int]]) -> List[List[int]]:
index_counter = [0]
stack: List[int] = []
on_stack: set = set()
indices: Dict[int, int] = {}
lowlink: Dict[int, int] = {}
result: List[List[int]] = []
for u in list(adj.keys()):
if u in indices:
continue
call_stack: List[Tuple[int, iter]] = [(u, iter(adj.get(u, ())))]
indices[u] = lowlink[u] = index_counter[0]
index_counter[0] += 1
stack.append(u)
on_stack.add(u)
while call_stack:
v, it = call_stack[-1]
advanced = False
for w in it:
if w not in indices:
indices[w] = lowlink[w] = index_counter[0]
index_counter[0] += 1
stack.append(w)
on_stack.add(w)
call_stack.append((w, iter(adj.get(w, ()))))
advanced = True
break
elif w in on_stack:
if indices[w] < lowlink[v]:
lowlink[v] = indices[w]
call_stack[-1] = (v, it)
if advanced:
continue
call_stack.pop()
if call_stack:
parent = call_stack[-1][0]
if lowlink[v] < lowlink[parent]:
lowlink[parent] = lowlink[v]
if lowlink[v] == indices[v]:
comp = []
while True:
w = stack.pop()
on_stack.discard(w)
comp.append(w)
if w == v:
break
result.append(comp)
return result
+43
View File
@@ -0,0 +1,43 @@
import sys
sys.path.insert(0, "/root/.hermes/wizard-outputs/beam")
from scc import scc
def tarjan_recursive(adj):
idx=[0]; stack=[]; on=set(); indices={}; low={}; res=[]
import sys as _s
_s.setrecursionlimit(100000)
def strong(v):
indices[v]=low[v]=idx[0]; idx[0]+=1; stack.append(v); on.add(v)
for w in adj.get(v,()):
if w not in indices:
strong(w); low[v]=min(low[v],low[w])
elif w in on: low[v]=min(low[v],indices[w])
if low[v]==indices[v]:
comp=[]
while True:
w=stack.pop(); on.discard(w); comp.append(w)
if w==v: break
res.append(comp)
for u in list(adj):
if u not in indices: strong(u)
return res
import random
random.seed(42)
for trial in range(200):
n=random.randint(1,40)
adj={i:[] for i in range(n)}
for i in range(n):
for j in range(n):
if random.random()<0.25: adj[i].append(j)
a=sorted(sorted(c) for c in scc(adj))
b=sorted(sorted(c) for c in tarjan_recursive(adj))
assert a==b, (a,b)
print("ALL 200 RANDOM TRIALS PASSED")
# big graph no recursion
N=200000
adj={i:[i+1] for i in range(N-1)}
adj[N-1]=[0]
r=scc(adj)
assert len(r)==1 and len(r[0])==N
print("BIG CYCLE OK", len(r[0]))