使用networkx返回负循环

时间:2017-03-18 23:36:15

标签: python graph-theory networkx bellman-ford

我正在玩sukses并注意到networkx算法没有返回负循环,而是提升bellman_ford

如何返回第一个负循环而不是异常?

unbounded exception

此外,我用bellman_ford测试套利交易

谢谢,

3 个答案:

答案 0 :(得分:2)

这是因为Bellman-Ford算法从单个源返回所有节点的最短路径。但是,如果存在任何负循环,则没有从源顶点到所有节点的最短路径(例如,该循环中的每个节点都没有最短路径,因为您可以再次迭代循环并获得较低的加权路径)。

你可能做的是使用nx.simple_cycles。它的作用是返回一个简单循环的生成器,即图中不同的循环而不重复节点(当然除了第一个和最后一个)。 然后,您可以迭代生成的输出并检查负循环。

我想它看起来像这样:

#import networx as nx
import networkx as nx
def find_path(digraph, start="USD"):
    try:
        path = nx.bellman_ford(digraph, start) 
        return path
    except NetworkXUnbounded:
        cycles = nx.simple_cycles(digraph)
        for cycle in cycles:
            print cycle  # do whatever you prefer here of course

我没有尝试过。

答案 1 :(得分:0)

您仍然可以使用Bellman-Ford。在这里,我将finding-negative-cycle-in-graph的代码改编成python,并添加了一个正在运行的示例。

import matplotlib.pyplot as plt
import networkx as nx
import numpy as np


def getW(edge):
    return edge[2]['weight']


def getNegativeCycle(g):
    n = len(g.nodes())
    edges = list(g.edges().data())
    d = np.ones(n) * 10000
    p = np.ones(n)*-1
    x = -1
    for i in range(n):        
        for e in edges:
            if d[int(e[0])] + getW(e) < d[int(e[1])]:
                d[int(e[1])] = d[int(e[0])] + getW(e)
                p[int(e[1])] = int(e[0])
                x = int(e[1])
    if x == -1:
        print("No negative cycle")
        return None
    for i in range(n):
        x = p[int(x)]
    cycle = []
    v = x
    while True:
        cycle.append(str(int(v)))
        if v == x and len(cycle) > 1:
            break
        v = p[int(v)]
    return list(reversed(cycle))


G = nx.DiGraph()
G.add_edge('0', '1', weight=0.1)
G.add_edge('1', '2', weight=-1)
G.add_edge('2', '3', weight=-0.3)
G.add_edge('3', '0', weight=-0.4)
G.add_edge('4', '3', weight=0.7)
G.add_edge('4', '5', weight=0.9)
G.add_edge('3', '5', weight=-5)

cycle = getNegativeCycle(G)

这将输出一个负循环:

cycle
Out[68]: ['2', '3', '0', '1', '2']

请注意,为简单起见(数组位置),我使用的是数字顶点。

答案 2 :(得分:0)

因此,修改Or Dinari的代码以使用任意权重函数,例如networkx的其余部分...

def negative_cycle(g, weight_func=burns_advanced):
    n = len(g.nodes())
    d = defaultdict(lambda: 10000)
    p = defaultdict(lambda: -1)
    x = -1

    for i in range(n):
        for u, v in g.edges():
            weight = weight_func(u, v, g[u][v])
            if d[u] + weight < d[v]:
                d[v] = d[u] + weight
                p[v] = u
                x = v

    if x == -1:
        print('No negative cycle')
        return None

    for i in range(n):
        x = p[x]

    cycle = []
    v = x

    while True:
        cycle.append(v)
        if v == x and len(cycle) > 1:
            break
        v = p[v]

    return list(reversed(cycle))

像魅力一样工作!无论如何,我都会给您赏金,因为参考确实是我所需要的。谢谢!