rgl 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,61 +1,72 @@
1
+ # topsort.rb
2
+
1
3
  require 'rgl/traversal'
2
4
 
3
5
  module RGL
6
+
4
7
  # Topological Sort Iterator
5
8
  #
6
- # The topological sort algorithm creates a linear ordering
7
- # of the vertices such that if edge (u,v) appears in the graph,
8
- # then u comes before v in the ordering. The graph must
9
- # be a directed acyclic graph (DAG).
9
+ # The topological sort algorithm creates a linear ordering of the vertices
10
+ # such that if edge (u,v) appears in the graph, then u comes before v in
11
+ # the ordering. The graph must be a directed acyclic graph (DAG).
10
12
  #
11
- # The iterator can also be applied to undirected graph or a DG graph which
12
- # contains a cycle. In this case the Iterator does not reach all vertices. The
13
- # implementation of acyclic? uses this fact.
13
+ # The iterator can also be applied to undirected graph or to a DG graph
14
+ # which contains a cycle. In this case, the Iterator does not reach all
15
+ # vertices. The implementation of acyclic? uses this fact.
16
+
14
17
  class TopsortIterator
15
- include GraphIterator
16
- def initialize(g)
17
- super g
18
- set_to_begin
19
- end
20
-
21
- def set_to_begin # :nodoc:
22
- @waiting = Array.new
23
- @inDegrees = Hash.new(0)
24
-
25
- graph.each_vertex do |u|
26
- @inDegrees[u] = 0 unless @inDegrees.has_key? u
27
- graph.each_adjacent(u) do |v|
28
- @inDegrees[v] += 1
29
- end
30
- end
31
- @inDegrees.each_pair do |v, indegree |
32
- @waiting.push(v) if indegree.zero?
33
- end
34
- end
35
-
36
- def basic_forward # :nodoc:
37
- u = @waiting.pop
38
- graph.each_adjacent(u) do |v|
39
- @inDegrees[v] -= 1
40
- @waiting.push(v) if @inDegrees[v].zero?
41
- end
42
- u
43
- end
44
-
45
- def at_beginning?; true; end # :nodoc: FIXME
46
- def at_end?; @waiting.empty?; end # :nodoc:
47
- end
18
+
19
+ include GraphIterator
20
+
21
+ def initialize (g)
22
+ super(g)
23
+ set_to_begin
24
+ end
25
+
26
+ def set_to_begin # :nodoc:
27
+ @waiting = Array.new
28
+ @inDegrees = Hash.new(0)
29
+
30
+ graph.each_vertex do |u|
31
+ @inDegrees[u] = 0 unless @inDegrees.has_key?(u)
32
+ graph.each_adjacent(u) do |v|
33
+ @inDegrees[v] += 1
34
+ end
35
+ end
36
+
37
+ @inDegrees.each_pair do |v, indegree|
38
+ @waiting.push(v) if indegree.zero?
39
+ end
40
+ end
41
+
42
+ def basic_forward # :nodoc:
43
+ u = @waiting.pop
44
+ graph.each_adjacent(u) do |v|
45
+ @inDegrees[v] -= 1
46
+ @waiting.push(v) if @inDegrees[v].zero?
47
+ end
48
+ u
49
+ end
50
+
51
+ def at_beginning?; true; end # :nodoc: FIXME
52
+ def at_end?; @waiting.empty?; end # :nodoc:
53
+
54
+ end # class TopsortIterator
48
55
 
49
56
  module Graph
50
- # Returns a TopsortIterator.
51
- def topsort_iterator
52
- TopsortIterator.new(self)
53
- end
54
-
55
- # Returns true if the graph contains no cycle. This is only meaningful for
56
- # directed graphs. Returns false for undirected graph.
57
- def acyclic?
58
- topsort_iterator.length == num_vertices
59
- end
60
- end
61
- end
57
+
58
+ # Returns a TopsortIterator.
59
+
60
+ def topsort_iterator
61
+ TopsortIterator.new(self)
62
+ end
63
+
64
+ # Returns true if the graph contains no cycles. This is only meaningful
65
+ # for directed graphs. Returns false for undirected graphs.
66
+
67
+ def acyclic?
68
+ topsort_iterator.length == num_vertices
69
+ end
70
+
71
+ end # module Graph
72
+ end # module RGL
@@ -1,34 +1,46 @@
1
+ # transitiv_closure.rb
2
+ #
1
3
  # == transitive_closure
2
4
  #
3
- # The transitive closure of a graph G = (V,E) is a graph G* = (V,E*) such that E*
4
- # contains an edge (u,v) if and only if G contains a path (of at least one edge)
5
- # from u to v. The transitive_closure() function transforms the input graph g into
6
- # the transitive closure graph tc.
5
+ # The transitive closure of a graph G = (V,E) is a graph G* = (V,E*),
6
+ # such that E* contains an edge (u,v) if and only if G contains a path
7
+ # (of at least one edge) from u to v. The transitive_closure() function
8
+ # transforms the input graph g into the transitive closure graph tc.
9
+
7
10
  require 'rgl/adjacency'
8
11
 
9
12
  module RGL
13
+
10
14
  module Graph
11
- # Floyd-Warshal algorithm which should be O(n^3) where n is the number of
12
- # nodes. We can probably work a bit on the constant factors!
13
- #
14
- # In BGL there is an algorithm with time complexity (worst-case) O(|V||E|)
15
- # (see BOOST_DOC/transitive_closure.html) based on the detection of strong components.
16
- def transitive_closure_floyd_warshal
17
- raise NotDirectedError, "transitive_closure makes only sense for directed graphs." unless directed?
18
- tc = to_adjacency # direct links
19
-
20
- # indirect links
21
- each_vertex do |vi|
22
- each_vertex do |vj|
23
- each_vertex do |vk|
24
- unless tc.has_edge?(vi,vj)
25
- tc.add_edge(vi, vj) if has_edge?(vi,vk) and has_edge?(vk,vj)
26
- end
27
- end
28
- end
29
- end
30
- tc
31
- end
32
- alias_method :transitive_closure, :transitive_closure_floyd_warshal
33
- end
34
- end
15
+
16
+ # Floyd-Warshal algorithm which should be O(n^3), where n is the number of
17
+ # nodes. We can probably work a bit on the constant factors!
18
+ #
19
+ # In BGL, there is an algorithm with time complexity (worst-case) O(|V||E|)
20
+ # (see BOOST_DOC/transitive_closure.html), based on the detection of strong
21
+ # components.
22
+
23
+ def transitive_closure_floyd_warshal
24
+ raise NotDirectedError,
25
+ "transitive_closure makes sense only for directed graphs." unless directed?
26
+ tc = to_adjacency # direct links
27
+
28
+ # indirect links
29
+
30
+ each_vertex do |vi|
31
+ each_vertex do |vj|
32
+ each_vertex do |vk|
33
+ unless tc.has_edge?(vi, vj)
34
+ tc.add_edge(vi, vj) if has_edge?(vi, vk) and
35
+ has_edge?(vk, vj)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ tc
41
+ end
42
+
43
+ alias_method :transitive_closure, :transitive_closure_floyd_warshal
44
+
45
+ end # module Graph
46
+ end # module RGL
@@ -1,296 +1,349 @@
1
- # This files defines the basic graph traversal algorithm DFS and BFS
2
- # search. They are implemented as an RGL::GraphIterator which is a Stream of
3
- # vertices of a given graph. The streams are not reversable.
1
+ # traversal.rb
4
2
  #
5
- # Beside being an iterator in the sense of the Stream mixin RGL::BFSIterator and
6
- # RGL::DFSIterator follow the BGL Visitor Concepts (see
7
- # BOOST_DOC/visitor_concepts.html) in a slightly modified fashion (especially
8
- # for the DFSIterator).
3
+ # This file defines the basic graph traversal algorithm for DFS and BFS search.
4
+ # They are implemented as an RGL::GraphIterator, which is a Stream of vertices
5
+ # of a given graph. The streams are not reversable.
6
+ #
7
+ # Beside being an iterator in the sense of the Stream mixin, RGL::BFSIterator
8
+ # and RGL::DFSIterator follow the BGL
9
+ # Visitor[http://www.boost.org/libs/graph/doc/visitor_concepts.html] Concepts
10
+ # in a slightly modified fashion (especially for the RGL::DFSIterator).
9
11
 
10
12
  require 'rgl/base'
11
13
  require 'rubygems' rescue LoadError # If using stream gem
12
14
  require 'stream'
13
15
 
14
16
  module RGL
15
- module GraphWrapper # :nodoc:
16
- attr_accessor :graph
17
17
 
18
- # Creates a new GraphWrapper on _graph_.
19
- def initialize(graph); @graph = graph; end
20
- end
18
+ module GraphWrapper # :nodoc:
19
+
20
+ attr_accessor :graph
21
+
22
+ # Creates a new GraphWrapper on _graph_.
23
+ def initialize (graph)
24
+ @graph = graph
25
+ end
26
+
27
+ end # module GraphWrapper
21
28
 
22
- # A GraphIterator is the abstract superclass of all Iterators on graphs. Each
23
- # such iterator should implement the protocol defined in module Stream.
29
+ # A GraphIterator is the abstract superclass of all Iterators on graphs.
30
+ # Each such iterator should implement the protocol defined in module Stream.
24
31
  module GraphIterator
25
- include Stream
26
- include GraphWrapper
32
+ include Stream
33
+ include GraphWrapper
27
34
  end
28
35
 
29
- # Module GraphVisitor defines the BGL BFS Visitor Concept (see
30
- # BOOST_DOC/BFSVisitor.html).
36
+ # Module GraphVisitor defines the BGL
37
+ # BFS[http://www.boost.org/libs/graph/doc/BFSVisitor.html] Visitor Concept).
31
38
  #
32
- # Visitors provide a mechanism for extending an algorithm; for customizing
33
- # what is done at each step of the algorithm. They allow the user to insert
34
- # their own operations at various steps within a graph algorithm.
39
+ # Visitors provide a mechanism for extending an algorithm (i.e., for
40
+ # customizing what is done at each step of the algorithm). They allow users
41
+ # to insert their own operations at various steps within a graph algorithm.
35
42
  #
36
43
  # Graph algorithms typically have multiple event points where one may want to
37
- # insert a call-back. Therefore visitors have several methods that correspond
38
- # to the various event points. Each algorithm has a different set of event
39
- # points. The following are are common to both DFS and BFS search.
44
+ # insert a call-back. Therefore, visitors have several methods that
45
+ # correspond to the various event points. Each algorithm has a different
46
+ # set of event points. The following are common to both DFS and BFS search.
40
47
  #
41
- # * examine_vertex
42
- # * finish_vertex
43
- # * examine_edge
44
- # * tree_edge
45
- # * back_edge
46
- # * forward_edge
48
+ # * examine_vertex
49
+ # * finish_vertex
50
+ # * examine_edge
51
+ # * tree_edge
52
+ # * back_edge
53
+ # * forward_edge
47
54
  #
48
- # These methods are all called handle_* and can be set to appropriate blocks
55
+ # These methods are all called handle_* and can be set to appropriate blocks,
49
56
  # using the methods set_*_event_handler, which are defined for each event
50
57
  # mentioned above.
51
58
  #
52
- # As an alternative you can also overide the handle_* methods
53
- # in a subclass to configure the algorithm (as an example see
54
- # TarjanSccVisitor).
59
+ # As an alternative, you can also override the handle_* methods in a
60
+ # subclass, to configure the algorithm (as an example, see TarjanSccVisitor).
55
61
  #
56
- # During a graph traversal vertices are *colored* using the colors :GRAY
57
- # (when waiting) and :BLACK when finished. All other vertices are :WHITE.
62
+ # During a graph traversal, vertices are *colored* using the colors :GRAY
63
+ # (when waiting) and :BLACK when finished. All other vertices are :WHITE.
58
64
  # The color_map is also maintained in the visitor.
65
+
59
66
  module GraphVisitor
60
- include GraphWrapper
61
- attr_reader :color_map
62
-
63
- # Create a new GraphVisitor on _graph_.
64
- def initialize(graph)
65
- super graph
66
- reset
67
- end
68
-
69
- # Mark each vertex unvisited (i.e. :WHITE)
70
- def reset
71
- @color_map = Hash.new(:WHITE)
72
- end
73
-
74
- # Returns true if vertex _v_ is colored :BLACK (i.e. finished)
75
- def finished_vertex? v
76
- @color_map[v] == :BLACK
77
- end
67
+
68
+ include GraphWrapper
69
+
70
+ attr_reader :color_map
71
+
72
+ # Create a new GraphVisitor on _graph_.
73
+
74
+ def initialize (graph)
75
+ super graph
76
+ reset
77
+ end
78
+
79
+ # Mark each vertex unvisited (i.e. :WHITE)
80
+
81
+ def reset
82
+ @color_map = Hash.new(:WHITE)
83
+ end
84
+
85
+ # Returns true if vertex _v_ is colored :BLACK (i.e. finished).
86
+
87
+ def finished_vertex? (v)
88
+ @color_map[v] == :BLACK
89
+ end
78
90
 
79
- # Attach a map to the visitor which records the distance of a visited
80
- # vertex to the start vertex.
81
- #
82
- # This is similar to BGLs distance_recorder (see
83
- # BOOST_DOC/distance_recorder.html).
84
- #
85
- # After the distance_map is attached, the visitor has a new method
86
- # distance_to_root, which answers the distance to the start vertex.
87
- def attach_distance_map(map=Hash.new(0))
88
- @dist_map = map
89
- class << self
90
- def handle_tree_edge(u,v)
91
- super
92
- @dist_map[v] = @dist_map[u] + 1
93
- end
94
-
95
- # Answer the distance to the start vertex.
96
- def distance_to_root(v)
97
- @dist_map[v]
98
- end
99
- end
100
- end
101
-
102
- # Shell we follow the edge (u,v) i.e. v has color :WHITE
103
- def follow_edge?(u,v) # :nodoc:
104
- @color_map[v] == :WHITE
105
- end
106
-
107
- # == Visitor Event Points
108
- def self.def_event_handler(m)
109
- params = m =~ /edge/ ? "u,v" : "u"
110
- self.class_eval %{
111
- def handle_#{m}(#{params})
112
- @#{m}_event_handler.call(#{params}) if defined? @#{m}_event_handler
113
- end
114
- def set_#{m}_event_handler(&b)
115
- @#{m}_event_handler = b
116
- end
117
- }
118
- end
119
-
120
- %w[examine_vertex finish_vertex examine_edge tree_edge back_edge forward_edge].each do |m|
121
- def_event_handler(m)
122
- end
123
- end # GraphVisitor
91
+ # Attach a map to the visitor which records the distance of a visited
92
+ # vertex to the start vertex.
93
+ #
94
+ # This is similar to BGLs
95
+ # distance_recorder[http://www.boost.org/libs/graph/doc/distance_recorder.html].
96
+ #
97
+ # After the distance_map is attached, the visitor has a new method
98
+ # distance_to_root, which answers the distance to the start vertex.
99
+
100
+ def attach_distance_map (map = Hash.new(0))
101
+ @dist_map = map
102
+
103
+ class << self
104
+
105
+ def handle_tree_edge (u, v)
106
+ super
107
+ @dist_map[v] = @dist_map[u] + 1
108
+ end
109
+
110
+ # Answer the distance to the start vertex.
111
+
112
+ def distance_to_root (v)
113
+ @dist_map[v]
114
+ end
115
+
116
+ end # class
117
+ end
118
+
119
+ # Shall we follow the edge (u,v); i.e. v has color :WHITE
120
+
121
+ def follow_edge? (u, v) # :nodoc:
122
+ @color_map[v] == :WHITE
123
+ end
124
+
125
+ # == Visitor Event Points
126
+
127
+ def self.def_event_handler (m)
128
+ params = m =~ /edge/ ? "u,v" : "u"
129
+ self.class_eval %{
130
+ def handle_#{m} (#{params})
131
+ @#{m}_event_handler.call(#{params}) if defined? @#{m}_event_handler
132
+ end
133
+
134
+ def set_#{m}_event_handler (&b)
135
+ @#{m}_event_handler = b
136
+ end
137
+ }
138
+ end
139
+
140
+ %w[examine_vertex finish_vertex examine_edge tree_edge back_edge
141
+ forward_edge].each do |m|
142
+ def_event_handler(m)
143
+ end
144
+
145
+ end # module GraphVisitor
124
146
 
125
147
  # A BFSIterator can be used to traverse a graph from a given start vertex in
126
- # breath first search order. Since the Iterator also mixins the GraphVisitor
148
+ # breath first search order. Since the Iterator also mixins the GraphVisitor,
127
149
  # it provides all event points defined there.
128
150
  #
129
- # The vertices which are not yet visited are hold in the queue
130
- # @waiting. During the traversal vertices are *colored* using the colors :GRAY
131
- # (when waiting) and :BLACK when finished. All other vertices are :WHITE.
151
+ # The vertices which are not yet visited are held in the queue @waiting.
152
+ # During the traversal, vertices are *colored* using the colors :GRAY
153
+ # (when waiting) and :BLACK when finished. All other vertices are :WHITE.
132
154
  #
133
- # For more doc see the BGL BFS Visitor Concept
134
- # BOOST_DOC/BFSVisitor.html.
155
+ # For more doc see the BGL
156
+ # BFS[http://www.boost.org/libs/graph/doc/BFSVisitor.html] Visitor Concept .
135
157
  #
136
158
  # See the implementation of bfs_search_tree_from for an example usage.
159
+
137
160
  class BFSIterator
138
- include GraphIterator
139
- include GraphVisitor
140
- attr_accessor :start_vertex
141
-
142
- # Create a new BFSIterator on _graph_ starting at vertex _start_.
143
- def initialize(graph, start=graph.detect{|x| true})
144
- super graph
145
- @start_vertex = start
146
- set_to_begin
147
- end
148
-
149
- # Returns true if the @color_map has only one entry (for the start vertex).
150
- def at_beginning?; @color_map.size == 1; end # :nodoc:
151
-
152
- # Returns true if @waiting is empty.
153
- def at_end?; @waiting.empty?; end
154
-
155
- # Reset the iterator to the initial state (i.e. at_beginning? == true).
156
- def set_to_begin
157
- color_map[@start_vertex] = :GRAY
158
- @waiting = [@start_vertex] # a queue
159
- handle_tree_edge(nil,@start_vertex) # discovers start vertex
160
- end
161
-
162
- def basic_forward # :nodoc:
163
- u = next_vertex
164
- handle_examine_vertex(u)
165
- graph.each_adjacent(u) { |v|
166
- handle_examine_edge(u,v)
167
- if follow_edge? u,v # (u,v) is a tree edge
168
- handle_tree_edge(u,v) # also discovers v
169
- color_map[v] = :GRAY # color of v was :WHITE
170
- @waiting.push v
171
- else # (u,v) is a non tree edge
172
- if color_map[v] == :GRAY
173
- handle_back_edge(u,v) # (u,v) has gray target
174
- else
175
- handle_forward_edge(u,v) # (u,v) has black target
176
- end
177
- end
178
- }
179
- color_map[u] = :BLACK
180
- handle_finish_vertex(u) # finish vertex
181
- u
182
- end
183
-
184
- protected
185
-
186
- def next_vertex () # :nodoc:
187
- # waiting is a queue
188
- @waiting.shift
189
- end
190
- end # BFSIterator
161
+
162
+ include GraphIterator
163
+ include GraphVisitor
164
+
165
+ attr_accessor :start_vertex
166
+
167
+ # Create a new BFSIterator on _graph_, starting at vertex _start_.
168
+
169
+ def initialize (graph, start=graph.detect{ |x| true })
170
+ super(graph)
171
+ @start_vertex = start
172
+ set_to_begin
173
+ end
174
+
175
+ # Returns true if the @color_map has only one entry (for the start vertex).
176
+
177
+ def at_beginning? # :nodoc:
178
+ @color_map.size == 1
179
+ end
180
+
181
+ # Returns true if @waiting is empty.
182
+
183
+ def at_end?
184
+ @waiting.empty?
185
+ end
186
+
187
+ # Reset the iterator to the initial state (i.e. at_beginning? == true).
188
+
189
+ def set_to_begin
190
+ color_map[@start_vertex] = :GRAY
191
+ @waiting = [@start_vertex] # a queue
192
+ handle_tree_edge(nil, @start_vertex) # discovers start vertex
193
+ end
194
+
195
+ def basic_forward # :nodoc:
196
+ u = next_vertex
197
+ handle_examine_vertex(u)
198
+ graph.each_adjacent(u) { |v|
199
+ handle_examine_edge(u, v)
200
+ if follow_edge?(u, v) # (u,v) is a tree edge
201
+ handle_tree_edge(u, v) # also discovers v
202
+ color_map[v] = :GRAY # color of v was :WHITE
203
+ @waiting.push(v)
204
+ else # (u,v) is a non tree edge
205
+ if color_map[v] == :GRAY
206
+ handle_back_edge(u, v) # (u,v) has gray target
207
+ else
208
+ handle_forward_edge(u, v) # (u,v) has black target
209
+ end
210
+ end
211
+ }
212
+ color_map[u] = :BLACK
213
+ handle_finish_vertex(u) # finish vertex
214
+ u
215
+ end
216
+
217
+ protected
218
+
219
+ def next_vertex # :nodoc:
220
+ # waiting is a queue
221
+ @waiting.shift
222
+ end
223
+ end # class BFSIterator
224
+
191
225
 
192
226
  module Graph
193
- # Returns a BFSIterator staring at vertex _v_.
194
- def bfs_iterator (v=self.detect {|x| true})
195
- BFSIterator.new(self,v)
196
- end
197
-
198
- # Returns a DirectedAdjacencyGraph which represents a BFS search tree
199
- # starting at _v_. This methods uses the tree_edge_event of BFSIterator to
200
- # record all tree edges of the search tree in the result.
201
- def bfs_search_tree_from(v)
202
- require 'rgl/adjacency'
203
- bfs = bfs_iterator(v)
204
- tree = DirectedAdjacencyGraph.new
205
- bfs.set_tree_edge_event_handler {|from, to|
206
- tree.add_edge from, to
207
- }
208
- bfs.set_to_end # does the search
209
- tree
210
- end
211
- end
212
227
 
213
- # Iterator for a depth first search starting at a given vertex. The only
214
- # difference to BFSIterator is that @waiting is a stack instead of a queue.
228
+ # Returns a BFSIterator, starting at vertex _v_.
229
+
230
+ def bfs_iterator (v = self.detect { |x| true})
231
+ BFSIterator.new(self, v)
232
+ end
233
+
234
+ # Returns a DirectedAdjacencyGraph, which represents a BFS search tree
235
+ # starting at _v_. This method uses the tree_edge_event of BFSIterator
236
+ # to record all tree edges of the search tree in the result.
237
+
238
+ def bfs_search_tree_from (v)
239
+ require 'rgl/adjacency'
240
+ bfs = bfs_iterator(v)
241
+ tree = DirectedAdjacencyGraph.new
242
+ bfs.set_tree_edge_event_handler { |from, to|
243
+ tree.add_edge(from, to)
244
+ }
245
+ bfs.set_to_end # does the search
246
+ tree
247
+ end
248
+
249
+ end # module Graph
250
+
251
+
252
+ # Iterator for a depth first search, starting at a given vertex. The only
253
+ # difference from BFSIterator is that @waiting is a stack, instead of a queue.
215
254
  #
216
- # Note that this is different to DFSVisitor which is used in the recursive
255
+ # Note that this is different from DFSVisitor, which is used in the recursive
217
256
  # version for depth first search (see depth_first_search).
257
+
218
258
  class DFSIterator < BFSIterator
219
- def next_vertex
220
- # waiting is a stack
221
- @waiting.pop
222
- end
223
- end
224
259
 
225
- # A DFSVisitor is needed by the depth_first_search and
226
- # depth_first_visit methods of a graph. Besides the eventpoint of GraphVisitor
227
- # it provides an additional eventpoint start_vertex, which is called when a
228
- # depth_first_search starts a new subtree of the depth first forest defined by
229
- # the search.
260
+ def next_vertex
261
+ # waiting is a stack
262
+ @waiting.pop
263
+ end
264
+
265
+ end # class DFSIterator
266
+
267
+
268
+ # A DFSVisitor is needed by the depth_first_search and depth_first_visit
269
+ # methods of a graph. Besides the eventpoint of GraphVisitor, it provides
270
+ # an additional eventpoint start_vertex, which is called when a
271
+ # depth_first_search starts a new subtree of the depth first forest that is
272
+ # defined by the search.
230
273
  #
231
- # Note that the discover_vertex event defined in the BGL DFSVisitor
232
- # (BOOST_DOC/DFSVisitor.html) is not provided. Use examine_vertex instead
233
- # which is also defined in the common mixin GraphVisitor of DFSVisitor,
234
- # DFSIterator and BFSIterator.
274
+ # Note that the discover_vertex event defined in the BGL
275
+ # DFSVisitor[http://www.boost.org/libs/graph/doc/DFSVisitor.html] is not
276
+ # this is also defined in the common mixin GraphVisitor of DFSVisitor,
277
+ # DFSIterator, and BFSIterator.
278
+
235
279
  class DFSVisitor
236
- include GraphVisitor
237
280
 
238
- GraphVisitor.def_event_handler("start_vertex")
239
- end
281
+ include GraphVisitor
282
+
283
+ GraphVisitor.def_event_handler("start_vertex")
284
+
285
+ end # class DFSVisitor
286
+
240
287
 
241
288
  module Graph
242
- # Returns a DFSIterator staring at vertex _v_.
243
- def dfs_iterator (v=self.detect {|x| true})
244
- DFSIterator.new(self,v)
245
- end
246
-
247
- # Do a recursive DFS search on the whole graph. If a block is passed, it is
248
- # called on each _finish_vertex_ event. See strongly_connected_components for
249
- # an example usage.
250
- def depth_first_search (vis = DFSVisitor.new(self),&b)
251
- each_vertex do |u|
252
- unless vis.finished_vertex? u
253
- vis.handle_start_vertex u
254
- depth_first_visit(u,vis,&b)
255
- end
256
- end
257
- end
258
-
259
- # Start a depth first search at vertex _u_. The block _b_ is called on each
260
- # finish_vertex event.
261
- def depth_first_visit (u, vis = DFSVisitor.new(self), &b)
262
- vis.color_map[u] = :GRAY
263
- vis.handle_examine_vertex(u)
264
- each_adjacent(u) { |v|
265
- vis.handle_examine_edge(u,v)
266
- if vis.follow_edge? u,v # (u,v) is a tree edge
267
- vis.handle_tree_edge(u,v) # also discovers v
268
- vis.color_map[v] = :GRAY # color of v was :WHITE
269
- depth_first_visit(v, vis, &b)
270
- else # (u,v) is a non tree edge
271
- if vis.color_map[v] == :GRAY
272
- vis.handle_back_edge(u,v) # (u,v) has gray target
273
- else
274
- vis.handle_forward_edge(u,v) # (u,v) is a cross or forward edge
275
- end
276
- end
277
- }
278
- vis.color_map[u] = :BLACK
279
- vis.handle_finish_vertex(u) # finish vertex
280
- b.call(u)
281
- end
282
- end
289
+
290
+ # Returns a DFSIterator staring at vertex _v_.
291
+
292
+ def dfs_iterator (v = self.detect { |x| true })
293
+ DFSIterator.new(self, v)
294
+ end
295
+
296
+ # Do a recursive DFS search on the whole graph. If a block is passed,
297
+ # it is called on each _finish_vertex_ event. See
298
+ # strongly_connected_components for an example usage.
299
+
300
+ def depth_first_search (vis = DFSVisitor.new(self), &b)
301
+ each_vertex do |u|
302
+ unless vis.finished_vertex?(u)
303
+ vis.handle_start_vertex(u)
304
+ depth_first_visit(u, vis, &b)
305
+ end
306
+ end
307
+ end
308
+
309
+ # Start a depth first search at vertex _u_. The block _b_ is called on
310
+ # each finish_vertex event.
311
+
312
+ def depth_first_visit (u, vis = DFSVisitor.new(self), &b)
313
+ vis.color_map[u] = :GRAY
314
+ vis.handle_examine_vertex(u)
315
+ each_adjacent(u) { |v|
316
+ vis.handle_examine_edge(u, v)
317
+ if vis.follow_edge?(u, v) # (u,v) is a tree edge
318
+ vis.handle_tree_edge(u, v) # also discovers v
319
+ vis.color_map[v] = :GRAY # color of v was :WHITE
320
+ depth_first_visit(v, vis, &b)
321
+ else # (u,v) is a non tree edge
322
+ if vis.color_map[v] == :GRAY
323
+ vis.handle_back_edge(u, v) # (u,v) has gray target
324
+ else
325
+ vis.handle_forward_edge(u, v) # (u,v) is a cross or forward edge
326
+ end
327
+ end
328
+ }
329
+ vis.color_map[u] = :BLACK
330
+ vis.handle_finish_vertex(u) # finish vertex
331
+ b.call(u)
332
+ end
333
+
334
+ end # module Graph
283
335
 
284
336
  =begin
285
337
  def acyclic?
286
- has_cycle = false
287
- dfs = DFSIterator.new(self)
288
- dfs.set_back_edge_event {has_cycle = true}
289
- dfs_each(dfs) do |x|
290
- puts x,has_cycle,dfs.inspect
291
- return false if has_cycle
292
- end
293
- true
338
+ has_cycle = false
339
+ dfs = DFSIterator.new(self)
340
+ dfs.set_back_edge_event {has_cycle = true}
341
+ dfs_each(dfs) do |x|
342
+ puts x,has_cycle,dfs.inspect
343
+ return false if has_cycle
344
+ end
345
+ true
294
346
  end
295
347
  =end
296
- end
348
+
349
+ end # module RGL