gonum.org/v1/gonum@v0.15.1-0.20240517103525-f853624cb1bb/graph/implicit_example_test.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 graph_test 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/simple" 13 "gonum.org/v1/gonum/graph/topo" 14 ) 15 16 // GraphNode is a node in an implicit graph. 17 type GraphNode struct { 18 id int64 19 neighbors []graph.Node 20 roots []*GraphNode 21 22 name string 23 } 24 25 // NewGraphNode returns a new GraphNode. 26 func NewGraphNode(id int64, name string) *GraphNode { 27 return &GraphNode{name: name, id: id} 28 } 29 30 // String returns the node's name. 31 func (g *GraphNode) String() string { 32 return g.name 33 } 34 35 // Node allows GraphNode to satisfy the graph.Graph interface. 36 func (g *GraphNode) Node(id int64) graph.Node { 37 if id == g.id { 38 return g 39 } 40 41 seen := map[int64]struct{}{g.id: {}} 42 for _, root := range g.roots { 43 if root.ID() == id || root.has(seen, id) { 44 return root 45 } 46 } 47 48 for _, n := range g.neighbors { 49 if n.ID() == id { 50 return n 51 } 52 53 if gn, ok := n.(*GraphNode); ok { 54 if gn.has(seen, id) { 55 return gn 56 } 57 } 58 } 59 60 return nil 61 } 62 63 func (g *GraphNode) has(seen map[int64]struct{}, id int64) bool { 64 for _, root := range g.roots { 65 if _, ok := seen[root.ID()]; ok { 66 continue 67 } 68 seen[root.ID()] = struct{}{} 69 70 if root.ID() == id || root.has(seen, id) { 71 return true 72 } 73 } 74 75 for _, n := range g.neighbors { 76 if _, ok := seen[n.ID()]; ok { 77 continue 78 } 79 seen[n.ID()] = struct{}{} 80 81 if n.ID() == id { 82 return true 83 } 84 if gn, ok := n.(*GraphNode); ok { 85 if gn.has(seen, id) { 86 return true 87 } 88 } 89 } 90 91 return false 92 } 93 94 // Nodes allows GraphNode to satisfy the graph.Graph interface. 95 func (g *GraphNode) Nodes() graph.Nodes { 96 nodes := []graph.Node{g} 97 seen := map[int64]struct{}{g.id: {}} 98 99 for _, root := range g.roots { 100 seen[root.ID()] = struct{}{} 101 nodes = root.nodes(append(nodes, root), seen) 102 } 103 104 for _, n := range g.neighbors { 105 seen[n.ID()] = struct{}{} 106 107 nodes = append(nodes, n) 108 if gn, ok := n.(*GraphNode); ok { 109 nodes = gn.nodes(nodes, seen) 110 } 111 } 112 113 return iterator.NewOrderedNodes(nodes) 114 } 115 116 func (g *GraphNode) nodes(dst []graph.Node, seen map[int64]struct{}) []graph.Node { 117 for _, root := range g.roots { 118 if _, ok := seen[root.ID()]; ok { 119 continue 120 } 121 seen[root.ID()] = struct{}{} 122 123 dst = root.nodes(append(dst, graph.Node(root)), seen) 124 } 125 126 for _, n := range g.neighbors { 127 if _, ok := seen[n.ID()]; ok { 128 continue 129 } 130 seen[n.ID()] = struct{}{} 131 132 dst = append(dst, n) 133 if gn, ok := n.(*GraphNode); ok { 134 dst = gn.nodes(dst, seen) 135 } 136 } 137 138 return dst 139 } 140 141 // From allows GraphNode to satisfy the graph.Graph interface. 142 func (g *GraphNode) From(id int64) graph.Nodes { 143 if id == g.ID() { 144 return iterator.NewOrderedNodes(g.neighbors) 145 } 146 147 seen := map[int64]struct{}{g.id: {}} 148 for _, root := range g.roots { 149 seen[root.ID()] = struct{}{} 150 151 if result := root.findNeighbors(id, seen); result != nil { 152 return iterator.NewOrderedNodes(result) 153 } 154 } 155 156 for _, n := range g.neighbors { 157 seen[n.ID()] = struct{}{} 158 159 if gn, ok := n.(*GraphNode); ok { 160 if result := gn.findNeighbors(id, seen); result != nil { 161 return iterator.NewOrderedNodes(result) 162 } 163 } 164 } 165 166 return graph.Empty 167 } 168 169 func (g *GraphNode) findNeighbors(id int64, seen map[int64]struct{}) []graph.Node { 170 if id == g.ID() { 171 return g.neighbors 172 } 173 174 for _, root := range g.roots { 175 if _, ok := seen[root.ID()]; ok { 176 continue 177 } 178 seen[root.ID()] = struct{}{} 179 180 if result := root.findNeighbors(id, seen); result != nil { 181 return result 182 } 183 } 184 185 for _, n := range g.neighbors { 186 if _, ok := seen[n.ID()]; ok { 187 continue 188 } 189 seen[n.ID()] = struct{}{} 190 191 if gn, ok := n.(*GraphNode); ok { 192 if result := gn.findNeighbors(id, seen); result != nil { 193 return result 194 } 195 } 196 } 197 198 return nil 199 } 200 201 // HasEdgeBetween allows GraphNode to satisfy the graph.Graph interface. 202 func (g *GraphNode) HasEdgeBetween(uid, vid int64) bool { 203 return g.EdgeBetween(uid, vid) != nil 204 } 205 206 // Edge allows GraphNode to satisfy the graph.Graph interface. 207 func (g *GraphNode) Edge(uid, vid int64) graph.Edge { 208 return g.EdgeBetween(uid, vid) 209 } 210 211 // EdgeBetween allows GraphNode to satisfy the graph.Graph interface. 212 func (g *GraphNode) EdgeBetween(uid, vid int64) graph.Edge { 213 if uid == g.id || vid == g.id { 214 for _, n := range g.neighbors { 215 if n.ID() == uid || n.ID() == vid { 216 return simple.Edge{F: g, T: n} 217 } 218 } 219 return nil 220 } 221 222 seen := map[int64]struct{}{g.id: {}} 223 for _, root := range g.roots { 224 seen[root.ID()] = struct{}{} 225 if result := root.edgeBetween(uid, vid, seen); result != nil { 226 return result 227 } 228 } 229 230 for _, n := range g.neighbors { 231 seen[n.ID()] = struct{}{} 232 if gn, ok := n.(*GraphNode); ok { 233 if result := gn.edgeBetween(uid, vid, seen); result != nil { 234 return result 235 } 236 } 237 } 238 239 return nil 240 } 241 242 func (g *GraphNode) edgeBetween(uid, vid int64, seen map[int64]struct{}) graph.Edge { 243 if uid == g.id || vid == g.id { 244 for _, n := range g.neighbors { 245 if n.ID() == uid || n.ID() == vid { 246 return simple.Edge{F: g, T: n} 247 } 248 } 249 return nil 250 } 251 252 for _, root := range g.roots { 253 if _, ok := seen[root.ID()]; ok { 254 continue 255 } 256 seen[root.ID()] = struct{}{} 257 258 if result := root.edgeBetween(uid, vid, seen); result != nil { 259 return result 260 } 261 } 262 263 for _, n := range g.neighbors { 264 if _, ok := seen[n.ID()]; ok { 265 continue 266 } 267 seen[n.ID()] = struct{}{} 268 269 if gn, ok := n.(*GraphNode); ok { 270 if result := gn.edgeBetween(uid, vid, seen); result != nil { 271 return result 272 } 273 } 274 } 275 276 return nil 277 } 278 279 // ID allows GraphNode to satisfy the graph.Node interface. 280 func (g *GraphNode) ID() int64 { 281 return g.id 282 } 283 284 // AddMeighbor adds an edge between g and n. 285 func (g *GraphNode) AddNeighbor(n *GraphNode) { 286 g.neighbors = append(g.neighbors, graph.Node(n)) 287 } 288 289 // AddRoot adds provides an entrance into the graph g from n. 290 func (g *GraphNode) AddRoot(n *GraphNode) { 291 g.roots = append(g.roots, n) 292 } 293 294 func Example_implicit() { 295 // This example shows the construction of the following graph 296 // using the implicit graph type above. 297 // 298 // The visual representation of the graph can be seen at 299 // https://graphviz.gitlab.io/_pages/Gallery/undirected/fdpclust.html 300 // 301 // graph G { 302 // e 303 // subgraph clusterA { 304 // a -- b 305 // subgraph clusterC { 306 // C -- D 307 // } 308 // } 309 // subgraph clusterB { 310 // d -- f 311 // } 312 // d -- D 313 // e -- clusterB 314 // clusterC -- clusterB 315 // } 316 317 // graph G { 318 G := NewGraphNode(0, "G") 319 // e 320 e := NewGraphNode(1, "e") 321 322 // subgraph clusterA { 323 clusterA := NewGraphNode(2, "clusterA") 324 // a -- b 325 a := NewGraphNode(3, "a") 326 b := NewGraphNode(4, "b") 327 a.AddNeighbor(b) 328 b.AddNeighbor(a) 329 clusterA.AddRoot(a) 330 clusterA.AddRoot(b) 331 332 // subgraph clusterC { 333 clusterC := NewGraphNode(5, "clusterC") 334 // C -- D 335 C := NewGraphNode(6, "C") 336 D := NewGraphNode(7, "D") 337 C.AddNeighbor(D) 338 D.AddNeighbor(C) 339 340 clusterC.AddRoot(C) 341 clusterC.AddRoot(D) 342 // } 343 clusterA.AddRoot(clusterC) 344 // } 345 346 // subgraph clusterB { 347 clusterB := NewGraphNode(8, "clusterB") 348 // d -- f 349 d := NewGraphNode(9, "d") 350 f := NewGraphNode(10, "f") 351 d.AddNeighbor(f) 352 f.AddNeighbor(d) 353 clusterB.AddRoot(d) 354 clusterB.AddRoot(f) 355 // } 356 357 // d -- D 358 d.AddNeighbor(D) 359 D.AddNeighbor(d) 360 361 // e -- clusterB 362 e.AddNeighbor(clusterB) 363 clusterB.AddNeighbor(e) 364 365 // clusterC -- clusterB 366 clusterC.AddNeighbor(clusterB) 367 clusterB.AddNeighbor(clusterC) 368 369 G.AddRoot(e) 370 G.AddRoot(clusterA) 371 G.AddRoot(clusterB) 372 // } 373 374 if topo.IsPathIn(G, []graph.Node{C, D, d, f}) { 375 fmt.Println("C--D--d--f is a path in G.") 376 } 377 378 fmt.Println("\nConnected components:") 379 for _, c := range topo.ConnectedComponents(G) { 380 fmt.Printf(" %s\n", c) 381 } 382 383 // Output: 384 // 385 // C--D--d--f is a path in G. 386 // 387 // Connected components: 388 // [G] 389 // [e clusterB clusterC] 390 // [d D C f] 391 // [clusterA] 392 // [a b] 393 }