Skip to content

Commit

Permalink
Kahn's algorithm for topological sort (#286)
Browse files Browse the repository at this point in the history
  • Loading branch information
czgdp1807 authored May 31, 2020
1 parent 8fef63a commit e625a9f
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 4 deletions.
3 changes: 2 additions & 1 deletion pydatastructs/graphs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
minimum_spanning_tree_parallel,
strongly_connected_components,
depth_first_search,
shortest_paths
shortest_paths,
topological_sort
)

__all__.extend(algorithms.__all__)
75 changes: 73 additions & 2 deletions pydatastructs/graphs/algorithms.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Contains all the algorithms associated with graph
Contains algorithms associated with graph
data structure.
"""
from collections import deque
Expand All @@ -18,7 +18,8 @@
'minimum_spanning_tree_parallel',
'strongly_connected_components',
'depth_first_search',
'shortest_paths'
'shortest_paths',
'topological_sort'
]

Stack = Queue = deque
Expand Down Expand Up @@ -725,3 +726,73 @@ def _bellman_ford_adjacency_list(graph: Graph, source: str, target: str) -> tupl
return (distances, predecessor)

_bellman_ford_adjacency_matrix = _bellman_ford_adjacency_list

def topological_sort(graph: Graph, algorithm: str) -> list:
"""
Performs topological sort on the given graph using given algorithm.
Parameters
==========
graph: Graph
The graph under consideration.
algorithm: str
The algorithm to be used.
Currently, following are supported,
'kahn' -> Kahn's algorithm as given in [1].
Returns
=======
list
The list of topologically sorted vertices.
Examples
========
>>> from pydatastructs import Graph, AdjacencyListGraphNode, topological_sort
>>> v_1 = AdjacencyListGraphNode('v_1')
>>> v_2 = AdjacencyListGraphNode('v_2')
>>> graph = Graph(v_1, v_2)
>>> graph.add_edge('v_1', 'v_2')
>>> topological_sort(graph, 'kahn')
['v_1', 'v_2']
References
==========
.. [1] https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm
"""
import pydatastructs.graphs.algorithms as algorithms
func = "_" + algorithm + "_" + graph._impl
if not hasattr(algorithms, func):
raise NotImplementedError(
"Currently %s algorithm isn't implemented for "
"performing topological sort on %s graphs."%(algorithm, graph._impl))
return getattr(algorithms, func)(graph)

def _kahn_adjacency_list(graph: Graph) -> list:
S = set(graph.vertices)
in_degree = dict()
for u in graph.vertices:
for v in graph.neighbors(u):
if v.name not in in_degree:
in_degree[v.name] = 0
in_degree[v.name] += 1
if v.name in S:
S.remove(v.name)

L = []
while S:
n = S.pop()
L.append(n)
for m in graph.neighbors(n):
graph.remove_edge(n, m.name)
in_degree[m.name] -= 1
if in_degree[m.name] == 0:
S.add(m.name)
in_degree.pop(m.name)

if in_degree:
raise ValueError("Graph is not acyclic.")
return L
26 changes: 25 additions & 1 deletion pydatastructs/graphs/tests/test_algorithms.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from pydatastructs import (breadth_first_search, Graph,
breadth_first_search_parallel, minimum_spanning_tree,
minimum_spanning_tree_parallel, strongly_connected_components,
depth_first_search, shortest_paths)
depth_first_search, shortest_paths, topological_sort)
from pydatastructs.utils.raises_util import raises

def test_breadth_first_search():
Expand Down Expand Up @@ -289,3 +289,27 @@ def _test_shortest_paths(ds, algorithm):

_test_shortest_paths("List", 'bellman_ford')
_test_shortest_paths("Matrix", 'bellman_ford')

def test_topological_sort():

def _test_topological_sort(ds, algorithm):
import pydatastructs.utils.misc_util as utils
GraphNode = getattr(utils, "Adjacency" + ds + "GraphNode")
vertices = [GraphNode('2'), GraphNode('3'), GraphNode('5'),
GraphNode('7'), GraphNode('8'), GraphNode('10'),
GraphNode('11'), GraphNode('9')]

graph = Graph(*vertices)
graph.add_edge('5', '11')
graph.add_edge('7', '11')
graph.add_edge('7', '8')
graph.add_edge('3', '8')
graph.add_edge('3', '10')
graph.add_edge('11', '2')
graph.add_edge('11', '9')
graph.add_edge('11', '10')
graph.add_edge('8', '9')
l = topological_sort(graph, algorithm)
assert all([(l1 in l[0:3]) for l1 in ('3', '5', '7')] +
[(l2 in l[3:5]) for l2 in ('8', '11')] +
[(l3 in l[5:]) for l3 in ('10', '9', '2')])

0 comments on commit e625a9f

Please sign in to comment.