Example #1
0
def loops(node, type_):
    '''
    Return all loops from the given node.
    
    Each loop is a list that starts and ends with the given node.
    '''
    stack = [[node]]
    known = {node} # avoid getting lost in sub-loops
    while stack:
        ancestors = stack.pop()
        parent = ancestors[-1]
        if isinstance(parent, type_):
            for child in parent:
                family = list(ancestors)
                family.append(child)
                if child is node:
                    yield family
                else:
                    if not safe_in(child, known):
                        stack.append(family)
                        known = fallback_add(known, child)
Example #2
0
def loops(node, type_):
    '''
    Return all loops from the given node.
    
    Each loop is a list that starts and ends with the given node.
    '''
    stack = [[node]]
    known = set([node])  # avoid getting lost in sub-loops
    while stack:
        ancestors = stack.pop()
        parent = ancestors[-1]
        if isinstance(parent, type_):
            for child in parent:
                family = list(ancestors)
                family.append(child)
                if child is node:
                    yield family
                else:
                    if not safe_in(child, known):
                        stack.append(family)
                        safe_add(known, child)
Example #3
0
 def __call__(self, visitor):
     '''
     Apply the visitor to the nodes in the graph, in postorder.
     '''
     pending = {}
     for (parent, node, kind) in dfs_edges(self.__root, self.__type):
         if kind & POSTORDER:
             if safe_in(node, pending):
                 args = pending[node]
                 del pending[node]
             else:
                 args = []
             if parent not in pending:
                 pending[parent] = []
             visitor.node(node)
             if kind & LEAF:
                 pending[parent].append(visitor.leaf(node))
             elif kind & NON_TREE:
                 pending[parent].append(visitor.loop(node))
             else:
                 pending[parent].append(visitor.constructor(*args))
     return pending[self.__root][0]
Example #4
0
 def __call__(self, visitor):
     '''
     Apply the visitor to the nodes in the graph, in postorder.
     '''
     pending = {}
     for (parent, node, kind) in dfs_edges(self.__root, self.__type):
         if kind & POSTORDER:
             if safe_in(node, pending):
                 args = pending[node]
                 del pending[node]
             else:
                 args = []
             if parent not in pending:
                 pending[parent] = []
             visitor.node(node)
             if kind & LEAF:
                 pending[parent].append(visitor.leaf(node))
             elif kind & NON_TREE:
                 pending[parent].append(visitor.loop(node))
             else:
                 pending[parent].append(visitor.constructor(*args))
     return pending[self.__root][0]
Example #5
0
def dfs_edges(node, type_):
    '''
    Iterative DFS, based on http://www.ics.uci.edu/~eppstein/PADS/DFS.py
    
    Returns forward and reverse edges.  Also returns root node in correct 
    order for pre- (FORWARD) and post- (BACKWARD) ordering.

    ``type_`` selects which values are iterated over.  Children which are
    not of this type are flagged with LEAF.
    '''
    while isinstance(node, type_):
        try:
            stack = [(node, iter(node), ROOT)]
            yield node, node, FORWARD | ROOT
            visited = set()
            visited = fallback_add(visited, node)
            while stack:
                parent, children, p_type = stack[-1]
                try:
                    child = next(children)
                    if isinstance(child, type_):
                        if safe_in(child, visited, False):
                            yield parent, child, NON_TREE
                        else:
                            stack.append((child, iter(child), NODE))
                            yield parent, child, FORWARD | NODE
                            visited = fallback_add(visited, child)
                    else:
                        stack.append((child, empty(), LEAF))
                        yield parent, child, FORWARD | LEAF
                except StopIteration:
                    stack.pop()
                    if stack:
                        yield stack[-1][0], parent, BACKWARD | p_type
            yield node, node, BACKWARD | ROOT
            return
        except Reset:
            yield # in response to the throw (ignored by caller)
Example #6
0
def dfs_edges(node, type_):
    '''
    Iterative DFS, based on http://www.ics.uci.edu/~eppstein/PADS/DFS.py
    
    Returns forward and reverse edges.  Also returns root node in correct 
    order for pre- (FORWARD) and post- (BACKWARD) ordering.

    ``type_`` selects which values are iterated over.  Children which are
    not of this type are flagged with LEAF.
    '''
    while isinstance(node, type_):
        try:
            stack = [(node, iter(node), ROOT)]
            yield node, node, FORWARD | ROOT
            visited = set()
            safe_add(visited, node)  # cannot track loops in unhashable objects
            while stack:
                parent, children, ptype = stack[-1]
                try:
                    child = next(children)
                    if isinstance(child, type_):
                        if safe_in(child, visited, False):
                            yield parent, child, NONTREE
                        else:
                            stack.append((child, iter(child), NODE))
                            yield parent, child, FORWARD | NODE
                            safe_add(visited, child)
                    else:
                        stack.append((child, empty(), LEAF))
                        yield parent, child, FORWARD | LEAF
                except StopIteration:
                    stack.pop()
                    if stack:
                        yield stack[-1][0], parent, BACKWARD | ptype
            yield node, node, BACKWARD | ROOT
            return
        except Reset:
            yield  # in response to the throw (ignored by caller)