toposort.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. package toposort
  2. import (
  3. "bytes"
  4. "fmt"
  5. "sort"
  6. "strings"
  7. )
  8. // Reworked from https://github.com/philopon/go-toposort
  9. type Graph struct {
  10. // Outgoing connections for every node.
  11. outputs map[string]map[string]int
  12. // How many parents each node has.
  13. inputs map[string]int
  14. }
  15. // NewGraph initializes a new Graph.
  16. func NewGraph() *Graph {
  17. return &Graph{
  18. inputs: map[string]int{},
  19. outputs: map[string]map[string]int{},
  20. }
  21. }
  22. // Copy clones the graph and returns the independent copy.
  23. func (g *Graph) Copy() *Graph {
  24. clone := NewGraph()
  25. for k, v := range g.inputs {
  26. clone.inputs[k] = v
  27. }
  28. for k1, v1 := range g.outputs {
  29. m := map[string]int{}
  30. clone.outputs[k1] = m
  31. for k2, v2 := range v1 {
  32. m[k2] = v2
  33. }
  34. }
  35. return clone
  36. }
  37. // AddNode inserts a new node into the graph.
  38. func (g *Graph) AddNode(name string) bool {
  39. if _, exists := g.outputs[name]; exists {
  40. return false
  41. }
  42. g.outputs[name] = make(map[string]int)
  43. g.inputs[name] = 0
  44. return true
  45. }
  46. // AddNodes inserts multiple nodes into the graph at once.
  47. func (g *Graph) AddNodes(names ...string) bool {
  48. for _, name := range names {
  49. if ok := g.AddNode(name); !ok {
  50. return false
  51. }
  52. }
  53. return true
  54. }
  55. // AddEdge inserts the link from "from" node to "to" node.
  56. func (g *Graph) AddEdge(from, to string) int {
  57. m, ok := g.outputs[from]
  58. if !ok {
  59. return 0
  60. }
  61. m[to] = len(m) + 1
  62. ni := g.inputs[to] + 1
  63. g.inputs[to] = ni
  64. return ni
  65. }
  66. // ReindexNode updates the internal representation of the node after edge removals.
  67. func (g *Graph) ReindexNode(node string) {
  68. children, ok := g.outputs[node]
  69. if !ok {
  70. return
  71. }
  72. keys := []string{}
  73. for key := range children {
  74. keys = append(keys, key)
  75. }
  76. sort.Strings(keys)
  77. for i, key := range keys {
  78. children[key] = i + 1
  79. }
  80. }
  81. func (g *Graph) unsafeRemoveEdge(from, to string) {
  82. delete(g.outputs[from], to)
  83. g.inputs[to]--
  84. }
  85. // RemoveEdge deletes the link from "from" node to "to" node.
  86. // Call ReindexNode(from) after you finish modifying the edges.
  87. func (g *Graph) RemoveEdge(from, to string) bool {
  88. if _, ok := g.outputs[from]; !ok {
  89. return false
  90. }
  91. g.unsafeRemoveEdge(from, to)
  92. return true
  93. }
  94. // Toposort sorts the nodes in the graph in topological order.
  95. func (g *Graph) Toposort() ([]string, bool) {
  96. L := make([]string, 0, len(g.outputs))
  97. S := make([]string, 0, len(g.outputs))
  98. for n := range g.outputs {
  99. if g.inputs[n] == 0 {
  100. S = append(S, n)
  101. }
  102. }
  103. sort.Strings(S)
  104. for len(S) > 0 {
  105. var n string
  106. n, S = S[0], S[1:]
  107. L = append(L, n)
  108. ms := make([]string, len(g.outputs[n]))
  109. for m, i := range g.outputs[n] {
  110. ms[i-1] = m
  111. }
  112. for _, m := range ms {
  113. g.unsafeRemoveEdge(n, m)
  114. if g.inputs[m] == 0 {
  115. S = append(S, m)
  116. }
  117. }
  118. }
  119. N := 0
  120. for _, v := range g.inputs {
  121. N += v
  122. }
  123. if N > 0 {
  124. return L, false
  125. }
  126. return L, true
  127. }
  128. // BreadthSort sorts the nodes in the graph in BFS order.
  129. func (g *Graph) BreadthSort() []string {
  130. L := make([]string, 0, len(g.outputs))
  131. S := make([]string, 0, len(g.outputs))
  132. for n := range g.outputs {
  133. if g.inputs[n] == 0 {
  134. S = append(S, n)
  135. }
  136. }
  137. visited := map[string]bool{}
  138. for len(S) > 0 {
  139. node := S[0]
  140. S = S[1:]
  141. if _, exists := visited[node]; !exists {
  142. L = append(L, node)
  143. visited[node] = true
  144. for child := range g.outputs[node] {
  145. S = append(S, child)
  146. }
  147. }
  148. }
  149. return L
  150. }
  151. // FindCycle returns the cycle in the graph which contains "seed" node.
  152. func (g *Graph) FindCycle(seed string) []string {
  153. type edge struct {
  154. node string
  155. parent string
  156. }
  157. S := make([]edge, 0, len(g.outputs))
  158. S = append(S, edge{seed, ""})
  159. visited := map[string]string{}
  160. for len(S) > 0 {
  161. e := S[0]
  162. S = S[1:]
  163. if parent, exists := visited[e.node]; !exists || parent == "" {
  164. visited[e.node] = e.parent
  165. for child := range g.outputs[e.node] {
  166. S = append(S, edge{child, e.node})
  167. }
  168. }
  169. if e.node == seed && e.parent != "" {
  170. result := []string{}
  171. node := e.parent
  172. for node != seed {
  173. result = append(result, node)
  174. node = visited[node]
  175. }
  176. result = append(result, seed)
  177. // reverse
  178. for left, right := 0, len(result)-1; left < right; left, right = left+1, right-1 {
  179. result[left], result[right] = result[right], result[left]
  180. }
  181. return result
  182. }
  183. }
  184. return []string{}
  185. }
  186. // FindParents returns the other ends of incoming edges.
  187. func (g *Graph) FindParents(to string) []string {
  188. result := []string{}
  189. for node, children := range g.outputs {
  190. if _, exists := children[to]; exists {
  191. result = append(result, node)
  192. }
  193. }
  194. return result
  195. }
  196. // FindChildren returns the other ends of outgoing edges.
  197. func (g *Graph) FindChildren(from string) []string {
  198. result := []string{}
  199. for child := range g.outputs[from] {
  200. result = append(result, child)
  201. }
  202. sort.Strings(result)
  203. return result
  204. }
  205. // Serialize outputs the graph in Graphviz format.
  206. func (g *Graph) Serialize(sorted []string) string {
  207. node2index := map[string]int{}
  208. for index, node := range sorted {
  209. node2index[node] = index
  210. }
  211. var buffer bytes.Buffer
  212. buffer.WriteString("digraph Hercules {\n")
  213. nodesFrom := []string{}
  214. for nodeFrom := range g.outputs {
  215. nodesFrom = append(nodesFrom, nodeFrom)
  216. }
  217. sort.Strings(nodesFrom)
  218. for _, nodeFrom := range nodesFrom {
  219. links := []string{}
  220. for nodeTo := range g.outputs[nodeFrom] {
  221. links = append(links, nodeTo)
  222. }
  223. sort.Strings(links)
  224. for _, nodeTo := range links {
  225. buffer.WriteString(fmt.Sprintf(" \"%d %s\" -> \"%d %s\"\n",
  226. node2index[nodeFrom], nodeFrom, node2index[nodeTo], nodeTo))
  227. }
  228. }
  229. buffer.WriteString("}")
  230. return buffer.String()
  231. }
  232. func (g *Graph) DebugDump() string {
  233. S := make([]string, 0, len(g.outputs))
  234. for n := range g.outputs {
  235. if g.inputs[n] == 0 {
  236. S = append(S, n)
  237. }
  238. }
  239. sort.Strings(S)
  240. var buffer bytes.Buffer
  241. buffer.WriteString(strings.Join(S, " ") + "\n")
  242. keys := []string{}
  243. vals := map[string][]string{}
  244. for key, val1 := range g.outputs {
  245. val2 := make([]string, len(val1))
  246. for name, idx := range val1 {
  247. val2[idx-1] = name
  248. }
  249. keys = append(keys, key)
  250. vals[key] = val2
  251. }
  252. sort.Strings(keys)
  253. for _, key := range keys {
  254. buffer.WriteString(fmt.Sprintf("%s %d = ", key, g.inputs[key]))
  255. outs := vals[key]
  256. buffer.WriteString(strings.Join(outs, " ") + "\n")
  257. }
  258. return buffer.String()
  259. }