Source code for hwt.serializer.combLoopAnalyzer.tarjan
from typing import Generator
[docs]def _tarjan_head(index, lowlink, S, S_set, T, g, v):
lowlink[v] = index[v] = len(index)
S.append(v)
S_set.add(v)
it = iter(g.get(v, ()))
T.append((it, False, v, None))
[docs]class StronglyConnectedComponentSearchTarjan():
"""
Tarjan's strongly connected component search graph algorithm for DAGs
based on https://github.com/bwesterb/py-tarjan
"""
[docs] def __init__(self, g: dict):
"""
:param g: graph represented as a dictionary { <vertex> : <successors of vertex> }.
:note: vertex type does not matter but it has to be hashable (implement __eq__ and __hash__)
"""
self.g = g
[docs] def search_strongly_connected_components(self) -> Generator:
"""
yields the strongly connected components of the graph in a topological order.
"""
g = self.g # the graph
S = [] # The main stack of the alg.
S_set = set() # == set(S) for performance
index = {} # { v : <index of v> }
lowlink = {} # { v : <lowlink of v> }
T = [] # stack to replace recursion
main_iter = iter(g)
for v in main_iter:
if v not in index:
_tarjan_head(index, lowlink, S, S_set, T, g, v)
while T:
it, inside, v, w = T.pop()
if inside:
lowlink[v] = min(lowlink[w], lowlink[v])
body_break = False
for w in it:
if w not in index:
T.append((it, True, v, w))
_tarjan_head(index, lowlink, S, S_set, T, g, w)
body_break = True
break
if w in S_set:
lowlink[v] = min(lowlink[v], index[w])
if body_break:
continue
if lowlink[v] == index[v]:
scc = []
w = None
while v != w:
w = S.pop()
scc.append(w)
S_set.remove(w)
yield scc