gorgonia.org/gorgonia@v0.9.17/walker.go (about)

     1  package gorgonia
     2  
     3  import (
     4  	"sort"
     5  
     6  	"github.com/pkg/errors"
     7  	"gonum.org/v1/gonum/graph"
     8  	"gonum.org/v1/gonum/graph/iterator"
     9  	"gonum.org/v1/gonum/graph/topo"
    10  )
    11  
    12  // WalkGraph walks a graph. It returns a channel of *Nodes, so be sure to consume the channel or there may be a deadlock
    13  func WalkGraph(start *Node) <-chan *Node {
    14  	ch := make(chan *Node)
    15  	walked := NewNodeSet()
    16  
    17  	go func() {
    18  		walkGraph(start, ch, walked)
    19  		close(ch)
    20  	}()
    21  	return ch
    22  }
    23  
    24  func walkGraph(start *Node, ch chan *Node, walked NodeSet) {
    25  	defer func() {
    26  		walked.Add(start)
    27  	}()
    28  	if _, ok := walked[start]; ok {
    29  		return // walked before
    30  	}
    31  
    32  	ch <- start
    33  
    34  	for _, child := range start.children {
    35  		walkGraph(child, ch, walked)
    36  	}
    37  
    38  }
    39  
    40  // Sort topologically sorts a ExprGraph: root of graph will be first
    41  // nodes are sorted using gonum's SortStabilized function.
    42  //
    43  // see https://godoc.org/gonum.org/v1/gonum/graph/topo#SortStabilized for more info
    44  func Sort(g *ExprGraph) (sorted Nodes, err error) {
    45  	var sortedNodes []graph.Node
    46  	// if sortedNodes, err = topo.Sort(g); err != nil {
    47  	if sortedNodes, err = topo.SortStabilized(g, reverseLexical); err != nil {
    48  		return nil, errors.Wrap(err, sortFail)
    49  	}
    50  
    51  	sorted = graphNodeToNode(iterator.NewOrderedNodes(sortedNodes))
    52  	return
    53  }
    54  
    55  // UnstableSort performs a topological sort of the directed graph g returning the 'from' to 'to'
    56  // sort order. If a topological ordering is not possible, an Unorderable error is returned
    57  // listing cyclic components in g with each cyclic component's members sorted by ID. When
    58  // an Unorderable error is returned, each cyclic component's topological position within
    59  // the sorted nodes is marked with a nil graph.Node.
    60  func UnstableSort(g *ExprGraph) (sorted Nodes, err error) {
    61  	var sortedNodes []graph.Node
    62  	if sortedNodes, err = topo.Sort(g); err != nil {
    63  		return nil, errors.Wrap(err, sortFail)
    64  	}
    65  
    66  	sorted = graphNodeToNode(iterator.NewOrderedNodes(sortedNodes))
    67  	return
    68  }
    69  
    70  func reverseNodes(sorted Nodes) {
    71  	for i := len(sorted)/2 - 1; i >= 0; i-- {
    72  		j := len(sorted) - i - 1
    73  		sorted[i], sorted[j] = sorted[j], sorted[i]
    74  	}
    75  }
    76  
    77  type byID []graph.Node
    78  
    79  func (ns byID) Len() int           { return len(ns) }
    80  func (ns byID) Less(i, j int) bool { return ns[i].ID() > ns[j].ID() }
    81  func (ns byID) Swap(i, j int)      { ns[i], ns[j] = ns[j], ns[i] }
    82  
    83  func reverseLexical(a []graph.Node) {
    84  	sort.Sort(byID(a))
    85  }