github.com/gopherd/gonum@v0.0.4/graph/topo/topo.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 topo 6 7 import ( 8 "github.com/gopherd/gonum/graph" 9 "github.com/gopherd/gonum/graph/internal/ordered" 10 "github.com/gopherd/gonum/graph/traverse" 11 ) 12 13 // IsPathIn returns whether path is a path in g. 14 // 15 // As special cases, IsPathIn returns true for a zero length path or for 16 // a path of length 1 when the node in path exists in the graph. 17 func IsPathIn(g graph.Graph, path []graph.Node) bool { 18 switch len(path) { 19 case 0: 20 return true 21 case 1: 22 return g.Node(path[0].ID()) != nil 23 default: 24 var canReach func(uid, vid int64) bool 25 switch g := g.(type) { 26 case graph.Directed: 27 canReach = g.HasEdgeFromTo 28 default: 29 canReach = g.HasEdgeBetween 30 } 31 32 for i, u := range path[:len(path)-1] { 33 if !canReach(u.ID(), path[i+1].ID()) { 34 return false 35 } 36 } 37 return true 38 } 39 } 40 41 // PathExistsIn returns whether there is a path in g starting at 'from' extending 42 // to 'to'. 43 // 44 // PathExistsIn exists as a helper function. If many tests for path existence 45 // are being performed, other approaches will be more efficient. 46 func PathExistsIn(g graph.Graph, from, to graph.Node) bool { 47 var t traverse.BreadthFirst 48 return t.Walk(g, from, func(n graph.Node, _ int) bool { return n.ID() == to.ID() }) != nil 49 } 50 51 // ConnectedComponents returns the connected components of the undirected graph g. 52 func ConnectedComponents(g graph.Undirected) [][]graph.Node { 53 var ( 54 w traverse.DepthFirst 55 c []graph.Node 56 cc [][]graph.Node 57 ) 58 during := func(n graph.Node) { 59 c = append(c, n) 60 } 61 after := func() { 62 cc = append(cc, []graph.Node(nil)) 63 cc[len(cc)-1] = append(cc[len(cc)-1], c...) 64 c = c[:0] 65 } 66 w.WalkAll(g, nil, after, during) 67 68 return cc 69 } 70 71 // Equal returns whether two graphs are topologically equal. To be 72 // considered topologically equal, a and b must have identical sets 73 // of nodes and be identically traversable. 74 func Equal(a, b graph.Graph) bool { 75 aNodes := a.Nodes() 76 bNodes := b.Nodes() 77 if aNodes.Len() != bNodes.Len() { 78 return false 79 } 80 81 aNodeSlice := graph.NodesOf(aNodes) 82 bNodeSlice := graph.NodesOf(bNodes) 83 ordered.ByID(aNodeSlice) 84 ordered.ByID(bNodeSlice) 85 for i, aU := range aNodeSlice { 86 id := aU.ID() 87 if id != bNodeSlice[i].ID() { 88 return false 89 } 90 91 toA := a.From(id) 92 toB := b.From(id) 93 if toA.Len() != toB.Len() { 94 return false 95 } 96 97 aAdjacent := graph.NodesOf(toA) 98 bAdjacent := graph.NodesOf(toB) 99 ordered.ByID(aAdjacent) 100 ordered.ByID(bAdjacent) 101 for i, aV := range aAdjacent { 102 id := aV.ID() 103 if id != bAdjacent[i].ID() { 104 return false 105 } 106 } 107 } 108 109 return true 110 }