gonum.org/v1/gonum@v0.14.0/graph/path/johnson_apsp.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 "math" 9 10 "golang.org/x/exp/rand" 11 12 "gonum.org/v1/gonum/graph" 13 "gonum.org/v1/gonum/graph/simple" 14 ) 15 16 // JohnsonAllPaths returns a shortest-path tree for shortest paths in the graph g. 17 // If the graph does not implement Weighted, UniformCost is used. If a negative cycle 18 // exists in g, ok will be returned false and paths will not contain valid data. 19 // 20 // The time complexity of JohnsonAllPaths is O(|V|.|E|+|V|^2.log|V|). 21 func JohnsonAllPaths(g graph.Graph) (paths AllShortest, ok bool) { 22 adjusted := johnsonWeightAdjuster{Graph: g} 23 if wg, ok := g.(Weighted); ok { 24 adjusted.weight = wg.Weight 25 } else { 26 adjusted.weight = UniformCost(g) 27 } 28 29 paths = newAllShortest(graph.NodesOf(g.Nodes()), false) 30 31 var q int64 32 sign := int64(-1) 33 for { 34 // Choose a random node ID until we find 35 // one that is not in g. 36 q = sign * rand.Int63() 37 if _, exists := paths.indexOf[q]; !exists { 38 break 39 } 40 sign *= -1 41 } 42 43 adjusted.adjustBy, ok = BellmanFordFrom(johnsonGraphNode(q), johnsonReWeight{adjusted, q}) 44 if !ok { 45 return paths, false 46 } 47 48 dijkstraAllPaths(adjusted, paths) 49 50 for i, u := range paths.nodes { 51 hu := adjusted.adjustBy.WeightTo(u.ID()) 52 for j, v := range paths.nodes { 53 if i == j { 54 continue 55 } 56 hv := adjusted.adjustBy.WeightTo(v.ID()) 57 paths.dist.Set(i, j, paths.dist.At(i, j)-hu+hv) 58 } 59 } 60 61 return paths, ok 62 } 63 64 // johnsonWeightAdjuster is an edge re-weighted graph constructed 65 // by the first phase of the Johnson algorithm such that no negative 66 // edge weights exist in the graph. 67 type johnsonWeightAdjuster struct { 68 graph.Graph 69 weight Weighting 70 71 adjustBy Shortest 72 } 73 74 var _ graph.Weighted = johnsonWeightAdjuster{} 75 76 func (g johnsonWeightAdjuster) Node(id int64) graph.Node { 77 panic("path: unintended use of johnsonWeightAdjuster") 78 } 79 80 func (g johnsonWeightAdjuster) WeightedEdge(_, _ int64) graph.WeightedEdge { 81 panic("path: unintended use of johnsonWeightAdjuster") 82 } 83 84 func (g johnsonWeightAdjuster) Weight(xid, yid int64) (w float64, ok bool) { 85 w, ok = g.weight(xid, yid) 86 return w + g.adjustBy.WeightTo(xid) - g.adjustBy.WeightTo(yid), ok 87 } 88 89 func (johnsonWeightAdjuster) HasEdgeBetween(_, _ int64) bool { 90 panic("path: unintended use of johnsonWeightAdjuster") 91 } 92 93 // johnsonReWeight provides a query node to allow edge re-weighting 94 // using the Bellman-Ford algorithm for the first phase of the 95 // Johnson algorithm. 96 type johnsonReWeight struct { 97 johnsonWeightAdjuster 98 q int64 99 } 100 101 func (g johnsonReWeight) Node(id int64) graph.Node { 102 if id != g.q { 103 panic("path: unintended use of johnsonReWeight") 104 } 105 return simple.Node(id) 106 } 107 108 func (g johnsonReWeight) Nodes() graph.Nodes { 109 return newJohnsonNodeIterator(g.q, g.Graph.Nodes()) 110 } 111 112 func (g johnsonReWeight) From(id int64) graph.Nodes { 113 if id == g.q { 114 return g.Graph.Nodes() 115 } 116 return g.Graph.From(id) 117 } 118 119 func (g johnsonReWeight) Edge(uid, vid int64) graph.Edge { 120 if uid == g.q && g.Graph.Node(vid) != nil { 121 return simple.Edge{F: johnsonGraphNode(g.q), T: simple.Node(vid)} 122 } 123 return g.Graph.Edge(uid, vid) 124 } 125 126 func (g johnsonReWeight) Weight(xid, yid int64) (w float64, ok bool) { 127 switch g.q { 128 case xid: 129 return 0, true 130 case yid: 131 return math.Inf(1), false 132 default: 133 return g.weight(xid, yid) 134 } 135 } 136 137 type johnsonGraphNode int64 138 139 func (n johnsonGraphNode) ID() int64 { return int64(n) } 140 141 func newJohnsonNodeIterator(q int64, nodes graph.Nodes) *johnsonNodeIterator { 142 return &johnsonNodeIterator{q: q, nodes: nodes} 143 } 144 145 type johnsonNodeIterator struct { 146 q int64 147 nodes graph.Nodes 148 qUsed, qOK bool 149 } 150 151 func (it *johnsonNodeIterator) Len() int { 152 var len int 153 if it.nodes != nil { 154 len = it.nodes.Len() 155 if len < 0 { 156 return len 157 } 158 } 159 if !it.qUsed { 160 len++ 161 } 162 return len 163 } 164 165 func (it *johnsonNodeIterator) Next() bool { 166 if it.nodes != nil { 167 ok := it.nodes.Next() 168 if ok { 169 return true 170 } 171 } 172 if !it.qUsed { 173 it.qOK = true 174 it.qUsed = true 175 return true 176 } 177 it.qOK = false 178 return false 179 } 180 181 func (it *johnsonNodeIterator) Node() graph.Node { 182 if it.qOK { 183 return johnsonGraphNode(it.q) 184 } 185 if it.nodes == nil { 186 return nil 187 } 188 return it.nodes.Node() 189 } 190 191 func (it *johnsonNodeIterator) Reset() { 192 it.qOK = false 193 it.qUsed = false 194 if it.nodes == nil { 195 return 196 } 197 it.nodes.Reset() 198 }