示例#1
0
    def test_graph_copy(self):
        # Create graph
        graph = Graph()

        node_1 = Node(graph)
        node_2 = Node(graph)
        node_3 = Node(graph)
        node_4 = Node(graph)

        Branch(node_1, node_2)
        Branch(node_2, node_2)
        Branch(node_2, node_3)
        Branch(node_3, node_1)
        Branch(node_1, node_4)

        # Make copy
        graph_copy = graph.copy()

        # Assert
        nodes_original = list(graph.nodes)
        nodes_original.sort(key=lambda n: n.id)
        nodes_copy = list(graph_copy.nodes)
        nodes_copy.sort(key=lambda n: n.id)

        branches_original = list(graph.branches)
        branches_original.sort(key=lambda n: n.id)
        branches_copy = list(graph_copy.branches)
        branches_copy.sort(key=lambda n: n.id)

        for node_original, node_copy in zip(nodes_original, nodes_copy):
            self.assertTrue(self.__node_equals(node_original, node_copy))

        for branch_original, branch_copy in zip(branches_original,
                                                branches_copy):
            self.assertTrue(self.__branch_equals(branch_original, branch_copy))
示例#2
0
def simple_cycles(g: Graph) -> List[List[Branch]]:
    """Find all simple cycles in a graph"""
    # Make copy because the graph gets altered during the algorithm
    graph_copy = g.copy()
    branch_map = {}
    copy_result = list()

    # Create map to allow returning original branches
    for branch in g.branches:
        branch_map[branch.id] = branch

    # Yield every elementary cycle in python graph G exactly once
    # Expects a dictionary mapping from vertices to iterables of vertices
    def _unblock(thisnode, blocked, B):
        stack = set([thisnode])
        while stack:
            node = stack.pop()
            if node in blocked:
                blocked.remove(node)
                stack.update(B[node])
                B[node].clear()

    sccs = [(graph_copy, scc)
            for scc in strongly_connected_components(graph_copy)]
    while sccs:
        current_graph, scc = sccs.pop()
        startnode = scc.pop()
        path = [startnode.id]
        pathBranches = []
        blocked = set()
        closed = set()
        blocked.add(startnode.id)
        B = defaultdict(set)
        stack = [(startnode, list(startnode.outgoing))]
        while stack:
            thisnode, nbrs = stack[-1]
            if nbrs:
                branch = nbrs.pop()
                nextnode = branch.end
                if nextnode.id == startnode.id:
                    result = pathBranches[:]
                    result.append(branch)
                    copy_result.append(result)
                    closed.update(path)
                elif nextnode.id not in blocked:
                    path.append(nextnode.id)
                    pathBranches.append(branch)
                    stack.append((nextnode, list(nextnode.outgoing)))
                    closed.discard(nextnode.id)
                    blocked.add(nextnode.id)
                    continue
            if not nbrs:
                if thisnode.id in closed:
                    _unblock(thisnode.id, blocked, B)
                else:
                    for nbr in map(lambda x: x.end, thisnode.outgoing):
                        if thisnode.id not in B[nbr.id]:
                            B[nbr.id].add(thisnode.id)
                stack.pop()
                path.pop()
                if (pathBranches):
                    pathBranches.pop()
        startnode.remove()
        subgraph = current_graph.subgraph(set(scc))
        new_scc = strongly_connected_components(subgraph)
        sccs.extend([(subgraph, scc) for scc in new_scc])

    for loop in copy_result:
        yield list(map(lambda b: branch_map[b.id], loop))