#!/usr/bin/env python # encoding: utf-8 from __future__ import (absolute_import, division, print_function, unicode_literals) import os, sys, re import logging import argparse import collections import numpy import time import TNode from GraphCycleException import GraphCycleException logger = logging.getLogger(__name__) class Topological_sort: """ Implementation of Topological Sorting - as per described on wikipedia # https://en.wikipedia.org/wiki/Topological_sorting L ← Empty list that will contain the sorted elements S ← Set of all nodes with no incoming edge while S is non-empty do remove a node n from S add n to tail of 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) """ @staticmethod def topologically_sort(nodes_list): logger.debug("Nodes to topo sort: " + str(nodes_list)) L = list() # empty list to contain the sorted elements S = list() # set of all nodes with no incoming edge # populate S with nodes lacking incoming edges for node in nodes_list: if len(node.get_prev_nodes()) == 0: S.append(node) while len(S) > 0: node_n = S.pop(0) L.append(node_n) n_children = sorted(node_n.get_next_nodes()) # make a copy instead of using the reference directly. for n_child in n_children: n_child.stash_prev_node(node_n) node_n.stash_next_node(n_child) if len(n_child.get_prev_nodes()) == 0: S.append(n_child) # see if there are cycles for node in nodes_list: if len(node.get_prev_nodes()) > 0 or len(node.get_next_nodes()) > 0: raise GraphCycleException("Graph has cycles! offending node: " + node.toString()) idx = 0 for node in L: node.restore_stashed_nodes() node.set_topological_order(idx) idx += 1 return L