I've been having a go at writing the Bellman Ford algoritm for finding the shortest path in a graph and while I've got a working solution it doesn't run very quickly and I'm led to believe it could be faster if I use numpy instead of my current approach.

This is the solution I have using for loops:

import os                    
file = open(os.path.dirname(os.path.realpath(__file__)) + "/g_small.txt")

vertices, edges = map(lambda x: int(x), file.readline().replace("\n", "").split(" "))

adjacency_list = [[] for k in xrange(vertices)]
for line in file.readlines():
    tail, head, weight = line.split(" ")
    adjacency_list[int(head)-1].append({"from" : int(tail), "weight" : int(weight)})

n = vertices

shortest_paths = []
s=2

cache = [[0 for k in xrange(vertices)] for j in xrange(vertices)]
cache[0][s] = 0

for v in range(0, vertices):
    if v != s:
    cache[0][v] = float("inf")

# this can be done with numpy I think?
for i in range(1, vertices):
    for v in range(0, vertices):
        adjacent_nodes = adjacency_list[v]

        least_adjacent_cost = float("inf")
        for node in adjacent_nodes:
            adjacent_cost = cache[i-1][node["from"]-1] + node["weight"]
            if adjacent_cost < least_adjacent_cost:
                least_adjacent_cost = adjacent_cost

        cache[i][v] = min(cache[i-1][v], least_adjacent_cost)

shortest_paths.append([s, cache[vertices-1]])

for path in shortest_paths:
    print(str(path[1]))

shortest_path = min(reduce(lambda x, y: x + y, map(lambda x: x[1], shortest_paths)))  
print("Shortest Path: " + str(shortest_path))  

The input file looks like this -> https://github.com/mneedham/algorithms2/blob/master/shortestpath/g_small.txt

It's mostly uninteresting except for the nested loops about half way down. I've tried to vectorise it using numpy but I'm not really sure how to do it given that the matrix/2D array gets changed on each iteration.

If anyone has any ideas on what I need to do or even something to read that would help me on my way that'd be awesome.

==================

I wrote an updated version to take Jaime's comment into account:

s=0

def initialise_cache(vertices, s):
    cache = [0 for k in xrange(vertices)]
    cache[s] = 0

    for v in range(0, vertices):
        if v != s:
            cache[v] = float("inf")
    return cache    

cache = initialise_cache(vertices, s)

for i in range(1, vertices):
    previous_cache = deepcopy(cache)
    cache = initialise_cache(vertices, s)
    for v in range(0, vertices):
        adjacent_nodes = adjacency_list[v]

    least_adjacent_cost = float("inf")
    for node in adjacent_nodes:
        adjacent_cost = previous_cache[node["from"]-1] + node["weight"]
        if adjacent_cost < least_adjacent_cost:
            least_adjacent_cost = adjacent_cost

    cache[v] = min(previous_cache[v], least_adjacent_cost)

================

And another new version this time using vectorisation:

def initialise_cache(vertices, s):
    cache = empty(vertices)
    cache[:] = float("inf")
    cache[s] = 0
    return cache    

adjacency_matrix = zeros((vertices, vertices))
adjacency_matrix[:] = float("inf")
for line in file.readlines():
    tail, head, weight = line.split(" ")
    adjacency_matrix[int(head)-1][int(tail)-1] = int(weight)    

n = vertices
shortest_paths = []
s=2

cache = initialise_cache(vertices, s)
for i in range(1, vertices):
    previous_cache = cache
    combined = (previous_cache.T + adjacency_matrix).min(axis=1)
    cache = minimum(previous_cache, combined)

shortest_paths.append([s, cache])
有帮助吗?

解决方案

I ended up with the following vectorised code after following Jaime's advice:

def initialise_cache(vertices, s):
    cache = empty(vertices)
    cache[:] = float("inf")
    cache[s] = 0
    return cache    

adjacency_matrix = zeros((vertices, vertices))
adjacency_matrix[:] = float("inf")
for line in file.readlines():
    tail, head, weight = line.split(" ")
    adjacency_matrix[int(head)-1][int(tail)-1] = int(weight)    

n = vertices
shortest_paths = []
s=2

cache = initialise_cache(vertices, s)
for i in range(1, vertices):
    previous_cache = cache
    combined = (previous_cache.T + adjacency_matrix).min(axis=1)
    cache = minimum(previous_cache, combined)

shortest_paths.append([s, cache])
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top