blob: e6f405cc6ab9e06ee7e5b594cd92f2bed42c96ef [file] [log] [blame]
khenaidooac637102019-01-14 15:44:34 -05001package goraph
2
3import (
4 "container/heap"
5 "fmt"
6 "math"
7)
8
9// Dijkstra returns the shortest path using Dijkstra
10// algorithm with a min-priority queue. This algorithm
11// does not work with negative weight edges.
12// (https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm)
13//
14// 0. Dijkstra(G, source, target)
15// 1.
16// 2. let Q be a priority queue
17// 3. distance[source] = 0
18// 4.
19// 5. for each vertex v in G:
20// 6.
21// 7. if v ≠ source:
22// 8. distance[v] = ∞
23// 9. prev[v] = undefined
24// 10.
25// 11. Q.add_with_priority(v, distance[v])
26// 12.
27// 13. while Q is not empty:
28// 14.
29// 15. u = Q.extract_min()
30// 16. if u == target:
31// 17. break
32// 18.
33// 19. for each child vertex v of u:
34// 20.
35// 21. alt = distance[u] + weight(u, v)
36// 22. if distance[v] > alt:
37// 23. distance[v] = alt
38// 24. prev[v] = u
39// 25. Q.decrease_priority(v, alt)
40// 26.
41// 27. reheapify(Q)
42// 28.
43// 29.
44// 30. path = []
45// 31. u = target
46// 32. while prev[u] is defined:
47// 33. path.push_front(u)
48// 34. u = prev[u]
49// 35.
50// 36. return path, prev
51//
52func Dijkstra(g Graph, source, target ID) ([]ID, map[ID]float64, error) {
53 // let Q be a priority queue
54 minHeap := &nodeDistanceHeap{}
55
56 // distance[source] = 0
57 distance := make(map[ID]float64)
58 distance[source] = 0.0
59
60 // for each vertex v in G:
61 for id := range g.GetNodes() {
62 // if v ≠ source:
63 if id != source {
64 // distance[v] = ∞
65 distance[id] = math.MaxFloat64
66
67 // prev[v] = undefined
68 // prev[v] = ""
69 }
70
71 // Q.add_with_priority(v, distance[v])
72 nds := nodeDistance{}
73 nds.id = id
74 nds.distance = distance[id]
75
76 heap.Push(minHeap, nds)
77 }
78
79 heap.Init(minHeap)
80 prev := make(map[ID]ID)
81
82 // while Q is not empty:
83 for minHeap.Len() != 0 {
84
85 // u = Q.extract_min()
86 u := heap.Pop(minHeap).(nodeDistance)
87
88 // if u == target:
89 if u.id == target {
90 break
91 }
92
93 // for each child vertex v of u:
94 cmap, err := g.GetTargets(u.id)
95 if err != nil {
96 return nil, nil, err
97 }
98 for v := range cmap {
99
100 // alt = distance[u] + weight(u, v)
101 weight, err := g.GetWeight(u.id, v)
102 if err != nil {
103 return nil, nil, err
104 }
105 alt := distance[u.id] + weight
106
107 // if distance[v] > alt:
108 if distance[v] > alt {
109
110 // distance[v] = alt
111 distance[v] = alt
112
113 // prev[v] = u
114 prev[v] = u.id
115
116 // Q.decrease_priority(v, alt)
117 minHeap.updateDistance(v, alt)
118 }
119 }
120 heap.Init(minHeap)
121 }
122
123 // path = []
124 path := []ID{}
125
126 // u = target
127 u := target
128
129 // while prev[u] is defined:
130 for {
131 if _, ok := prev[u]; !ok {
132 break
133 }
134 // path.push_front(u)
135 temp := make([]ID, len(path)+1)
136 temp[0] = u
137 copy(temp[1:], path)
138 path = temp
139
140 // u = prev[u]
141 u = prev[u]
142 }
143
144 // add the source
145 temp := make([]ID, len(path)+1)
146 temp[0] = source
147 copy(temp[1:], path)
148 path = temp
149
150 return path, distance, nil
151}
152
153// BellmanFord returns the shortest path using Bellman-Ford algorithm
154// This algorithm works with negative weight edges.
155// Time complexity is O(|V||E|).
156// (http://courses.csail.mit.edu/6.006/spring11/lectures/lec15.pdf)
157// It returns error when there is a negative-weight cycle.
158// A negatively-weighted cycle adds up to infinite negative-weight.
159//
160// 0. BellmanFord(G, source, target)
161// 1.
162// 2. distance[source] = 0
163// 3.
164// 4. for each vertex v in G:
165// 5.
166// 6. if v ≠ source:
167// 7. distance[v] = ∞
168// 8. prev[v] = undefined
169// 9.
170// 10.
171// 11. for 1 to |V|-1:
172// 12.
173// 13. for every edge (u, v):
174// 14.
175// 15. alt = distance[u] + weight(u, v)
176// 16. if distance[v] > alt:
177// 17. distance[v] = alt
178// 18. prev[v] = u
179// 19.
180// 20.
181// 21. for every edge (u, v):
182// 22.
183// 23. alt = distance[u] + weight(u, v)
184// 24. if distance[v] > alt:
185// 25. there is a negative-weight cycle
186// 26.
187// 27.
188// 28. path = []
189// 29. u = target
190// 30. while prev[u] is defined:
191// 31. path.push_front(u)
192// 32. u = prev[u]
193// 33.
194// 34. return path, prev
195//
196func BellmanFord(g Graph, source, target ID) ([]ID, map[ID]float64, error) {
197 // distance[source] = 0
198 distance := make(map[ID]float64)
199 distance[source] = 0.0
200
201 // for each vertex v in G:
202 for id := range g.GetNodes() {
203
204 // if v ≠ source:
205 if id != source {
206 // distance[v] = ∞
207 distance[id] = math.MaxFloat64
208
209 // prev[v] = undefined
210 // prev[v] = ""
211 }
212 }
213
214 prev := make(map[ID]ID)
215
216 // for 1 to |V|-1:
217 for i := 1; i <= g.GetNodeCount()-1; i++ {
218
219 // for every edge (u, v):
220 for id := range g.GetNodes() {
221
222 cmap, err := g.GetTargets(id)
223 if err != nil {
224 return nil, nil, err
225 }
226 u := id
227 for v := range cmap {
228 // edge (u, v)
229 weight, err := g.GetWeight(u, v)
230 if err != nil {
231 return nil, nil, err
232 }
233
234 // alt = distance[u] + weight(u, v)
235 alt := distance[u] + weight
236
237 // if distance[v] > alt:
238 if distance[v] > alt {
239 // distance[v] = alt
240 distance[v] = alt
241
242 // prev[v] = u
243 prev[v] = u
244 }
245 }
246
247 pmap, err := g.GetSources(id)
248 if err != nil {
249 return nil, nil, err
250 }
251 v := id
252 for u := range pmap {
253 // edge (u, v)
254 weight, err := g.GetWeight(u, v)
255 if err != nil {
256 return nil, nil, err
257 }
258
259 // alt = distance[u] + weight(u, v)
260 alt := distance[u] + weight
261
262 // if distance[v] > alt:
263 if distance[v] > alt {
264 // distance[v] = alt
265 distance[v] = alt
266
267 // prev[v] = u
268 prev[v] = u
269 }
270 }
271 }
272 }
273
274 // for every edge (u, v):
275 for id := range g.GetNodes() {
276
277 cmap, err := g.GetTargets(id)
278 if err != nil {
279 return nil, nil, err
280 }
281 u := id
282 for v := range cmap {
283 // edge (u, v)
284 weight, err := g.GetWeight(u, v)
285 if err != nil {
286 return nil, nil, err
287 }
288
289 // alt = distance[u] + weight(u, v)
290 alt := distance[u] + weight
291
292 // if distance[v] > alt:
293 if distance[v] > alt {
294 return nil, nil, fmt.Errorf("there is a negative-weight cycle: %v", g)
295 }
296 }
297
298 pmap, err := g.GetSources(id)
299 if err != nil {
300 return nil, nil, err
301 }
302 v := id
303 for u := range pmap {
304 // edge (u, v)
305 weight, err := g.GetWeight(u, v)
306 if err != nil {
307 return nil, nil, err
308 }
309
310 // alt = distance[u] + weight(u, v)
311 alt := distance[u] + weight
312
313 // if distance[v] > alt:
314 if distance[v] > alt {
315 return nil, nil, fmt.Errorf("there is a negative-weight cycle: %v", g)
316 }
317 }
318 }
319
320 // path = []
321 path := []ID{}
322
323 // u = target
324 u := target
325
326 // while prev[u] is defined:
327 for {
328 if _, ok := prev[u]; !ok {
329 break
330 }
331 // path.push_front(u)
332 temp := make([]ID, len(path)+1)
333 temp[0] = u
334 copy(temp[1:], path)
335 path = temp
336
337 // u = prev[u]
338 u = prev[u]
339 }
340
341 // add the source
342 temp := make([]ID, len(path)+1)
343 temp[0] = source
344 copy(temp[1:], path)
345 path = temp
346
347 return path, distance, nil
348}