如何修改Johnson算法以在文本文件中打印所有图形循环

时间:2017-12-26 22:52:19

标签: python python-3.x algorithm graph networkx

我想修改Johnson算法的networkx实现(https://networkx.github.io/documentation/networkx-1.10/_modules/networkx/algorithms/cycles.html#simple_cycles),以查找图中的所有基本周期(也在下面复制)并将其打印在文本文件中。我想做这个修改,因为我使用大图,我得到一个内存错误,因为保存周期的列表是巨大的。

def simple_cycles(G):

    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()

    # Johnson's algorithm requires some ordering of the nodes.
    # We assign the arbitrary ordering given by the strongly connected comps
    # There is no need to track the ordering as each node removed as processed.
    subG = type(G)(G.edges_iter()) # save the actual graph so we can mutate it here
                              # We only take the edges because we do not want to
                              # copy edge and node attributes here.
    sccs = list(nx.strongly_connected_components(subG))
    while sccs:
        scc=sccs.pop()
        # order of scc determines ordering of nodes
        startnode = scc.pop()
        # Processing node runs "circuit" routine from recursive version
        path=[startnode]
        blocked = set() # vertex: blocked from search?
        closed = set() # nodes involved in a cycle
        blocked.add(startnode)
        B=defaultdict(set) # graph portions that yield no elementary circuit
        stack=[ (startnode,list(subG[startnode])) ]  # subG gives component nbrs
        while stack:
            thisnode,nbrs = stack[-1]
            if nbrs:
                nextnode = nbrs.pop()
#                    print thisnode,nbrs,":",nextnode,blocked,B,path,stack,startnode
#                    f=raw_input("pause")
                if nextnode == startnode:
                    yield path[:]
                    closed.update(path)
#                        print "Found a cycle",path,closed
                elif nextnode not in blocked:
                    path.append(nextnode)
                    stack.append( (nextnode,list(subG[nextnode])) )
                    closed.discard(nextnode)
                    blocked.add(nextnode)
                    continue
            # done with nextnode... look for more neighbors
            if not nbrs:  # no more nbrs
                if thisnode in closed:
                    _unblock(thisnode,blocked,B)
                else:
                    for nbr in subG[thisnode]:
                        if thisnode not in B[nbr]:
                            B[nbr].add(thisnode)
                stack.pop()
#                assert path[-1]==thisnode
                path.pop()
        # done processing this node
        subG.remove_node(startnode)
        H=subG.subgraph(scc)  # make smaller to avoid work in SCC routine
        sccs.extend(list(nx.strongly_connected_components(H)))

当然,我也接受一个与上述实施不同但在相似时间内运行的建议。此外,我的项目使用networkx,因此可以随意使用该库中的任何其他功能

1 个答案:

答案 0 :(得分:1)

networkx.simple_cycles()函数已经是一个生成器。你可以迭代循环并将它们打印到像这样的文件

In [1]: import networkx as nx

In [2]: G = nx.cycle_graph(5).to_directed()

In [3]: with open('foo','w') as f:
   ...:     for c in nx.simple_cycles(G):
   ...:         print(c, file=f)
   ...:         

In [4]: cat foo
[0, 4]
[0, 4, 3, 2, 1]
[0, 1, 2, 3, 4]
[0, 1]
[1, 2]
[2, 3]
[3, 4]