This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python | |
# -*- coding: utf-8 -*- | |
""" | |
`Topological sort by Kahn (1962) on Wikipedia | |
<http://en.wikipedia.org/wiki/Topological_sorting>`_ | |
L ← Empty list that will contain the sorted elements | |
S ← Set of all nodes with no incoming edges | |
while S is non-empty do | |
remove a node n from S | |
insert n into L | |
for each node m with an edge e from n to m do | |
remove edge e from the graph | |
if m has no other incoming edges then | |
insert m into S | |
if graph has edges then | |
return error (graph has at least one cycle) | |
else | |
return L (a topologically sorted order) | |
""" | |
class CircularDependencyError(Exception): | |
def __init__(self, keys): | |
self.args = keys | |
self.message = self.__str__ | |
def __str__(self): | |
return 'Not a DAG. These keys are cyclic:\n\t%s' % str(self.args) | |
def topological_sort(DAG): | |
""" | |
Kahn ('62) topological sort. | |
:param DAG: directed acyclic graph | |
:type DAG: dict | |
""" | |
L = [] | |
S = [k for k, v in DAG.iteritems() if not v] | |
while S: | |
n = S.pop(0) | |
L.append(n) | |
for m in (k for k, v in DAG.iteritems() if n in v): | |
# idx = DAG[m].index(n); DAG[m].pop(idx) # Python < 2.7 alternative | |
DAG[m] = list(set(DAG[m]).difference([n])) | |
if not DAG[m]: | |
S.append(m) | |
if any([bool(v) for v in DAG.itervalues()]): | |
raise CircularDependencyError([k for k, v in DAG.iteritems() if v]) | |
return L | |
if __name__ == "__main__": | |
# test DAG | |
DAG = {'7': [], '5': [], '3': [], '11': ['7', '5'], '8': ['7', '3'], | |
'2': ['11'], '9': ['11', '8'], '10': ['11', '3']} | |
print topological_sort(DAG.copy()) | |
# test 10->9->8 circular dependency | |
notDAG = {'7': [], '5': [], '3': [], '11': ['7', '5'], '8': ['7', '3', '10'], | |
'2': ['11'], '9': ['11', '8'], '10': ['11', '3', '9']} | |
print topological_sort(notDAG.copy()) |
No comments:
Post a Comment