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  }