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 }