Compute Strongly Connected Components of a directed graph. Args: vertices: the labels for the vertices edges: for each vertex, gives the target vertices of its outgoing edges Returns: An iterator yielding strongly connected components, each represented as a set of v
(
vertices: AbstractSet[T], edges: dict[T, list[T]]
)
| 9 | |
| 10 | |
| 11 | def strongly_connected_components( |
| 12 | vertices: AbstractSet[T], edges: dict[T, list[T]] |
| 13 | ) -> Iterator[set[T]]: |
| 14 | """Compute Strongly Connected Components of a directed graph. |
| 15 | |
| 16 | Args: |
| 17 | vertices: the labels for the vertices |
| 18 | edges: for each vertex, gives the target vertices of its outgoing edges |
| 19 | |
| 20 | Returns: |
| 21 | An iterator yielding strongly connected components, each |
| 22 | represented as a set of vertices. Each input vertex will occur |
| 23 | exactly once; vertices not part of a SCC are returned as |
| 24 | singleton sets. |
| 25 | |
| 26 | From https://code.activestate.com/recipes/578507/. |
| 27 | """ |
| 28 | identified: set[T] = set() |
| 29 | stack: list[T] = [] |
| 30 | index: dict[T, int] = {} |
| 31 | boundaries: list[int] = [] |
| 32 | |
| 33 | def dfs(v: T) -> Iterator[set[T]]: |
| 34 | index[v] = len(stack) |
| 35 | stack.append(v) |
| 36 | boundaries.append(index[v]) |
| 37 | |
| 38 | for w in edges[v]: |
| 39 | if w not in index: |
| 40 | yield from dfs(w) |
| 41 | elif w not in identified: |
| 42 | while index[w] < boundaries[-1]: |
| 43 | boundaries.pop() |
| 44 | |
| 45 | if boundaries[-1] == index[v]: |
| 46 | boundaries.pop() |
| 47 | scc = set(stack[index[v] :]) |
| 48 | del stack[index[v] :] |
| 49 | identified.update(scc) |
| 50 | yield scc |
| 51 | |
| 52 | for v in vertices: |
| 53 | if v not in index: |
| 54 | yield from dfs(v) |
| 55 | |
| 56 | |
| 57 | def prepare_sccs( |
searching dependent graphs…