-1

This is my implementation of the Floyd Warshall algorithm:

def algorithm(self, graph):
    nodes = graph.keys()
    shuffle(nodes, lambda : 0.5)

    int_nodes = range(len(nodes))
    arcs = set((a,b) for a in nodes for b in graph[a])

    distances = {} 
    for i in int_nodes:
        distances[(i, i, 0)] = 0

    for i in int_nodes:
        for j in int_nodes:
            distances[(i, j, 0)] = 1 if (nodes[i], nodes[j]) in arcs else float("inf")

    for k in range(1, len(nodes)):
        for i in int_nodes:
            for j in int_nodes:
                distances[(i, j, k)] = min(distances[(i, j, k-1)], distances[(i, k, k-1)] + distances[(k, j, k-1)])


    return {(nodes[i], nodes[j]): distances[(i, j, len(nodes)-1)] for i in int_nodes for j in int_nodes}

If I change the seed of the shuffle, the results sometimes change.

Why does it happen?

edit.

Here a minimal working example:

from random import shuffle

def algorithm(graph, n):
nodes = graph.keys()
shuffle(nodes, lambda : n)

int_nodes = range(len(nodes))
arcs = set((a,b) for a in nodes for b in graph[a])

distances = {} 
for i in int_nodes:
    distances[(i, i, 0)] = 0

for i in int_nodes:
    for j in int_nodes:
        distances[(i, j, 0)] = 1 if (nodes[i], nodes[j]) in arcs else float("inf")

for k in range(1, len(nodes)):
    for i in int_nodes:
        for j in int_nodes:
            distances[(i, j, k)] = min(distances[(i, j, k-1)], distances[(i, k, k-1)] + distances[(k, j, k-1)])


return {(nodes[i], nodes[j]): distances[(i, j, len(nodes)-1)] for i in int_nodes for j in int_nodes}

if __name__ == "__main__":
graph = {'Z': ['B', 'H', 'G', 'O', 'I'], 'F': ['C', 'G', 'D', 'O'], 'L': ['M', 'C', 'D', 'E', 'H'], 'C': ['F', 'G', 'B', 'L', 'M', 'I'], 'B': ['C', 'Z', 'I', 'O', 'H', 'G'], 'D': ['F', 'L', 'G', 'M', 'E'], 'E': ['L', 'D', 'G', 'M'], 'H': ['B', 'L', 'Z', 'I', 'O'], 'G': ['C', 'F', 'D', 'E', 'Z', 'B'], 'O': ['B', 'H', 'F', 'I', 'Z'], 'M': ['L', 'D', 'E', 'C'], 'I': ['B', 'H', 'O', 'Z', 'C']}

for i in [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]:
    dis1 = algorithm(graph,i )
    print sum(dis1.values())

And this is the output:

244
246
244
244
242
242
242
242
242

The total leght should be the same, but it changes as the seed changes.

jophab
  • 5,356
  • 14
  • 41
  • 60
Luca
  • 801
  • 1
  • 6
  • 11
  • 1
    Simply because there can be multiple solutions to the problem and the algorithm searches in a certain order and thus with different configurations, the search is a bit different and thus the result as well. – Willem Van Onsem Jan 19 '17 at 21:09
  • But the minimal distances should be the same, or no? Sometimes it doesn't find the shortest path for certain couples of nodes. I found the problem because, say in the dictionary D, the distance between node A and B is 2. If I copy D with dict(D) the order of the keys change, and the distance between A and B become 3. – Luca Jan 19 '17 at 21:12
  • Welcome to StackOverflow. Please read and follow the posting guidelines in the help documentation. [Minimal, complete, verifiable example](http://stackoverflow.com/help/mcve) applies here. We cannot effectively help you until you post your MCVE code and accurately describe the problem. Your posted code doesn't execute, and you've shown no output. – Prune Jan 19 '17 at 21:14
  • @Nopaste: indeed, if that ain't the case, something is wrong with your algorithm, but returning a different equivalent path is acceptable. I will take a look at your program :) – Willem Van Onsem Jan 19 '17 at 21:15
  • @WillemVanOnsem Thanks! I updated the post with a MCVE. Finding the problem was hard enough, but to me the algorithm should work perfectly fine and I can't really understand why it doesn't. I'll try to look more into it :) – Luca Jan 19 '17 at 21:36
  • @user2357112 I didn't know that, thanks! – Luca Jan 19 '17 at 21:45

1 Answers1

1

Your final set of loops is not considering k=0, and it should, otherwise you omit paths of form a->0->b in your search. In general the idea of using k to index both nodes and iteration is a bit odd (and makes debugging harder).

You could easily fix it by

from random import shuffle

def algorithm(graph, n):
  nodes = graph.keys()
  shuffle(nodes, lambda : n)

  int_nodes = range(len(nodes))
  arcs = set((a,b) for a in nodes for b in graph[a])

  distances = {} 
  for i in int_nodes:
      distances[(i, i, -1)] = 0

  for i in int_nodes:
      for j in int_nodes:
          distances[(i, j, -1)] = 1 if (nodes[i], nodes[j]) in arcs else float("inf")

  for k in int_nodes:
      for i in int_nodes:
          for j in int_nodes:
              distances[(i, j, k)] = min(distances[(i, j, k-1)], distances[(i, k, k-1)] + distances[(k, j, k-1)])


  return {(nodes[i], nodes[j]): distances[(i, j, len(nodes)-1)] for i in int_nodes for j in int_nodes}

if __name__ == "__main__":
  graph = {'Z': ['B', 'H', 'G', 'O', 'I'], 'F': ['C', 'G', 'D', 'O'], 'L': ['M', 'C', 'D', 'E', 'H'], 'C': ['F', 'G', 'B', 'L', 'M', 'I'], 'B': ['C', 'Z', 'I', 'O', 'H', 'G'], 'D': ['F', 'L', 'G', 'M', 'E'], 'E': ['L', 'D', 'G', 'M'], 'H': ['B', 'L', 'Z', 'I', 'O'], 'G': ['C', 'F', 'D', 'E', 'Z', 'B'], 'O': ['B', 'H', 'F', 'I', 'Z'], 'M': ['L', 'D', 'E', 'C'], 'I': ['B', 'H', 'O', 'Z', 'C']}

  for i in [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]:
      dis1 = algorithm(graph,i )
      print sum(dis1.values())

which gives

238
238
238
238
238
238
238
238
238
lejlot
  • 64,777
  • 8
  • 131
  • 164