github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/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 "github.com/jingcheng-WU/gonum/graph" 11 "github.com/jingcheng-WU/gonum/graph/iterator" 12 "github.com/jingcheng-WU/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 seen := make(map[[2]int64]struct{}) 79 for _, u := range g.edges { 80 for _, e := range u { 81 uid := e.From().ID() 82 vid := e.To().ID() 83 if _, ok := seen[[2]int64{uid, vid}]; ok { 84 continue 85 } 86 seen[[2]int64{uid, vid}] = struct{}{} 87 seen[[2]int64{vid, uid}] = struct{}{} 88 edges = append(edges, e) 89 } 90 } 91 if len(edges) == 0 { 92 return graph.Empty 93 } 94 return iterator.NewOrderedEdges(edges) 95 } 96 97 // From returns all nodes in g that can be reached directly from n. 98 func (g *WeightedUndirectedGraph) From(id int64) graph.Nodes { 99 if len(g.edges[id]) == 0 { 100 return graph.Empty 101 } 102 return iterator.NewNodesByWeightedEdge(g.nodes, g.edges[id]) 103 } 104 105 // HasEdgeBetween returns whether an edge exists between nodes x and y. 106 func (g *WeightedUndirectedGraph) HasEdgeBetween(xid, yid int64) bool { 107 _, ok := g.edges[xid][yid] 108 return ok 109 } 110 111 // NewNode returns a new unique Node to be added to g. The Node's ID does 112 // not become valid in g until the Node is added to g. 113 func (g *WeightedUndirectedGraph) NewNode() graph.Node { 114 if len(g.nodes) == 0 { 115 return Node(0) 116 } 117 if int64(len(g.nodes)) == uid.Max { 118 panic("simple: cannot allocate node: no slot") 119 } 120 return Node(g.nodeIDs.NewID()) 121 } 122 123 // NewWeightedEdge returns a new weighted edge from the source to the destination node. 124 func (g *WeightedUndirectedGraph) NewWeightedEdge(from, to graph.Node, weight float64) graph.WeightedEdge { 125 return WeightedEdge{F: from, T: to, W: weight} 126 } 127 128 // Node returns the node with the given ID if it exists in the graph, 129 // and nil otherwise. 130 func (g *WeightedUndirectedGraph) Node(id int64) graph.Node { 131 return g.nodes[id] 132 } 133 134 // Nodes returns all the nodes in the graph. 135 // 136 // The returned graph.Nodes is only valid until the next mutation of 137 // the receiver. 138 func (g *WeightedUndirectedGraph) Nodes() graph.Nodes { 139 if len(g.nodes) == 0 { 140 return graph.Empty 141 } 142 return iterator.NewNodes(g.nodes) 143 } 144 145 // NodeWithID returns a Node with the given ID if possible. If a graph.Node 146 // is returned that is not already in the graph NodeWithID will return true 147 // for new and the graph.Node must be added to the graph before use. 148 func (g *WeightedUndirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) { 149 n, ok := g.nodes[id] 150 if ok { 151 return n, false 152 } 153 return Node(id), true 154 } 155 156 // RemoveEdge removes the edge with the given end point IDs from the graph, leaving the terminal 157 // nodes. If the edge does not exist it is a no-op. 158 func (g *WeightedUndirectedGraph) RemoveEdge(fid, tid int64) { 159 if _, ok := g.nodes[fid]; !ok { 160 return 161 } 162 if _, ok := g.nodes[tid]; !ok { 163 return 164 } 165 166 delete(g.edges[fid], tid) 167 delete(g.edges[tid], fid) 168 } 169 170 // RemoveNode removes the node with the given ID from the graph, as well as any edges attached 171 // to it. If the node is not in the graph it is a no-op. 172 func (g *WeightedUndirectedGraph) RemoveNode(id int64) { 173 if _, ok := g.nodes[id]; !ok { 174 return 175 } 176 delete(g.nodes, id) 177 178 for from := range g.edges[id] { 179 delete(g.edges[from], id) 180 } 181 delete(g.edges, id) 182 183 g.nodeIDs.Release(id) 184 } 185 186 // SetWeightedEdge adds a weighted edge from one node to another. If the nodes do not exist, they are added 187 // and are set to the nodes of the edge otherwise. 188 // It will panic if the IDs of the e.From and e.To are equal. 189 func (g *WeightedUndirectedGraph) SetWeightedEdge(e graph.WeightedEdge) { 190 var ( 191 from = e.From() 192 fid = from.ID() 193 to = e.To() 194 tid = to.ID() 195 ) 196 197 if fid == tid { 198 panic("simple: adding self edge") 199 } 200 201 if _, ok := g.nodes[fid]; !ok { 202 g.AddNode(from) 203 } else { 204 g.nodes[fid] = from 205 } 206 if _, ok := g.nodes[tid]; !ok { 207 g.AddNode(to) 208 } else { 209 g.nodes[tid] = to 210 } 211 212 if fm, ok := g.edges[fid]; ok { 213 fm[tid] = e 214 } else { 215 g.edges[fid] = map[int64]graph.WeightedEdge{tid: e} 216 } 217 if tm, ok := g.edges[tid]; ok { 218 tm[fid] = e 219 } else { 220 g.edges[tid] = map[int64]graph.WeightedEdge{fid: e} 221 } 222 } 223 224 // Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge. 225 // If x and y are the same node or there is no joining edge between the two nodes the weight 226 // value returned is either the graph's absent or self value. Weight returns true if an edge 227 // exists between x and y or if x and y have the same ID, false otherwise. 228 func (g *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) { 229 if xid == yid { 230 return g.self, true 231 } 232 if n, ok := g.edges[xid]; ok { 233 if e, ok := n[yid]; ok { 234 return e.Weight(), true 235 } 236 } 237 return g.absent, false 238 } 239 240 // WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. 241 // The node v must be directly reachable from u as defined by the From method. 242 func (g *WeightedUndirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge { 243 return g.WeightedEdgeBetween(uid, vid) 244 } 245 246 // WeightedEdgeBetween returns the weighted edge between nodes x and y. 247 func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge { 248 edge, ok := g.edges[xid][yid] 249 if !ok { 250 return nil 251 } 252 if edge.From().ID() == xid { 253 return edge 254 } 255 return edge.ReversedEdge().(graph.WeightedEdge) 256 } 257 258 // WeightedEdges returns all the weighted edges in the graph. 259 func (g *WeightedUndirectedGraph) WeightedEdges() graph.WeightedEdges { 260 var edges []graph.WeightedEdge 261 seen := make(map[[2]int64]struct{}) 262 for _, u := range g.edges { 263 for _, e := range u { 264 uid := e.From().ID() 265 vid := e.To().ID() 266 if _, ok := seen[[2]int64{uid, vid}]; ok { 267 continue 268 } 269 seen[[2]int64{uid, vid}] = struct{}{} 270 seen[[2]int64{vid, uid}] = struct{}{} 271 edges = append(edges, e) 272 } 273 } 274 if len(edges) == 0 { 275 return graph.Empty 276 } 277 return iterator.NewOrderedWeightedEdges(edges) 278 }