1
|
|
|
from abc import ABCMeta, abstractmethod |
2
|
|
|
|
3
|
|
|
from pyalgs.algorithms.commons import util |
4
|
|
|
from pyalgs.data_structures.commons.priority_queue import IndexMinPQ |
5
|
|
|
from pyalgs.data_structures.commons.stack import Stack |
6
|
|
|
from pyalgs.data_structures.graphs.graph import Digraph, Graph, EdgeWeightedGraph |
7
|
|
|
|
8
|
|
|
|
9
|
|
|
class ShortestPath(object): |
10
|
|
|
__metaclass__ = ABCMeta |
11
|
|
|
|
12
|
|
|
@abstractmethod |
13
|
|
|
def shortestPathTo(self, v): |
14
|
|
|
pass |
15
|
|
|
|
16
|
|
|
@abstractmethod |
17
|
|
|
def hasPathTo(self, v): |
18
|
|
|
pass |
19
|
|
|
|
20
|
|
|
|
21
|
|
|
class DijkstraShortestPath(ShortestPath): |
22
|
|
|
|
23
|
|
|
edgeTo = None |
24
|
|
|
s = 0 |
25
|
|
|
pq = None |
26
|
|
|
cost = None |
27
|
|
|
|
28
|
|
|
def __init__(self, G, s): |
29
|
|
|
if isinstance(G, Graph): |
30
|
|
|
raise ValueError('Graph must be edge weighted') |
31
|
|
|
if isinstance(G, Digraph): |
32
|
|
|
raise ValueError('Graph must be edge weighted') |
33
|
|
|
if isinstance(G, EdgeWeightedGraph): |
34
|
|
|
G = G.to_edge_weighted_digraph() |
35
|
|
|
|
36
|
|
|
vertex_count = G.vertex_count() |
37
|
|
|
self.pq = IndexMinPQ(vertex_count) |
38
|
|
|
self.s = s |
39
|
|
|
|
40
|
|
|
self.marked = [False] * vertex_count |
41
|
|
|
self.edgeTo = [None] * vertex_count |
42
|
|
|
self.cost = [float("inf")] * vertex_count |
43
|
|
|
|
44
|
|
|
self.cost[s] = 0 |
45
|
|
|
self.pq.insert(s, 0.0) |
46
|
|
|
|
47
|
|
|
while not self.pq.is_empty(): |
48
|
|
|
v = self.pq.del_min() |
49
|
|
|
self.marked[v] = True |
50
|
|
|
for e in G.adj(v): |
51
|
|
|
self.relax(e) |
52
|
|
|
|
53
|
|
|
def relax(self, e): |
54
|
|
|
v = e.start() |
55
|
|
|
w = e.end() |
56
|
|
|
if self.cost[w] > self.cost[v] + e.weight: |
57
|
|
|
self.cost[w] = self.cost[v] + e.weight |
58
|
|
|
self.edgeTo[w] = e |
59
|
|
|
if self.pq.contains_index(w): |
60
|
|
|
self.pq.decrease_key(w, self.cost[w]) |
61
|
|
|
else: |
62
|
|
|
self.pq.insert(w, self.cost[w]) |
63
|
|
|
|
64
|
|
|
def hasPathTo(self, v): |
65
|
|
|
return self.marked[v] |
66
|
|
|
|
67
|
|
|
def shortestPathTo(self, v): |
68
|
|
|
path = Stack.create() |
69
|
|
|
x = v |
70
|
|
|
while x != self.s: |
71
|
|
|
path.push(self.edgeTo[x]) |
72
|
|
|
x = self.edgeTo[x].start() |
73
|
|
|
|
74
|
|
|
return path.iterate() |
75
|
|
|
|
76
|
|
|
def path_length_to(self, v): |
77
|
|
|
return self.cost[v] |
78
|
|
|
|