tarjan.go 5.7 KB

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