Skip to content

Instantly share code, notes, and snippets.

@mohamed
Last active May 16, 2023 11:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mohamed/4a5f5931d11bc2e68081bf83c5c0883e to your computer and use it in GitHub Desktop.
Save mohamed/4a5f5931d11bc2e68081bf83c5c0883e to your computer and use it in GitHub Desktop.
Tarjan's strongly connected components algorithm
"""
Tarjan's strongly connected components algorithm + Topological sort
Taken from: http://www.logarithmic.net/pfh/blog/01208083168
Public domain. Use it as you will
"""
def strongly_connected_components(graph):
"""
Tarjan's Algorithm (named for its discoverer, Robert Tarjan) is a graph
theory algorithm for finding the strongly connected components of a graph.
Based on:
http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
"""
index_counter = [0]
stack = []
lowlinks = {}
index = {}
result = []
def strongconnect(node):
# set the depth index for this node to the smallest unused index
index[node] = index_counter[0]
lowlinks[node] = index_counter[0]
index_counter[0] += 1
stack.append(node)
# Consider successors of `node`
try:
successors = graph[node]
except KeyError:
successors = []
for successor in successors:
if successor not in lowlinks:
# Successor has not yet been visited; recurse on it
strongconnect(successor)
lowlinks[node] = min(lowlinks[node], lowlinks[successor])
elif successor in stack:
# the successor is in the stack and hence in the current
# strongly connected component (SCC)
lowlinks[node] = min(lowlinks[node], index[successor])
# If `node` is a root node, pop the stack and generate an SCC
if lowlinks[node] == index[node]:
connected_component = []
while True:
successor = stack.pop()
connected_component.append(successor)
if successor == node:
break
component = tuple(connected_component)
# storing the result
result.append(component)
for node in graph:
if node not in lowlinks:
strongconnect(node)
return result
def topological_sort(graph):
"""
Performs topological sort on the graph
"""
count = {}
for node in graph:
count[node] = 0
for node in graph:
for successor in graph[node]:
count[successor] += 1
ready = [node for node in graph if count[node] == 0]
result = []
while ready:
node = ready.pop(-1)
result.append(node)
for successor in graph[node]:
count[successor] -= 1
if count[successor] == 0:
ready.append(successor)
return result
def robust_topological_sort(graph):
""" First identify strongly connected components,
then perform a topological sort on these components. """
components = strongly_connected_components(graph)
node_component = {}
for component in components:
for node in component:
node_component[node] = component
component_graph = {}
for component in components:
component_graph[component] = []
for node in graph:
node_c = node_component[node]
for successor in graph[node]:
successor_c = node_component[successor]
if node_c != successor_c:
component_graph[node_c].append(successor_c)
return topological_sort(component_graph)
def is_acyclic(graph):
"""
Checks if the specified graph is acyclic or not.
Returns True if acyclic, False otherwise
"""
components = strongly_connected_components(graph)
for comp in components:
if len(comp) > 1:
return False
return True
if __name__ == '__main__':
g1 = {
0: [1],
1: [2],
2: [1, 3],
3: [3],
}
g2 = {
0: [1],
1: [2],
2: [3],
3: [],
}
graphs = [g1, g2]
for g in graphs:
print(robust_topological_sort(g))
print(f"Is the graph acyclic? {is_acyclic(g)}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment