-
Notifications
You must be signed in to change notification settings - Fork 5
/
shortest_paths.py
109 lines (92 loc) · 3.63 KB
/
shortest_paths.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
'''
Created on Aug 7, 2014
@author: jeromethai
'''
import numpy as np
def Dijkstra(graph, sink, sources=None):
"""Find the shortest path in ffdelays to sink from every other vertex
Stops when the shortest path form sources to sink have been found
(see http://en.wikipedia.org/wiki/Dijkstra_algorithm)
Return value:
-------------
dist: dist[u] = distance from u to sink
next: next[u] = next node in the shortest path from u to sink
"""
n = graph.numnodes
dist = {k+1:np.inf for k in range(n)}
next = {k+1:None for k in range(n)}
dist[sink] = 0.0
S, Q = list(sources[:]), range(1,n+1)
while len(Q)>0:
min = np.inf
for v in Q:
if dist[v] < min: u=v; min = dist[v]
if min == np.inf: return dist, next
for s in S:
if u == s: S.remove(u)
if len(S)==0: return dist,next
Q.remove(u)
for link in graph.nodes[u].inlinks.values():
v, alt = link.startnode, dist[u] + link.delay
if alt < dist[v]: dist[v] = alt; next[v] = u
return dist, next
def get_path(source, sink, next):
"""Get shortest path from source to sink from next (given by output of Dijkstra)
Return value:
-------------
Shortest path: list of nodes
"""
u, path = source, [source]
while u != sink: u=next[u]; path.append(u)
return path
def mainKSP(graph, sources, sink, K):
"""Find the K-shortest paths from sources to sink
Return value:
-------------
As: dictionary s.t. As[s]=[K-shortest paths from s to sink for s in sources]
"""
dist, next = Dijkstra(graph, sink, sources)
A0s = {s:get_path(s, sink, next) for s in sources}
return {s : YenKSP(graph, s, sink, K, A0s[s]) for s in sources}
def YenKSP(graph, source, sink, K, A0):
""""Find the k-shortest paths from source to sink
A0: initialization with the shortest path from source to sink
{see http://en.wikipedia.org/wiki/Yen's_algorithm}
"""
A, B, costs, j, tmp, k2 = [A0], {}, {}, 0, {}, 0
for k in range(K-1):
for i in range(len(A[k2])-1):
spurNode, rootPath = A[k2][i], A[k2][:i+1]
costRootPath = 0
for l in range(i):
costRootPath += graph.links[(A[k2][l],A[k2][l+1],1)].delay
for p in A:
if rootPath == p[:i+1]:
if (p[i],p[i+1],1) not in tmp.keys():
link = graph.links[(p[i],p[i+1],1)]
tmp[(p[i],p[i+1],1)] = link.delay #save p.edge(i, i + 1)
link.delay = np.inf #remove p.edge(i, i + 1)
for node in rootPath:
for link in graph.nodes[node].inlinks.values():
if (link.startnode,node,1) not in tmp.keys():
tmp[(link.startnode,node,1)] = link.delay #save edge
link.delay = np.inf #remove edge
dist, next = Dijkstra(graph, sink, [spurNode])
cost = costRootPath + dist[spurNode]
if dist[spurNode] < np.inf and cost not in costs.values():
B[j] = rootPath[:-1] + get_path(spurNode, sink, next)
costs[j] = cost
j += 1
for id,delay in tmp.items(): graph.links[id].delay = delay
tmp = {}
if len(B) == 0: break
min_cost = min(costs.values())
for key,cost in costs.items():
if cost == min_cost:
A.append(B[key]); k2+=1
del costs[key]
del B[key]
break
return A
if __name__ == '__main__':
pass