traverse.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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 traverse provides basic graph traversal primitives.
  5. package traverse
  6. import (
  7. "golang.org/x/tools/container/intsets"
  8. "k8s.io/kubernetes/third_party/forked/gonum/graph"
  9. "k8s.io/kubernetes/third_party/forked/gonum/graph/internal/linear"
  10. )
  11. // BreadthFirst implements stateful breadth-first graph traversal.
  12. type BreadthFirst struct {
  13. EdgeFilter func(graph.Edge) bool
  14. Visit func(u, v graph.Node)
  15. queue linear.NodeQueue
  16. visited *intsets.Sparse
  17. }
  18. // Walk performs a breadth-first traversal of the graph g starting from the given node,
  19. // depending on the EdgeFilter field and the until parameter if they are non-nil. The
  20. // traversal follows edges for which EdgeFilter(edge) is true and returns the first node
  21. // for which until(node, depth) is true. During the traversal, if the Visit field is
  22. // non-nil, it is called with the nodes joined by each followed edge.
  23. func (b *BreadthFirst) Walk(g graph.Graph, from graph.Node, until func(n graph.Node, d int) bool) graph.Node {
  24. if b.visited == nil {
  25. b.visited = &intsets.Sparse{}
  26. }
  27. b.queue.Enqueue(from)
  28. b.visited.Insert(from.ID())
  29. var (
  30. depth int
  31. children int
  32. untilNext = 1
  33. )
  34. for b.queue.Len() > 0 {
  35. t := b.queue.Dequeue()
  36. if until != nil && until(t, depth) {
  37. return t
  38. }
  39. for _, n := range g.From(t) {
  40. if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(t, n)) {
  41. continue
  42. }
  43. if b.visited.Has(n.ID()) {
  44. continue
  45. }
  46. if b.Visit != nil {
  47. b.Visit(t, n)
  48. }
  49. b.visited.Insert(n.ID())
  50. children++
  51. b.queue.Enqueue(n)
  52. }
  53. if untilNext--; untilNext == 0 {
  54. depth++
  55. untilNext = children
  56. children = 0
  57. }
  58. }
  59. return nil
  60. }
  61. // WalkAll calls Walk for each unvisited node of the graph g using edges independent
  62. // of their direction. The functions before and after are called prior to commencing
  63. // and after completing each walk if they are non-nil respectively. The function
  64. // during is called on each node as it is traversed.
  65. func (b *BreadthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) {
  66. b.Reset()
  67. for _, from := range g.Nodes() {
  68. if b.Visited(from) {
  69. continue
  70. }
  71. if before != nil {
  72. before()
  73. }
  74. b.Walk(g, from, func(n graph.Node, _ int) bool {
  75. if during != nil {
  76. during(n)
  77. }
  78. return false
  79. })
  80. if after != nil {
  81. after()
  82. }
  83. }
  84. }
  85. // Visited returned whether the node n was visited during a traverse.
  86. func (b *BreadthFirst) Visited(n graph.Node) bool {
  87. return b.visited != nil && b.visited.Has(n.ID())
  88. }
  89. // Reset resets the state of the traverser for reuse.
  90. func (b *BreadthFirst) Reset() {
  91. b.queue.Reset()
  92. if b.visited != nil {
  93. b.visited.Clear()
  94. }
  95. }
  96. // DepthFirst implements stateful depth-first graph traversal.
  97. type DepthFirst struct {
  98. EdgeFilter func(graph.Edge) bool
  99. Visit func(u, v graph.Node)
  100. stack linear.NodeStack
  101. visited *intsets.Sparse
  102. }
  103. // Walk performs a depth-first traversal of the graph g starting from the given node,
  104. // depending on the EdgeFilter field and the until parameter if they are non-nil. The
  105. // traversal follows edges for which EdgeFilter(edge) is true and returns the first node
  106. // for which until(node) is true. During the traversal, if the Visit field is non-nil, it
  107. // is called with the nodes joined by each followed edge.
  108. func (d *DepthFirst) Walk(g graph.Graph, from graph.Node, until func(graph.Node) bool) graph.Node {
  109. if d.visited == nil {
  110. d.visited = &intsets.Sparse{}
  111. }
  112. d.stack.Push(from)
  113. d.visited.Insert(from.ID())
  114. for d.stack.Len() > 0 {
  115. t := d.stack.Pop()
  116. if until != nil && until(t) {
  117. return t
  118. }
  119. for _, n := range g.From(t) {
  120. if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(t, n)) {
  121. continue
  122. }
  123. if d.visited.Has(n.ID()) {
  124. continue
  125. }
  126. if d.Visit != nil {
  127. d.Visit(t, n)
  128. }
  129. d.visited.Insert(n.ID())
  130. d.stack.Push(n)
  131. }
  132. }
  133. return nil
  134. }
  135. // WalkAll calls Walk for each unvisited node of the graph g using edges independent
  136. // of their direction. The functions before and after are called prior to commencing
  137. // and after completing each walk if they are non-nil respectively. The function
  138. // during is called on each node as it is traversed.
  139. func (d *DepthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) {
  140. d.Reset()
  141. for _, from := range g.Nodes() {
  142. if d.Visited(from) {
  143. continue
  144. }
  145. if before != nil {
  146. before()
  147. }
  148. d.Walk(g, from, func(n graph.Node) bool {
  149. if during != nil {
  150. during(n)
  151. }
  152. return false
  153. })
  154. if after != nil {
  155. after()
  156. }
  157. }
  158. }
  159. // Visited returned whether the node n was visited during a traverse.
  160. func (d *DepthFirst) Visited(n graph.Node) bool {
  161. return d.visited != nil && d.visited.Has(n.ID())
  162. }
  163. // Reset resets the state of the traverser for reuse.
  164. func (d *DepthFirst) Reset() {
  165. d.stack = d.stack[:0]
  166. if d.visited != nil {
  167. d.visited.Clear()
  168. }
  169. }