【问题标题】:Calculate number of jumps in Dijkstra's algorithm?计算 Dijkstra 算法中的跳跃次数?
【发布时间】:2014-03-19 21:01:05
【问题描述】:

numpy 中计算 dijkstra 算法使用的跳跃次数的最快方法是什么?我有一个 10000x10000 元素连接矩阵并使用 scipy.sparse.csgraph.dijkstra 来计算填充距离矩阵和前驱矩阵。我的幼稚解决方案如下:

import numpy as np
from numpy.random import rand
from scipy.sparse.csgraph import dijkstra

def dijkway(dijkpredmat, i, j):
    """calculate the path between two nodes in a dijkstra matrix"""
    wayarr = []
    while (i != j) & (j >= 0):
        wayarr.append(j)
        j = dijkpredmat[i,j]
    return np.array(wayarr)

def jumpvec(pmat,node):
    """calculate number of jumps from one node to all others"""
    jumps = np.zeros(len(pmat))
    jumps[node] = -999
    while 1:
        try:
            rvec = np.nonzero(jumps==0)[0]
            r = rvec.min()
            dway = dijkway(pmat, node, r)
            jumps[dway] = np.arange(len(dway),0,-1)
        except ValueError:
            break
    return jumps

#Create a matrix
mat = (rand(500,500)*20)
mat[(rand(50000)*500).astype(int), (rand(50000)*500).astype(int)] = np.nan
dmat,pmat = dijkstra(mat,return_predecessors=True)

timeit jumpvec(pmat,300)
In [25]: 10 loops, best of 3: 51.5 ms per loop

~50msek/node 是可以的,但是将距离矩阵扩展到 10000 个节点会将时间增加到~2sek/node。 jumpvec 也必须执行 10000 次......

【问题讨论】:

  • 对于那些想在不查看您的 python 代码的情况下回答的人,通过计算 Dijkstra 算法使用的“跳跃次数”可能有助于解释您的意思。
  • 当然! Dijkstra 算法通过其他节点使用中间步骤来计算两个节点之间的最短距离。例如:A 和 C 之间的距离是 5,A 和 B 之间的距离是 2,B 和 C 之间的距离是 2。那么走 A->B->C 而不是直接走 A->C 会更短。第一种情况下的跳跃次数为 2,第二种情况下为 1。
  • @brorfred:我可能遗漏了一些东西,但似乎跳跃次数可以简单地解决为具有未加权图的 dijkstra 的一个特例,顺便说一下,可以用广度优先搜索(无需像 dijkstra 那样重新访问旧节点)。

标签: python algorithm numpy graph-theory dijkstra


【解决方案1】:

这是一个(渐近最优)O(n) 算法。

创建一组未访问的顶点,最初是除了源顶点之外的所有顶点。将源的跳转向量条目初始化为 0。当集合不为空时,弹出一个元素 v。使用前驱矩阵,将 v 和每个后续祖先收集到一个列表中,直到找到一个已经访问过的祖先。以相反的顺序遍历列表,将每个节点 w 的跳转向量条目设置为其父节点的条目加 1,然后从集合中删除 w。

【讨论】:

    【解决方案2】:

    以下代码可以在我的 PC 上加速 4 倍,它更快是因为:

    • 使用ndarray.item() 从数组中获取值。
    • 使用集合对象保存未处理的索引。
    • 不要在 while 循环中创建 numpy.arange()

    Python 代码:

    def dijkway2(dijkpredmat, i, j):
        wayarr = []
        while (i != j) & (j >= 0):
            wayarr.append(j)
            j = dijkpredmat.item(i,j)
        return wayarr
    
    def jumpvec2(pmat,node):
        jumps = np.zeros(len(pmat))
        jumps[node] = -999
        todo = set()
        for i in range(len(pmat)):
            if i != node:
                todo.add(i)
    
        indexs = np.arange(len(pmat), 0, -1)
        while todo:
            r = todo.pop()
            dway = dijkway2(pmat, node, r)
            jumps[dway] = indexs[-len(dway):]
            todo -= set(dway)
        return jumps
    

    为了进一步加快速度,您可以使用 cython:

    import numpy as np
    cimport numpy as np
    import cython
    
    @cython.wraparound(False)
    @cython.boundscheck(False)
    cpdef dijkway3(int[:, ::1] m, int i, int j):
        cdef list wayarr = []
        while (i != j) & (j >= 0):
            wayarr.append(j)
            j = m[i,j]
        return wayarr
    
    @cython.wraparound(False)
    @cython.boundscheck(False)
    def jumpvec3(int[:, ::1] pmat, int node):
        cdef np.ndarray jumps
        cdef int[::1] jumps_buf
        cdef int i, j, r, n
        cdef list dway
        jumps = np.zeros(len(pmat), int)
        jumps_buf = jumps
        jumps[node] = -999
    
        for i in range(len(jumps)):
            if jumps_buf[i] != 0:
                continue
            r = i
            dway = dijkway3(pmat, node, r)
            n = len(dway)
            for j in range(n):
                jumps_buf[<int>dway[j]] = n - j
        return jumps
    

    这是我的测试,cython 版本快 80 倍:

    %timeit jumpvec3(pmat,1)
    %timeit jumpvec2(pmat, 1)
    %timeit jumpvec(pmat, 1)
    

    输出:

    1000 loops, best of 3: 138 µs per loop
    100 loops, best of 3: 2.81 ms per loop
    100 loops, best of 3: 10.8 ms per loop
    

    【讨论】:

    • 哇,第一个示例的加速对于较大的矩阵更为显着——11000 个节点的速度提高了一个数量级。非常感谢您的建议!我认为我将不得不花更多时间在 python 上......
    猜你喜欢
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    • 2015-11-30
    • 2019-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多