beam: iterative Tarjan SCC (no recursion limit), verified vs recursive oracle + 200k cycle
This commit is contained in:
1 parent
0c4629b120
commit
12a48021e3
2 files changed
+98
No files matched your search
@@ -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
|
||||
@@ -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]))
|
||||
Reference in new issue
Block a user