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