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