github.com/gopherd/gonum@v0.0.4/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/gopherd/gonum/graph" 11 "github.com/gopherd/gonum/graph/iterator" 12 "github.com/gopherd/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 for xid, u := range g.edges { 78 for yid, e := range u { 79 if yid < xid { 80 // Do not consider edges when the To node ID is 81 // before the From node ID. Both orientations 82 // are stored. 83 continue 84 } 85 edges = append(edges, e) 86 } 87 } 88 if len(edges) == 0 { 89 return graph.Empty 90 } 91 return iterator.NewOrderedEdges(edges) 92 } 93 94 // From returns all nodes in g that can be reached directly from n. 95 // 96 // The returned graph.Nodes is only valid until the next mutation of 97 // the receiver. 98 func (g *UndirectedGraph) From(id int64) graph.Nodes { 99 if len(g.edges[id]) == 0 { 100 return graph.Empty 101 } 102 return iterator.NewNodesByEdge(g.nodes, g.edges[id]) 103 } 104 105 // HasEdgeBetween returns whether an edge exists between nodes x and y. 106 func (g *UndirectedGraph) HasEdgeBetween(xid, yid int64) bool { 107 _, ok := g.edges[xid][yid] 108 return ok 109 } 110 111 // NewEdge returns a new Edge from the source to the destination node. 112 func (g *UndirectedGraph) NewEdge(from, to graph.Node) graph.Edge { 113 return Edge{F: from, T: to} 114 } 115 116 // NewNode returns a new unique Node to be added to g. The Node's ID does 117 // not become valid in g until the Node is added to g. 118 func (g *UndirectedGraph) NewNode() graph.Node { 119 if len(g.nodes) == 0 { 120 return Node(0) 121 } 122 if int64(len(g.nodes)) == uid.Max { 123 panic("simple: cannot allocate node: no slot") 124 } 125 return Node(g.nodeIDs.NewID()) 126 } 127 128 // Node returns the node with the given ID if it exists in the graph, 129 // and nil otherwise. 130 func (g *UndirectedGraph) 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 *UndirectedGraph) 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 *UndirectedGraph) 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 IDs from the graph, leaving the terminal nodes. 157 // If the edge does not exist it is a no-op. 158 func (g *UndirectedGraph) 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 *UndirectedGraph) 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 // SetEdge adds e, an 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 *UndirectedGraph) SetEdge(e graph.Edge) { 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.Edge{tid: e} 216 } 217 if tm, ok := g.edges[tid]; ok { 218 tm[fid] = e 219 } else { 220 g.edges[tid] = map[int64]graph.Edge{fid: e} 221 } 222 }