github.com/gopherd/gonum@v0.0.4/graph/traverse/traverse.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 traverse 6 7 import ( 8 "github.com/gopherd/gonum/graph" 9 "github.com/gopherd/gonum/graph/internal/linear" 10 "github.com/gopherd/gonum/graph/internal/set" 11 ) 12 13 var _ Graph = graph.Graph(nil) 14 15 // Graph is the subset of graph.Graph necessary for graph traversal. 16 type Graph interface { 17 // From returns all nodes that can be reached directly 18 // from the node with the given ID. 19 From(id int64) graph.Nodes 20 21 // Edge returns the edge from u to v, with IDs uid and vid, 22 // if such an edge exists and nil otherwise. The node v 23 // must be directly reachable from u as defined by 24 // the From method. 25 Edge(uid, vid int64) graph.Edge 26 } 27 28 // BreadthFirst implements stateful breadth-first graph traversal. 29 type BreadthFirst struct { 30 // Visit is called on all nodes on their first visit. 31 Visit func(graph.Node) 32 33 // Traverse is called on all edges that may be traversed 34 // during the walk. This includes edges that would hop to 35 // an already visited node. 36 // 37 // The value returned by Traverse determines whether 38 // an edge can be traversed during the walk. 39 Traverse func(graph.Edge) bool 40 41 queue linear.NodeQueue 42 visited set.Int64s 43 } 44 45 // Walk performs a breadth-first traversal of the graph g starting from the given node, 46 // depending on the Traverse field and the until parameter if they are non-nil. 47 // The traversal follows edges for which Traverse(edge) is true and returns the first node 48 // for which until(node, depth) is true. During the traversal, if the Visit field is 49 // non-nil, it is called with each node the first time it is visited. 50 func (b *BreadthFirst) Walk(g Graph, from graph.Node, until func(n graph.Node, d int) bool) graph.Node { 51 if b.visited == nil { 52 b.visited = make(set.Int64s) 53 } 54 b.queue.Enqueue(from) 55 if b.Visit != nil && !b.visited.Has(from.ID()) { 56 b.Visit(from) 57 } 58 b.visited.Add(from.ID()) 59 60 var ( 61 depth int 62 children int 63 untilNext = 1 64 ) 65 for b.queue.Len() > 0 { 66 t := b.queue.Dequeue() 67 if until != nil && until(t, depth) { 68 return t 69 } 70 tid := t.ID() 71 to := g.From(tid) 72 for to.Next() { 73 n := to.Node() 74 nid := n.ID() 75 if b.Traverse != nil && !b.Traverse(g.Edge(tid, nid)) { 76 continue 77 } 78 if b.visited.Has(nid) { 79 continue 80 } 81 if b.Visit != nil { 82 b.Visit(n) 83 } 84 b.visited.Add(nid) 85 children++ 86 b.queue.Enqueue(n) 87 } 88 if untilNext--; untilNext == 0 { 89 depth++ 90 untilNext = children 91 children = 0 92 } 93 } 94 95 return nil 96 } 97 98 // WalkAll calls Walk for each unvisited node of the graph g using edges independent 99 // of their direction. The functions before and after are called prior to commencing 100 // and after completing each walk if they are non-nil respectively. The function 101 // during is called on each node as it is traversed. 102 func (b *BreadthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) { 103 b.Reset() 104 nodes := g.Nodes() 105 for nodes.Next() { 106 from := nodes.Node() 107 if b.Visited(from) { 108 continue 109 } 110 if before != nil { 111 before() 112 } 113 b.Walk(g, from, func(n graph.Node, _ int) bool { 114 if during != nil { 115 during(n) 116 } 117 return false 118 }) 119 if after != nil { 120 after() 121 } 122 } 123 } 124 125 // Visited returned whether the node n was visited during a traverse. 126 func (b *BreadthFirst) Visited(n graph.Node) bool { 127 return b.visited.Has(n.ID()) 128 } 129 130 // Reset resets the state of the traverser for reuse. 131 func (b *BreadthFirst) Reset() { 132 b.queue.Reset() 133 b.visited = nil 134 } 135 136 // DepthFirst implements stateful depth-first graph traversal. 137 type DepthFirst struct { 138 // Visit is called on all nodes on their first visit. 139 Visit func(graph.Node) 140 141 // Traverse is called on all edges that may be traversed 142 // during the walk. This includes edges that would hop to 143 // an already visited node. 144 // 145 // The value returned by Traverse determines whether an 146 // edge can be traversed during the walk. 147 Traverse func(graph.Edge) bool 148 149 stack linear.NodeStack 150 visited set.Int64s 151 } 152 153 // Walk performs a depth-first traversal of the graph g starting from the given node, 154 // depending on the Traverse field and the until parameter if they are non-nil. 155 // The traversal follows edges for which Traverse(edge) is true and returns the first node 156 // for which until(node) is true. During the traversal, if the Visit field is non-nil, it 157 // is called with each node the first time it is visited. 158 func (d *DepthFirst) Walk(g Graph, from graph.Node, until func(graph.Node) bool) graph.Node { 159 if d.visited == nil { 160 d.visited = make(set.Int64s) 161 } 162 d.stack.Push(from) 163 for d.stack.Len() != 0 { 164 u := d.stack.Pop() 165 uid := u.ID() 166 if d.visited.Has(uid) { 167 continue 168 } 169 d.visited.Add(uid) 170 if d.Visit != nil { 171 d.Visit(u) 172 } 173 if until != nil && until(u) { 174 return u 175 } 176 to := g.From(uid) 177 for to.Next() { 178 v := to.Node() 179 vid := v.ID() 180 if d.Traverse != nil && !d.Traverse(g.Edge(uid, vid)) { 181 continue 182 } 183 d.stack.Push(v) 184 } 185 } 186 187 return nil 188 } 189 190 // WalkAll calls Walk for each unvisited node of the graph g using edges independent 191 // of their direction. The functions before and after are called prior to commencing 192 // and after completing each walk if they are non-nil respectively. The function 193 // during is called on each node as it is traversed. 194 func (d *DepthFirst) WalkAll(g graph.Undirected, before, after func(), during func(graph.Node)) { 195 d.Reset() 196 nodes := g.Nodes() 197 for nodes.Next() { 198 from := nodes.Node() 199 if d.Visited(from) { 200 continue 201 } 202 if before != nil { 203 before() 204 } 205 d.Walk(g, from, func(n graph.Node) bool { 206 if during != nil { 207 during(n) 208 } 209 return false 210 }) 211 if after != nil { 212 after() 213 } 214 } 215 } 216 217 // Visited returned whether the node n was visited during a traverse. 218 func (d *DepthFirst) Visited(n graph.Node) bool { 219 return d.visited.Has(n.ID()) 220 } 221 222 // Reset resets the state of the traverser for reuse. 223 func (d *DepthFirst) Reset() { 224 d.stack = d.stack[:0] 225 d.visited = nil 226 }