def topological_sort(self): """ Orders nodes (permutes their topo_index's) such that no node is before any of its parents. Node with lowest topo_index number is a root node. So this could also be called a chronological or birthday sort, youngest nodes first. Exception is raised if graph has cycles and cannot be ordered topologically. Returns ------- None """ self.detect_two_node_cycle() sorted_set = set() i = 0 num_unsorted_nds = len(self.nodes) while len(self.nodes) > 0: if num_unsorted_nds <= 0: raise BadGraphStructure("Graph must be acyclic") num_unsorted_nds -= 1 for node in self.nodes: if sorted_set >= node.parents: sorted_set.add(node) self.nodes.remove(node) node.topo_index = i i += 1 break self.nodes = sorted_set
def detect_two_node_cycle(self): """ Detects a 2 node cycle. That is, when 2 nodes are both parents and children of each other. Returns ------- None """ for node in self.nodes: overlap = node.parents & node.children if overlap: raise BadGraphStructure("two node cycle detected")