我想修改Johnson的networkx implementation算法,以便在图表中找到所有基本周期(也在下面复制),这样就不会搜索更大的周期超过一些最大长度。
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,因此可以随意使用该库中的任何其他功能,例如shortest_path
。
(注意:不要做作业!)
Dorijan Cirkveni建议(如果我理解正确的话):
if len(blocked) >= limit + 1:
continue
elif nextnode == startnode:
yield path[:]
但是,这不起作用。这是一个反例:
G = nx.DiGraph()
G.add_edge(1, 2)
G.add_edge(2, 3)
G.add_edge(3, 1)
G.add_edge(3, 2)
G.add_edge(3, 4)
my_cycles = list(simple_cycles(G, limit = 3)) # Modification
nx_cycles = list(nx.simple_cycles(G)) # Original networkx code
print("MY:", my_cycles)
print("NX:", nx_cycles)
将输出
MY: [[2, 3]]
NX: [[1, 2, 3], [2, 3]]
此外,如果我们将blocked
替换为stack
或path
,则此示例的结果将是正确的,但会为其他图表提供错误的答案。
答案 0 :(得分:0)
这是此代码的高度修改版本,但至少它正在运行。
def simple_cycles(G, limit):
subG = type(G)(G.edges())
sccs = list(nx.strongly_connected_components(subG))
while sccs:
scc = sccs.pop()
startnode = scc.pop()
path = [startnode]
blocked = set()
blocked.add(startnode)
stack = [(startnode, list(subG[startnode]))]
while stack:
thisnode, nbrs = stack[-1]
if nbrs and len(path) < limit:
nextnode = nbrs.pop()
if nextnode == startnode:
yield path[:]
elif nextnode not in blocked:
path.append(nextnode)
stack.append((nextnode, list(subG[nextnode])))
blocked.add(nextnode)
continue
if not nbrs or len(path) >= limit:
blocked.remove(thisnode)
stack.pop()
path.pop()
subG.remove_node(startnode)
H = subG.subgraph(scc)
sccs.extend(list(nx.strongly_connected_components(H)))
答案 1 :(得分:-1)
你只需要改变两件事:
定义行(显然)
def simple_cycles(G,limit):
在下一个节点处理器的某处添加覆盖条件(示例如下:)
...
if blocked.size>=limit+1:
pass
elif if nextnode == startnode:
yield path[:] ...
奖励:使用==
代替>=
将导致函数运行,因为使用负值时没有限制,而不是返回任何节点。