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  }