gonum.org/v1/gonum@v0.14.0/graph/simple/weighted_directed.go (about) 1 // Copyright ©2014 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 simple 6 7 import ( 8 "fmt" 9 10 "gonum.org/v1/gonum/graph" 11 "gonum.org/v1/gonum/graph/iterator" 12 "gonum.org/v1/gonum/graph/set/uid" 13 ) 14 15 var ( 16 wdg *WeightedDirectedGraph 17 18 _ graph.Graph = wdg 19 _ graph.Weighted = wdg 20 _ graph.Directed = wdg 21 _ graph.WeightedDirected = wdg 22 _ graph.NodeAdder = wdg 23 _ graph.NodeRemover = wdg 24 _ graph.WeightedEdgeAdder = wdg 25 _ graph.EdgeRemover = wdg 26 ) 27 28 // WeightedDirectedGraph implements a generalized weighted directed graph. 29 type WeightedDirectedGraph struct { 30 nodes map[int64]graph.Node 31 from map[int64]map[int64]graph.WeightedEdge 32 to map[int64]map[int64]graph.WeightedEdge 33 34 self, absent float64 35 36 nodeIDs *uid.Set 37 } 38 39 // NewWeightedDirectedGraph returns a WeightedDirectedGraph with the specified self and absent 40 // edge weight values. 41 func NewWeightedDirectedGraph(self, absent float64) *WeightedDirectedGraph { 42 return &WeightedDirectedGraph{ 43 nodes: make(map[int64]graph.Node), 44 from: make(map[int64]map[int64]graph.WeightedEdge), 45 to: make(map[int64]map[int64]graph.WeightedEdge), 46 47 self: self, 48 absent: absent, 49 50 nodeIDs: uid.NewSet(), 51 } 52 } 53 54 // AddNode adds n to the graph. It panics if the added node ID matches an existing node ID. 55 func (g *WeightedDirectedGraph) AddNode(n graph.Node) { 56 if _, exists := g.nodes[n.ID()]; exists { 57 panic(fmt.Sprintf("simple: node ID collision: %d", n.ID())) 58 } 59 g.nodes[n.ID()] = n 60 g.nodeIDs.Use(n.ID()) 61 } 62 63 // Edge returns the edge from u to v if such an edge exists and nil otherwise. 64 // The node v must be directly reachable from u as defined by the From method. 65 func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge { 66 return g.WeightedEdge(uid, vid) 67 } 68 69 // Edges returns all the edges in the graph. 70 func (g *WeightedDirectedGraph) Edges() graph.Edges { 71 var edges []graph.Edge 72 for _, u := range g.nodes { 73 for _, e := range g.from[u.ID()] { 74 edges = append(edges, e) 75 } 76 } 77 if len(edges) == 0 { 78 return graph.Empty 79 } 80 return iterator.NewOrderedEdges(edges) 81 } 82 83 // From returns all nodes in g that can be reached directly from n. 84 // 85 // The returned graph.Nodes is only valid until the next mutation of 86 // the receiver. 87 func (g *WeightedDirectedGraph) From(id int64) graph.Nodes { 88 if len(g.from[id]) == 0 { 89 return graph.Empty 90 } 91 return iterator.NewNodesByWeightedEdge(g.nodes, g.from[id]) 92 } 93 94 // HasEdgeBetween returns whether an edge exists between nodes x and y without 95 // considering direction. 96 func (g *WeightedDirectedGraph) HasEdgeBetween(xid, yid int64) bool { 97 if _, ok := g.from[xid][yid]; ok { 98 return true 99 } 100 _, ok := g.from[yid][xid] 101 return ok 102 } 103 104 // HasEdgeFromTo returns whether an edge exists in the graph from u to v. 105 func (g *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool { 106 if _, ok := g.from[uid][vid]; !ok { 107 return false 108 } 109 return true 110 } 111 112 // NewNode returns a new unique Node to be added to g. The Node's ID does 113 // not become valid in g until the Node is added to g. 114 func (g *WeightedDirectedGraph) NewNode() graph.Node { 115 if len(g.nodes) == 0 { 116 return Node(0) 117 } 118 if int64(len(g.nodes)) == uid.Max { 119 panic("simple: cannot allocate node: no slot") 120 } 121 return Node(g.nodeIDs.NewID()) 122 } 123 124 // NewWeightedEdge returns a new weighted edge from the source to the destination node. 125 func (g *WeightedDirectedGraph) NewWeightedEdge(from, to graph.Node, weight float64) graph.WeightedEdge { 126 return WeightedEdge{F: from, T: to, W: weight} 127 } 128 129 // Node returns the node with the given ID if it exists in the graph, 130 // and nil otherwise. 131 func (g *WeightedDirectedGraph) Node(id int64) graph.Node { 132 return g.nodes[id] 133 } 134 135 // Nodes returns all the nodes in the graph. 136 // 137 // The returned graph.Nodes is only valid until the next mutation of 138 // the receiver. 139 func (g *WeightedDirectedGraph) Nodes() graph.Nodes { 140 if len(g.nodes) == 0 { 141 return graph.Empty 142 } 143 return iterator.NewNodes(g.nodes) 144 } 145 146 // NodeWithID returns a Node with the given ID if possible. If a graph.Node 147 // is returned that is not already in the graph NodeWithID will return true 148 // for new and the graph.Node must be added to the graph before use. 149 func (g *WeightedDirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) { 150 n, ok := g.nodes[id] 151 if ok { 152 return n, false 153 } 154 return Node(id), true 155 } 156 157 // RemoveEdge removes the edge with the given end point IDs from the graph, leaving the terminal 158 // nodes. If the edge does not exist it is a no-op. 159 func (g *WeightedDirectedGraph) RemoveEdge(fid, tid int64) { 160 if _, ok := g.nodes[fid]; !ok { 161 return 162 } 163 if _, ok := g.nodes[tid]; !ok { 164 return 165 } 166 167 delete(g.from[fid], tid) 168 delete(g.to[tid], fid) 169 } 170 171 // RemoveNode removes the node with the given ID from the graph, as well as any edges attached 172 // to it. If the node is not in the graph it is a no-op. 173 func (g *WeightedDirectedGraph) RemoveNode(id int64) { 174 if _, ok := g.nodes[id]; !ok { 175 return 176 } 177 delete(g.nodes, id) 178 179 for from := range g.from[id] { 180 delete(g.to[from], id) 181 } 182 delete(g.from, id) 183 184 for to := range g.to[id] { 185 delete(g.from[to], id) 186 } 187 delete(g.to, id) 188 189 g.nodeIDs.Release(id) 190 } 191 192 // SetWeightedEdge adds a weighted edge from one node to another. If the nodes do not exist, they are added 193 // and are set to the nodes of the edge otherwise. 194 // It will panic if the IDs of the e.From and e.To are equal. 195 func (g *WeightedDirectedGraph) SetWeightedEdge(e graph.WeightedEdge) { 196 var ( 197 from = e.From() 198 fid = from.ID() 199 to = e.To() 200 tid = to.ID() 201 ) 202 203 if fid == tid { 204 panic("simple: adding self edge") 205 } 206 207 if _, ok := g.nodes[fid]; !ok { 208 g.AddNode(from) 209 } else { 210 g.nodes[fid] = from 211 } 212 if _, ok := g.nodes[tid]; !ok { 213 g.AddNode(to) 214 } else { 215 g.nodes[tid] = to 216 } 217 218 if fm, ok := g.from[fid]; ok { 219 fm[tid] = e 220 } else { 221 g.from[fid] = map[int64]graph.WeightedEdge{tid: e} 222 } 223 if tm, ok := g.to[tid]; ok { 224 tm[fid] = e 225 } else { 226 g.to[tid] = map[int64]graph.WeightedEdge{fid: e} 227 } 228 } 229 230 // To returns all nodes in g that can reach directly to n. 231 // 232 // The returned graph.Nodes is only valid until the next mutation of 233 // the receiver. 234 func (g *WeightedDirectedGraph) To(id int64) graph.Nodes { 235 if len(g.to[id]) == 0 { 236 return graph.Empty 237 } 238 return iterator.NewNodesByWeightedEdge(g.nodes, g.to[id]) 239 } 240 241 // Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge. 242 // If x and y are the same node or there is no joining edge between the two nodes the weight 243 // value returned is either the graph's absent or self value. Weight returns true if an edge 244 // exists between x and y or if x and y have the same ID, false otherwise. 245 func (g *WeightedDirectedGraph) Weight(xid, yid int64) (w float64, ok bool) { 246 if xid == yid { 247 return g.self, true 248 } 249 if to, ok := g.from[xid]; ok { 250 if e, ok := to[yid]; ok { 251 return e.Weight(), true 252 } 253 } 254 return g.absent, false 255 } 256 257 // WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. 258 // The node v must be directly reachable from u as defined by the From method. 259 func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge { 260 edge, ok := g.from[uid][vid] 261 if !ok { 262 return nil 263 } 264 return edge 265 } 266 267 // WeightedEdges returns all the weighted edges in the graph. 268 func (g *WeightedDirectedGraph) WeightedEdges() graph.WeightedEdges { 269 var edges []graph.WeightedEdge 270 for _, u := range g.nodes { 271 for _, e := range g.from[u.ID()] { 272 edges = append(edges, e) 273 } 274 } 275 if len(edges) == 0 { 276 return graph.Empty 277 } 278 return iterator.NewOrderedWeightedEdges(edges) 279 }