github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/path/bellman_ford_moore.go (about) 1 // Copyright ©2015 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package path 6 7 import ( 8 "github.com/jingcheng-WU/gonum/graph" 9 "github.com/jingcheng-WU/gonum/graph/internal/linear" 10 "github.com/jingcheng-WU/gonum/graph/traverse" 11 ) 12 13 // BellmanFordFrom returns a shortest-path tree for a shortest path from u to all nodes in 14 // the graph g, or false indicating that a negative cycle exists in the graph. If the graph 15 // does not implement Weighted, UniformCost is used. 16 // 17 // If g is a graph.Graph, all nodes of the graph will be stored in the shortest-path 18 // tree, otherwise only nodes reachable from u will be stored. 19 // 20 // The time complexity of BellmanFordFrom is O(|V|.|E|). 21 func BellmanFordFrom(u graph.Node, g traverse.Graph) (path Shortest, ok bool) { 22 if h, ok := g.(graph.Graph); ok { 23 if h.Node(u.ID()) == nil { 24 return Shortest{from: u}, true 25 } 26 path = newShortestFrom(u, graph.NodesOf(h.Nodes())) 27 } else { 28 if g.From(u.ID()) == graph.Empty { 29 return Shortest{from: u}, true 30 } 31 path = newShortestFrom(u, []graph.Node{u}) 32 } 33 path.dist[path.indexOf[u.ID()]] = 0 34 path.negCosts = make(map[negEdge]float64) 35 36 var weight Weighting 37 if wg, ok := g.(Weighted); ok { 38 weight = wg.Weight 39 } else { 40 weight = UniformCost(g) 41 } 42 43 // Queue to keep track which nodes need to be relaxed. 44 // Only nodes whose vertex distance changed in the previous iterations 45 // need to be relaxed again. 46 queue := newBellmanFordQueue(path.indexOf) 47 queue.enqueue(u) 48 49 // TODO(kortschak): Consider adding further optimisations 50 // from http://arxiv.org/abs/1111.5414. 51 var loops int64 52 for queue.len() != 0 { 53 u := queue.dequeue() 54 uid := u.ID() 55 j := path.indexOf[uid] 56 57 to := g.From(uid) 58 for to.Next() { 59 v := to.Node() 60 vid := v.ID() 61 k, ok := path.indexOf[vid] 62 if !ok { 63 k = path.add(v) 64 } 65 w, ok := weight(uid, vid) 66 if !ok { 67 panic("bellman-ford: unexpected invalid weight") 68 } 69 70 joint := path.dist[j] + w 71 if joint < path.dist[k] { 72 path.set(k, joint, j) 73 74 if !queue.has(vid) { 75 queue.enqueue(v) 76 } 77 } 78 } 79 80 // The maximum number of edges in the relaxed subgraph is |V_r| * (|V_r|-1). 81 // If the queue-loop has more iterations than the maximum number of edges 82 // it indicates that we have a negative cycle. 83 maxEdges := int64(len(path.nodes)) * int64(len(path.nodes)-1) 84 if loops > maxEdges { 85 path.hasNegativeCycle = true 86 return path, false 87 } 88 loops++ 89 } 90 91 return path, true 92 } 93 94 // BellmanFordAllFrom returns a shortest-path tree for shortest paths from u to all nodes in 95 // the graph g, or false indicating that a negative cycle exists in the graph. If the graph 96 // does not implement Weighted, UniformCost is used. 97 // 98 // If g is a graph.Graph, all nodes of the graph will be stored in the shortest-path 99 // tree, otherwise only nodes reachable from u will be stored. 100 // 101 // The time complexity of BellmanFordAllFrom is O(|V|.|E|). 102 func BellmanFordAllFrom(u graph.Node, g traverse.Graph) (path ShortestAlts, ok bool) { 103 if h, ok := g.(graph.Graph); ok { 104 if h.Node(u.ID()) == nil { 105 return ShortestAlts{from: u}, true 106 } 107 path = newShortestAltsFrom(u, graph.NodesOf(h.Nodes())) 108 } else { 109 if g.From(u.ID()) == graph.Empty { 110 return ShortestAlts{from: u}, true 111 } 112 path = newShortestAltsFrom(u, []graph.Node{u}) 113 } 114 path.dist[path.indexOf[u.ID()]] = 0 115 path.negCosts = make(map[negEdge]float64) 116 117 var weight Weighting 118 if wg, ok := g.(Weighted); ok { 119 weight = wg.Weight 120 } else { 121 weight = UniformCost(g) 122 } 123 124 // Queue to keep track which nodes need to be relaxed. 125 // Only nodes whose vertex distance changed in the previous iterations 126 // need to be relaxed again. 127 queue := newBellmanFordQueue(path.indexOf) 128 queue.enqueue(u) 129 130 // TODO(kortschak): Consider adding further optimisations 131 // from http://arxiv.org/abs/1111.5414. 132 var loops int64 133 for queue.len() != 0 { 134 u := queue.dequeue() 135 uid := u.ID() 136 j := path.indexOf[uid] 137 138 for _, v := range graph.NodesOf(g.From(uid)) { 139 vid := v.ID() 140 k, ok := path.indexOf[vid] 141 if !ok { 142 k = path.add(v) 143 } 144 w, ok := weight(uid, vid) 145 if !ok { 146 panic("bellman-ford: unexpected invalid weight") 147 } 148 149 joint := path.dist[j] + w 150 if joint < path.dist[k] { 151 path.set(k, joint, j) 152 153 if !queue.has(vid) { 154 queue.enqueue(v) 155 } 156 } else if joint == path.dist[k] { 157 path.addPath(k, j) 158 } 159 } 160 161 // The maximum number of edges in the relaxed subgraph is |V_r| * (|V_r|-1). 162 // If the queue-loop has more iterations than the maximum number of edges 163 // it indicates that we have a negative cycle. 164 maxEdges := int64(len(path.nodes)) * int64(len(path.nodes)-1) 165 if loops > maxEdges { 166 path.hasNegativeCycle = true 167 return path, false 168 } 169 loops++ 170 } 171 172 return path, true 173 } 174 175 // bellmanFordQueue is a queue for the Queue-based Bellman-Ford algorithm. 176 type bellmanFordQueue struct { 177 // queue holds the nodes which need to be relaxed. 178 queue linear.NodeQueue 179 180 // onQueue keeps track whether a node is on the queue or not. 181 onQueue []bool 182 183 // indexOf contains a mapping holding the id of a node with its index in the onQueue array. 184 indexOf map[int64]int 185 } 186 187 // enqueue adds a node to the bellmanFordQueue. 188 func (q *bellmanFordQueue) enqueue(n graph.Node) { 189 i, ok := q.indexOf[n.ID()] 190 switch { 191 case !ok: 192 panic("bellman-ford: unknown node") 193 case i < len(q.onQueue): 194 if q.onQueue[i] { 195 panic("bellman-ford: already queued") 196 } 197 case i == len(q.onQueue): 198 q.onQueue = append(q.onQueue, false) 199 case i < cap(q.onQueue): 200 q.onQueue = q.onQueue[:i+1] 201 default: 202 q.onQueue = append(q.onQueue, make([]bool, i-len(q.onQueue)+1)...) 203 } 204 q.onQueue[i] = true 205 q.queue.Enqueue(n) 206 } 207 208 // dequeue returns the first value of the bellmanFordQueue. 209 func (q *bellmanFordQueue) dequeue() graph.Node { 210 n := q.queue.Dequeue() 211 q.onQueue[q.indexOf[n.ID()]] = false 212 return n 213 } 214 215 // len returns the number of nodes in the bellmanFordQueue. 216 func (q *bellmanFordQueue) len() int { return q.queue.Len() } 217 218 // has returns whether a node with the given id is in the queue. 219 func (q bellmanFordQueue) has(id int64) bool { 220 idx, ok := q.indexOf[id] 221 if !ok || idx >= len(q.onQueue) { 222 return false 223 } 224 return q.onQueue[idx] 225 } 226 227 // newBellmanFordQueue creates a new bellmanFordQueue. 228 func newBellmanFordQueue(indexOf map[int64]int) bellmanFordQueue { 229 return bellmanFordQueue{ 230 onQueue: make([]bool, len(indexOf)), 231 indexOf: indexOf, 232 } 233 }