github.com/gopherd/gonum@v0.0.4/graph/multi/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 multi 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 dg *DirectedGraph 17 18 _ graph.Graph = dg 19 _ graph.Directed = dg 20 _ graph.Multigraph = dg 21 _ graph.DirectedMultigraph = dg 22 _ graph.NodeAdder = dg 23 _ graph.NodeRemover = dg 24 _ graph.LineAdder = dg 25 _ graph.LineRemover = dg 26 ) 27 28 // DirectedGraph implements a generalized directed graph. 29 type DirectedGraph struct { 30 nodes map[int64]graph.Node 31 from map[int64]map[int64]map[int64]graph.Line 32 to map[int64]map[int64]map[int64]graph.Line 33 34 nodeIDs *uid.Set 35 lineIDs map[int64]map[int64]*uid.Set 36 } 37 38 // NewDirectedGraph returns a DirectedGraph. 39 func NewDirectedGraph() *DirectedGraph { 40 return &DirectedGraph{ 41 nodes: make(map[int64]graph.Node), 42 from: make(map[int64]map[int64]map[int64]graph.Line), 43 to: make(map[int64]map[int64]map[int64]graph.Line), 44 45 nodeIDs: uid.NewSet(), 46 lineIDs: make(map[int64]map[int64]*uid.Set), 47 } 48 } 49 50 // AddNode adds n to the graph. It panics if the added node ID matches an existing node ID. 51 func (g *DirectedGraph) AddNode(n graph.Node) { 52 if _, exists := g.nodes[n.ID()]; exists { 53 panic(fmt.Sprintf("simple: node ID collision: %d", n.ID())) 54 } 55 g.nodes[n.ID()] = n 56 g.nodeIDs.Use(n.ID()) 57 } 58 59 // Edge returns the edge from u to v if such an edge exists and nil otherwise. 60 // The node v must be directly reachable from u as defined by the From method. 61 // The returned graph.Edge is a multi.Edge if an edge exists. 62 func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge { 63 l := g.Lines(uid, vid) 64 if l == graph.Empty { 65 return nil 66 } 67 return Edge{F: g.Node(uid), T: g.Node(vid), Lines: l} 68 } 69 70 // Edges returns all the edges in the graph. Each edge in the returned slice 71 // is a multi.Edge. 72 // 73 // The returned graph.Edges is only valid until the next mutation of 74 // the receiver. 75 func (g *DirectedGraph) Edges() graph.Edges { 76 if len(g.nodes) == 0 { 77 return graph.Empty 78 } 79 var edges []graph.Edge 80 for uid, u := range g.nodes { 81 for vid, lines := range g.from[u.ID()] { 82 if len(lines) == 0 { 83 continue 84 } 85 edges = append(edges, Edge{ 86 F: g.Node(uid), 87 T: g.Node(vid), 88 Lines: iterator.NewLines(lines), 89 }) 90 } 91 } 92 if len(edges) == 0 { 93 return graph.Empty 94 } 95 return iterator.NewOrderedEdges(edges) 96 } 97 98 // From returns all nodes in g that can be reached directly from n. 99 // 100 // The returned graph.Nodes is only valid until the next mutation of 101 // the receiver. 102 func (g *DirectedGraph) From(id int64) graph.Nodes { 103 if len(g.from[id]) == 0 { 104 return graph.Empty 105 } 106 return iterator.NewNodesByLines(g.nodes, g.from[id]) 107 } 108 109 // HasEdgeBetween returns whether an edge exists between nodes x and y without 110 // considering direction. 111 func (g *DirectedGraph) HasEdgeBetween(xid, yid int64) bool { 112 if _, ok := g.from[xid][yid]; ok { 113 return true 114 } 115 _, ok := g.from[yid][xid] 116 return ok 117 } 118 119 // HasEdgeFromTo returns whether an edge exists in the graph from u to v. 120 func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool { 121 _, ok := g.from[uid][vid] 122 return ok 123 } 124 125 // Lines returns the lines from u to v if such any such lines exists and nil otherwise. 126 // The node v must be directly reachable from u as defined by the From method. 127 func (g *DirectedGraph) Lines(uid, vid int64) graph.Lines { 128 edge := g.from[uid][vid] 129 if len(edge) == 0 { 130 return graph.Empty 131 } 132 var lines []graph.Line 133 for _, l := range edge { 134 lines = append(lines, l) 135 } 136 return iterator.NewOrderedLines(lines) 137 } 138 139 // NewLine returns a new Line from the source to the destination node. 140 // The returned Line will have a graph-unique ID. 141 // The Line's ID does not become valid in g until the Line is added to g. 142 func (g *DirectedGraph) NewLine(from, to graph.Node) graph.Line { 143 fid := from.ID() 144 tid := to.ID() 145 var lineID int64 146 switch { 147 case g.lineIDs[fid] == nil: 148 uids := uid.NewSet() 149 lineID = uids.NewID() 150 g.lineIDs[fid] = map[int64]*uid.Set{tid: uids} 151 case g.lineIDs[fid][tid] == nil: 152 uids := uid.NewSet() 153 lineID = uids.NewID() 154 g.lineIDs[fid][tid] = uids 155 default: 156 lineID = g.lineIDs[fid][tid].NewID() 157 } 158 return Line{F: from, T: to, UID: lineID} 159 } 160 161 // NewNode returns a new unique Node to be added to g. The Node's ID does 162 // not become valid in g until the Node is added to g. 163 func (g *DirectedGraph) NewNode() graph.Node { 164 if len(g.nodes) == 0 { 165 return Node(0) 166 } 167 if int64(len(g.nodes)) == uid.Max { 168 panic("simple: cannot allocate node: no slot") 169 } 170 return Node(g.nodeIDs.NewID()) 171 } 172 173 // Node returns the node with the given ID if it exists in the graph, 174 // and nil otherwise. 175 func (g *DirectedGraph) Node(id int64) graph.Node { 176 return g.nodes[id] 177 } 178 179 // Nodes returns all the nodes in the graph. 180 // 181 // The returned graph.Nodes is only valid until the next mutation of 182 // the receiver. 183 func (g *DirectedGraph) Nodes() graph.Nodes { 184 if len(g.nodes) == 0 { 185 return graph.Empty 186 } 187 return iterator.NewNodes(g.nodes) 188 } 189 190 // NodeWithID returns a Node with the given ID if possible. If a graph.Node 191 // is returned that is not already in the graph NodeWithID will return true 192 // for new and the graph.Node must be added to the graph before use. 193 func (g *DirectedGraph) NodeWithID(id int64) (n graph.Node, new bool) { 194 n, ok := g.nodes[id] 195 if ok { 196 return n, false 197 } 198 return Node(id), true 199 } 200 201 // RemoveLine removes the line with the given end point and line IDs from the graph, leaving 202 // the terminal nodes. If the line does not exist it is a no-op. 203 func (g *DirectedGraph) RemoveLine(fid, tid, id int64) { 204 if _, ok := g.nodes[fid]; !ok { 205 return 206 } 207 if _, ok := g.nodes[tid]; !ok { 208 return 209 } 210 211 delete(g.from[fid][tid], id) 212 if len(g.from[fid][tid]) == 0 { 213 delete(g.from[fid], tid) 214 } 215 delete(g.to[tid][fid], id) 216 if len(g.to[tid][fid]) == 0 { 217 delete(g.to[tid], fid) 218 } 219 220 g.lineIDs[fid][tid].Release(id) 221 } 222 223 // RemoveNode removes the node with the given ID from the graph, as well as any edges attached 224 // to it. If the node is not in the graph it is a no-op. 225 func (g *DirectedGraph) RemoveNode(id int64) { 226 if _, ok := g.nodes[id]; !ok { 227 return 228 } 229 delete(g.nodes, id) 230 231 for from := range g.from[id] { 232 delete(g.to[from], id) 233 } 234 delete(g.from, id) 235 236 for to := range g.to[id] { 237 delete(g.from[to], id) 238 } 239 delete(g.to, id) 240 241 g.nodeIDs.Release(id) 242 } 243 244 // SetLine adds l, a line from one node to another. If the nodes do not exist, they are added 245 // and are set to the nodes of the line otherwise. 246 func (g *DirectedGraph) SetLine(l graph.Line) { 247 var ( 248 from = l.From() 249 fid = from.ID() 250 to = l.To() 251 tid = to.ID() 252 lid = l.ID() 253 ) 254 255 if _, ok := g.nodes[fid]; !ok { 256 g.AddNode(from) 257 } else { 258 g.nodes[fid] = from 259 } 260 if _, ok := g.nodes[tid]; !ok { 261 g.AddNode(to) 262 } else { 263 g.nodes[tid] = to 264 } 265 266 switch { 267 case g.from[fid] == nil: 268 g.from[fid] = map[int64]map[int64]graph.Line{tid: {lid: l}} 269 case g.from[fid][tid] == nil: 270 g.from[fid][tid] = map[int64]graph.Line{lid: l} 271 default: 272 g.from[fid][tid][lid] = l 273 } 274 switch { 275 case g.to[tid] == nil: 276 g.to[tid] = map[int64]map[int64]graph.Line{fid: {lid: l}} 277 case g.to[tid][fid] == nil: 278 g.to[tid][fid] = map[int64]graph.Line{lid: l} 279 default: 280 g.to[tid][fid][lid] = l 281 } 282 283 switch { 284 case g.lineIDs[fid] == nil: 285 uids := uid.NewSet() 286 g.lineIDs[fid] = map[int64]*uid.Set{tid: uids} 287 case g.lineIDs[fid][tid] == nil: 288 uids := uid.NewSet() 289 g.lineIDs[fid][tid] = uids 290 } 291 g.lineIDs[fid][tid].Use(lid) 292 } 293 294 // To returns all nodes in g that can reach directly to n. 295 // 296 // The returned graph.Nodes is only valid until the next mutation of 297 // the receiver. 298 func (g *DirectedGraph) To(id int64) graph.Nodes { 299 if len(g.to[id]) == 0 { 300 return graph.Empty 301 } 302 return iterator.NewNodesByLines(g.nodes, g.to[id]) 303 }