github.com/gopherd/gonum@v0.0.4/graph/topo/tarjan.go (about)

     1  // Copyright ©2015 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  	"fmt"
     9  
    10  	"github.com/gopherd/gonum/graph"
    11  	"github.com/gopherd/gonum/graph/internal/ordered"
    12  	"github.com/gopherd/gonum/graph/internal/set"
    13  )
    14  
    15  // Unorderable is an error containing sets of unorderable graph.Nodes.
    16  type Unorderable [][]graph.Node
    17  
    18  // Error satisfies the error interface.
    19  func (e Unorderable) Error() string {
    20  	const maxNodes = 10
    21  	var n int
    22  	for _, c := range e {
    23  		n += len(c)
    24  	}
    25  	if n > maxNodes {
    26  		// Don't return errors that are too long.
    27  		return fmt.Sprintf("topo: no topological ordering: %d nodes in %d cyclic components", n, len(e))
    28  	}
    29  	return fmt.Sprintf("topo: no topological ordering: cyclic components: %v", [][]graph.Node(e))
    30  }
    31  
    32  func lexical(nodes []graph.Node) { ordered.ByID(nodes) }
    33  
    34  // Sort performs a topological sort of the directed graph g returning the 'from' to 'to'
    35  // sort order. If a topological ordering is not possible, an Unorderable error is returned
    36  // listing cyclic components in g with each cyclic component's members sorted by ID. When
    37  // an Unorderable error is returned, each cyclic component's topological position within
    38  // the sorted nodes is marked with a nil graph.Node.
    39  func Sort(g graph.Directed) (sorted []graph.Node, err error) {
    40  	sccs := TarjanSCC(g)
    41  	return sortedFrom(sccs, lexical)
    42  }
    43  
    44  // SortStabilized performs a topological sort of the directed graph g returning the 'from'
    45  // to 'to' sort order, or the order defined by the in place order sort function where there
    46  // is no unambiguous topological ordering. If a topological ordering is not possible, an
    47  // Unorderable error is returned listing cyclic components in g with each cyclic component's
    48  // members sorted by the provided order function. If order is nil, nodes are ordered lexically
    49  // by node ID. When an Unorderable error is returned, each cyclic component's topological
    50  // position within the sorted nodes is marked with a nil graph.Node.
    51  func SortStabilized(g graph.Directed, order func([]graph.Node)) (sorted []graph.Node, err error) {
    52  	if order == nil {
    53  		order = lexical
    54  	}
    55  	sccs := tarjanSCCstabilized(g, order)
    56  	return sortedFrom(sccs, order)
    57  }
    58  
    59  func sortedFrom(sccs [][]graph.Node, order func([]graph.Node)) ([]graph.Node, error) {
    60  	sorted := make([]graph.Node, 0, len(sccs))
    61  	var sc Unorderable
    62  	for _, s := range sccs {
    63  		if len(s) != 1 {
    64  			order(s)
    65  			sc = append(sc, s)
    66  			sorted = append(sorted, nil)
    67  			continue
    68  		}
    69  		sorted = append(sorted, s[0])
    70  	}
    71  	var err error
    72  	if sc != nil {
    73  		for i, j := 0, len(sc)-1; i < j; i, j = i+1, j-1 {
    74  			sc[i], sc[j] = sc[j], sc[i]
    75  		}
    76  		err = sc
    77  	}
    78  	ordered.Reverse(sorted)
    79  	return sorted, err
    80  }
    81  
    82  // TarjanSCC returns the strongly connected components of the graph g using Tarjan's algorithm.
    83  //
    84  // A strongly connected component of a graph is a set of vertices where it's possible to reach any
    85  // vertex in the set from any other (meaning there's a cycle between them.)
    86  //
    87  // Generally speaking, a directed graph where the number of strongly connected components is equal
    88  // to the number of nodes is acyclic, unless you count reflexive edges as a cycle (which requires
    89  // only a little extra testing.)
    90  //
    91  func TarjanSCC(g graph.Directed) [][]graph.Node {
    92  	return tarjanSCCstabilized(g, nil)
    93  }
    94  
    95  func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.Node {
    96  	nodes := graph.NodesOf(g.Nodes())
    97  	var succ func(id int64) []graph.Node
    98  	if order == nil {
    99  		succ = func(id int64) []graph.Node {
   100  			return graph.NodesOf(g.From(id))
   101  		}
   102  	} else {
   103  		order(nodes)
   104  		ordered.Reverse(nodes)
   105  
   106  		succ = func(id int64) []graph.Node {
   107  			to := graph.NodesOf(g.From(id))
   108  			order(to)
   109  			ordered.Reverse(to)
   110  			return to
   111  		}
   112  	}
   113  
   114  	t := tarjan{
   115  		succ: succ,
   116  
   117  		indexTable: make(map[int64]int, len(nodes)),
   118  		lowLink:    make(map[int64]int, len(nodes)),
   119  		onStack:    make(set.Int64s),
   120  	}
   121  	for _, v := range nodes {
   122  		if t.indexTable[v.ID()] == 0 {
   123  			t.strongconnect(v)
   124  		}
   125  	}
   126  	return t.sccs
   127  }
   128  
   129  // tarjan implements Tarjan's strongly connected component finding
   130  // algorithm. The implementation is from the pseudocode at
   131  //
   132  // http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm?oldid=642744644
   133  //
   134  type tarjan struct {
   135  	succ func(id int64) []graph.Node
   136  
   137  	index      int
   138  	indexTable map[int64]int
   139  	lowLink    map[int64]int
   140  	onStack    set.Int64s
   141  
   142  	stack []graph.Node
   143  
   144  	sccs [][]graph.Node
   145  }
   146  
   147  // strongconnect is the strongconnect function described in the
   148  // wikipedia article.
   149  func (t *tarjan) strongconnect(v graph.Node) {
   150  	vID := v.ID()
   151  
   152  	// Set the depth index for v to the smallest unused index.
   153  	t.index++
   154  	t.indexTable[vID] = t.index
   155  	t.lowLink[vID] = t.index
   156  	t.stack = append(t.stack, v)
   157  	t.onStack.Add(vID)
   158  
   159  	// Consider successors of v.
   160  	for _, w := range t.succ(vID) {
   161  		wID := w.ID()
   162  		if t.indexTable[wID] == 0 {
   163  			// Successor w has not yet been visited; recur on it.
   164  			t.strongconnect(w)
   165  			t.lowLink[vID] = min(t.lowLink[vID], t.lowLink[wID])
   166  		} else if t.onStack.Has(wID) {
   167  			// Successor w is in stack s and hence in the current SCC.
   168  			t.lowLink[vID] = min(t.lowLink[vID], t.indexTable[wID])
   169  		}
   170  	}
   171  
   172  	// If v is a root node, pop the stack and generate an SCC.
   173  	if t.lowLink[vID] == t.indexTable[vID] {
   174  		// Start a new strongly connected component.
   175  		var (
   176  			scc []graph.Node
   177  			w   graph.Node
   178  		)
   179  		for {
   180  			w, t.stack = t.stack[len(t.stack)-1], t.stack[:len(t.stack)-1]
   181  			t.onStack.Remove(w.ID())
   182  			// Add w to current strongly connected component.
   183  			scc = append(scc, w)
   184  			if w.ID() == vID {
   185  				break
   186  			}
   187  		}
   188  		// Output the current strongly connected component.
   189  		t.sccs = append(t.sccs, scc)
   190  	}
   191  }
   192  
   193  func min(a, b int) int {
   194  	if a < b {
   195  		return a
   196  	}
   197  	return b
   198  }