Completed
Push — master ( 60d34b...f90dfb )
by Xianshun
01:18
created

TopologicalSortShortestPath.__init__()   A

Complexity

Conditions 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
c 1
b 0
f 0
dl 0
loc 15
rs 9.4285
1
from abc import ABCMeta, abstractmethod
2
3
from pyalgs.algorithms.commons import util
4
from pyalgs.algorithms.graphs.topological_sort import DepthFirstOrder
5
from pyalgs.data_structures.commons.priority_queue import IndexMinPQ
6
from pyalgs.data_structures.commons.stack import Stack
7
from pyalgs.data_structures.graphs.graph import Digraph, Graph, EdgeWeightedGraph
8
9
10
class ShortestPath(object):
11
    __metaclass__ = ABCMeta
12
13
    @abstractmethod
14
    def shortestPathTo(self, v):
15
        pass
16
17
    @abstractmethod
18
    def hasPathTo(self, v):
19
        pass
20
21
    @abstractmethod
22
    def path_length_to(self, v):
23
        pass
24
25
26
class DijkstraShortestPath(ShortestPath):
27
28
    edgeTo = None
29
    s = 0
30
    pq = None
31
    cost = None
32
33
    def __init__(self, G, s):
34
        if isinstance(G, Graph):
35
            raise ValueError('Graph must be edge weighted')
36
        if isinstance(G, Digraph):
37
            raise ValueError('Graph must be edge weighted')
38
        if isinstance(G, EdgeWeightedGraph):
39
            G = G.to_edge_weighted_digraph()
40
41
        vertex_count = G.vertex_count()
42
        self.pq = IndexMinPQ(vertex_count)
43
        self.s = s
44
45
        self.marked = [False] * vertex_count
46
        self.edgeTo = [None] * vertex_count
47
        self.cost = [float("inf")] * vertex_count
48
49
        self.cost[s] = 0
50
        self.pq.insert(s, 0.0)
51
52
        while not self.pq.is_empty():
53
            v = self.pq.del_min()
54
            self.marked[v] = True
55
            for e in G.adj(v):
56
                self.relax(e)
57
58
    def relax(self, e):
59
        v = e.start()
60
        w = e.end()
61
        if self.cost[w] > self.cost[v] + e.weight:
62
            self.cost[w] = self.cost[v] + e.weight
63
            self.edgeTo[w] = e
64
            if self.pq.contains_index(w):
65
                self.pq.decrease_key(w, self.cost[w])
66
            else:
67
                self.pq.insert(w, self.cost[w])
68
69
    def hasPathTo(self, v):
70
        return self.marked[v]
71
72
    def shortestPathTo(self, v):
73
        path = Stack.create()
74
        x = v
75
        while x != self.s:
76
            path.push(self.edgeTo[x])
77
            x = self.edgeTo[x].start()
78
79
        return path.iterate()
80
81
    def path_length_to(self, v):
82
        return self.cost[v]
83
84
85
class TopologicalSortShortestPath(ShortestPath):
86
87
    marked = None
88
    edgeTo = None
89
    cost = None
90
    s = 0
91
92
    def __init__(self, G, s):
93
        vertex_count = G.vertex_count()
94
        self.marked = [False] * vertex_count
95
        self.edgeTo = [None] * vertex_count
96
        self.cost = [float('inf')] * vertex_count
97
        self.s = s
98
99
        dfo = DepthFirstOrder(G)
100
        orders = dfo.postOrder()
101
102
        self.cost[s] = 0
103
104
        for v in orders:
105
            for e in G.adj(v):
106
                self.relax(e)
107
108
    def relax(self, e):
109
        v = e.start()
110
        w = e.end()
111
        if self.cost[w] > self.cost[v] + e.weight:
112
            self.cost[w] = self.cost[v] + e.weight
113
            self.edgeTo[w] = e
114
            self.marked[w] = True
115
116
    def shortestPathTo(self, v):
117
        path = Stack.create()
118
        x = v
119
        while x != self.s:
120
            path.push(self.edgeTo[x])
121
            x = self.edgeTo[x].start()
122
123
        return path.iterate()
124
125
    def hasPathTo(self, v):
126
        return self.marked[v]
127
128
    def path_length_to(self, v):
129
        return self.cost[v]