github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/simple/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 ug *UndirectedGraph 17 18 _ graph.Graph = ug 19 _ graph.Undirected = ug 20 _ graph.NodeAdder = ug 21 _ graph.NodeRemover = ug 22 _ graph.EdgeAdder = ug 23 _ graph.EdgeRemover = ug 24 ) 25 26 // UndirectedGraph implements a generalized undirected graph. 27 type UndirectedGraph struct { 28 nodes map[int64]graph.Node 29 edges map[int64]map[int64]graph.Edge 30 31 nodeIDs *uid.Set 32 } 33 34 // NewUndirectedGraph returns an UndirectedGraph. 35 func NewUndirectedGraph() *UndirectedGraph { 36 return &UndirectedGraph{ 37 nodes: make(map[int64]graph.Node), 38 edges: make(map[int64]map[int64]graph.Edge), 39 40 nodeIDs: uid.NewSet(), 41 } 42 } 43 44 // AddNode adds n to the graph. It panics if the added node ID matches an existing node ID. 45 func (g *UndirectedGraph) AddNode(n graph.Node) { 46 if _, exists := g.nodes[n.ID()]; exists { 47 panic(fmt.Sprintf("simple: node ID collision: %d", n.ID())) 48 } 49 g.nodes[n.ID()] = n 50 g.nodeIDs.Use(n.ID()) 51 } 52 53 // Edge returns the edge from u to v if such an edge exists and nil otherwise. 54 // The node v must be directly reachable from u as defined by the From method. 55 func (g *UndirectedGraph) Edge(uid, vid int64) graph.Edge { 56 return g.EdgeBetween(uid, vid) 57 } 58 59 // EdgeBetween returns the edge between nodes x and y. 60 func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge { 61 edge, ok := g.edges[xid][yid] 62 if !ok { 63 return nil 64 } 65 if edge.From().ID() == xid { 66 return edge 67 } 68 return edge.ReversedEdge() 69 } 70 71 // Edges returns all the edges in the graph. 72 func (g *UndirectedGraph) Edges() graph.Edges { 73 if len(g.edges) == 0 { 74 return graph.Empty 75 } 76 var edges []graph.Edge 77 seen := make(map[[2]int64]struct{}) 78 for _, u := range g.edges { 79 for _, e := range u { 80 uid := e.From().ID() 81 vid := e.To().ID() 82 if _, ok := seen[[2]int64{uid, vid}]; ok { 83 continue 84 } 85 seen[[2]int64{uid, vid}] = struct{}{} 86 seen[[2]int64{vid, uid}] = struct{}{} 87 edges = append(edges, e) 88 } 89 } 90 if len(edges) == 0 { 91 return graph.Empty 92 } 93 return iterator.NewOrderedEdges(edges) 94 } 95 96 // From returns all nodes in g that can be reached directly from n. 97 // 98 // The returned graph.Nodes is only valid until the next mutation of 99 // the receiver. 100 func (g *UndirectedGraph) From(id int64) graph.Nodes { 101 if len(g.edges[id]) == 0 { 102 return graph.Empty 103 } 104 return iterator.NewNodesByEdge(g.nodes, g.edges[id]) 105 } 106 107 // HasEdgeBetween returns whether an edge exists between nodes x and y. 108 func (g *UndirectedGraph) HasEdgeBetween(xid, yid int64) bool { 109 _, ok := g.edges[xid][yid] 110 return ok 111 } 112 113 // NewEdge returns a new Edge from the source to the destination node. 114 func (g *UndirectedGraph) NewEdge(from, to graph.Node) graph.Edge { 115 return Edge{F: from, T: to} 116 } 117 118 // NewNode returns a new unique Node to be added to g. The Node's ID does 119 // not become valid in g until the Node is added to g. 120 func (g *UndirectedGraph) NewNode() graph.Node { 121 if len(g.nodes) == 0 { 122 return Node(0) 123 } 124 if int64(len(g.nodes)) == uid.Max { 125 panic("simple: cannot allocate node: no slot") 126 } 127 return Node(g.nodeIDs.NewID()) 128 } 129 130 // Node returns the node with the given ID if it exists in the graph, 131 // and nil otherwise. 132 func (g *UndirectedGraph) Node(id int64) graph.Node { 133 return g.nodes[id] 134 } 135 136 // Nodes returns all the nodes in the graph. 137 // 138 // The returned graph.Nodes is only valid until the next mutation of 139 // the receiver. 140 func (g *UndirectedGraph) Nodes() graph.Nodes { 141 if len(g.nodes) == 0 { 142 return graph.Empty 143 } 144 return iterator.NewNodes(g.nodes) 145 } 146 147 // NodeWithID returns a Node with the given ID if possible. If a graph.Node 148 // is returned that is not already in the graph NodeWithID will return true 149 // for new and the graph.Node must be added to the graph before use. 150 func (g *UndirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) { 151 n, ok := g.nodes[id] 152 if ok { 153 return n, false 154 } 155 return Node(id), true 156 } 157 158 // RemoveEdge removes the edge with the given end IDs from the graph, leaving the terminal nodes. 159 // If the edge does not exist it is a no-op. 160 func (g *UndirectedGraph) RemoveEdge(fid, tid int64) { 161 if _, ok := g.nodes[fid]; !ok { 162 return 163 } 164 if _, ok := g.nodes[tid]; !ok { 165 return 166 } 167 168 delete(g.edges[fid], tid) 169 delete(g.edges[tid], fid) 170 } 171 172 // RemoveNode removes the node with the given ID from the graph, as well as any edges attached 173 // to it. If the node is not in the graph it is a no-op. 174 func (g *UndirectedGraph) RemoveNode(id int64) { 175 if _, ok := g.nodes[id]; !ok { 176 return 177 } 178 delete(g.nodes, id) 179 180 for from := range g.edges[id] { 181 delete(g.edges[from], id) 182 } 183 delete(g.edges, id) 184 185 g.nodeIDs.Release(id) 186 } 187 188 // SetEdge adds e, an edge from one node to another. If the nodes do not exist, they are added 189 // and are set to the nodes of the edge otherwise. 190 // It will panic if the IDs of the e.From and e.To are equal. 191 func (g *UndirectedGraph) SetEdge(e graph.Edge) { 192 var ( 193 from = e.From() 194 fid = from.ID() 195 to = e.To() 196 tid = to.ID() 197 ) 198 199 if fid == tid { 200 panic("simple: adding self edge") 201 } 202 203 if _, ok := g.nodes[fid]; !ok { 204 g.AddNode(from) 205 } else { 206 g.nodes[fid] = from 207 } 208 if _, ok := g.nodes[tid]; !ok { 209 g.AddNode(to) 210 } else { 211 g.nodes[tid] = to 212 } 213 214 if fm, ok := g.edges[fid]; ok { 215 fm[tid] = e 216 } else { 217 g.edges[fid] = map[int64]graph.Edge{tid: e} 218 } 219 if tm, ok := g.edges[tid]; ok { 220 tm[fid] = e 221 } else { 222 g.edges[tid] = map[int64]graph.Edge{fid: e} 223 } 224 }