rgl 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. data/ChangeLog +19 -10
  2. data/Gemfile +3 -0
  3. data/{README → README.rdoc} +70 -98
  4. data/Rakefile +44 -150
  5. data/examples/canvas.rb +63 -64
  6. data/examples/examples.rb +42 -42
  7. data/examples/graph.dot +46 -0
  8. data/examples/images/example.jpg +0 -0
  9. data/examples/images/module_graph.jpg +0 -0
  10. data/examples/images/rgl_modules.png +0 -0
  11. data/examples/{insel-der-tausend-gefahren.rb → insel_der_tausend_gefahren.rb} +18 -19
  12. data/examples/north.rb +2 -2
  13. data/examples/north2.rb +11 -11
  14. data/examples/rdep-rgl.rb +218 -222
  15. data/lib/rgl/adjacency.rb +78 -74
  16. data/lib/rgl/base.rb +160 -78
  17. data/lib/rgl/bellman_ford.rb +115 -0
  18. data/lib/rgl/bidirectional.rb +17 -10
  19. data/lib/rgl/bipartite.rb +87 -0
  20. data/lib/rgl/condensation.rb +13 -4
  21. data/lib/rgl/connected_components.rb +38 -30
  22. data/lib/rgl/dijkstra.rb +158 -0
  23. data/lib/rgl/dijkstra_visitor.rb +42 -0
  24. data/lib/rgl/dot.rb +40 -32
  25. data/lib/rgl/edge_properties_map.rb +55 -0
  26. data/lib/rgl/edmonds_karp.rb +136 -0
  27. data/lib/rgl/enumerable_ext.rb +4 -1
  28. data/lib/rgl/graph_iterator.rb +15 -0
  29. data/lib/rgl/graph_visitor.rb +138 -0
  30. data/lib/rgl/graph_wrapper.rb +15 -0
  31. data/lib/rgl/graphxml.rb +20 -10
  32. data/lib/rgl/implicit.rb +68 -66
  33. data/lib/rgl/mutable.rb +37 -31
  34. data/lib/rgl/path_builder.rb +40 -0
  35. data/lib/rgl/prim.rb +52 -0
  36. data/lib/rgl/rdot.rb +411 -374
  37. data/lib/rgl/topsort.rb +23 -16
  38. data/lib/rgl/transitivity.rb +29 -27
  39. data/lib/rgl/traversal.rb +67 -205
  40. data/rakelib/dep_graph.rake +4 -3
  41. data/test/bellman_ford_test.rb +187 -0
  42. data/test/bipartite_test.rb +47 -0
  43. data/test/components_test.rb +80 -0
  44. data/test/cycles_test.rb +60 -0
  45. data/test/dijkstra_test.rb +148 -0
  46. data/test/directed_graph_test.rb +118 -0
  47. data/test/dot_test.rb +26 -0
  48. data/test/edge_properties_map_test.rb +63 -0
  49. data/test/edge_test.rb +35 -0
  50. data/test/edmonds_karp_test.rb +105 -0
  51. data/{tests/TestGraph.rb → test/graph_test.rb} +6 -6
  52. data/test/graph_xml_test.rb +57 -0
  53. data/test/implicit_test.rb +53 -0
  54. data/test/prim_test.rb +98 -0
  55. data/{tests/TestRdot.rb → test/rdot_test.rb} +309 -308
  56. data/{tests → test}/test_helper.rb +4 -1
  57. data/{tests/TestTransitivity.rb → test/transitivity_test.rb} +43 -43
  58. data/test/traversal_test.rb +221 -0
  59. data/test/undirected_graph_test.rb +103 -0
  60. metadata +226 -145
  61. data/examples/example.jpg +0 -0
  62. data/examples/module_graph.jpg +0 -0
  63. data/install.rb +0 -49
  64. data/tests/TestComponents.rb +0 -65
  65. data/tests/TestCycles.rb +0 -61
  66. data/tests/TestDirectedGraph.rb +0 -125
  67. data/tests/TestDot.rb +0 -18
  68. data/tests/TestEdge.rb +0 -34
  69. data/tests/TestGraphXML.rb +0 -57
  70. data/tests/TestImplicit.rb +0 -52
  71. data/tests/TestTraversal.rb +0 -220
  72. data/tests/TestUnDirectedGraph.rb +0 -102
@@ -1,6 +1,6 @@
1
1
  # topsort.rb
2
2
 
3
- require 'rgl/traversal'
3
+ require 'rgl/graph_iterator'
4
4
 
5
5
  module RGL
6
6
 
@@ -11,19 +11,19 @@ module RGL
11
11
  # the ordering. The graph must be a directed acyclic graph (DAG).
12
12
  #
13
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
+ # which contains a cycle. In this case, the Iterator does not reach all
15
+ # vertices. The implementation of acyclic? uses this fact.
16
+ #
17
17
  class TopsortIterator
18
18
 
19
19
  include GraphIterator
20
20
 
21
- def initialize (g)
21
+ def initialize(g)
22
22
  super(g)
23
23
  set_to_begin
24
24
  end
25
25
 
26
- def set_to_begin # :nodoc:
26
+ def set_to_begin # :nodoc:
27
27
  @waiting = Array.new
28
28
  @inDegrees = Hash.new(0)
29
29
 
@@ -39,7 +39,7 @@ module RGL
39
39
  end
40
40
  end
41
41
 
42
- def basic_forward # :nodoc:
42
+ def basic_forward # :nodoc:
43
43
  u = @waiting.pop
44
44
  graph.each_adjacent(u) do |v|
45
45
  @inDegrees[v] -= 1
@@ -48,25 +48,32 @@ module RGL
48
48
  u
49
49
  end
50
50
 
51
- def at_beginning?; true; end # :nodoc: FIXME
52
- def at_end?; @waiting.empty?; end # :nodoc:
51
+ def at_beginning?
52
+ true
53
+ end
54
+
55
+ # :nodoc: FIXME
56
+ def at_end?
57
+ @waiting.empty?
58
+ end # :nodoc:
53
59
 
54
- end # class TopsortIterator
60
+ end # class TopsortIterator
55
61
 
56
62
  module Graph
57
63
 
58
64
  # Returns a TopsortIterator.
59
-
65
+ #
60
66
  def topsort_iterator
61
67
  TopsortIterator.new(self)
62
68
  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
69
 
70
+ # Returns true if the graph contains no cycles. This is only meaningful
71
+ # for directed graphs. Returns false for undirected graphs.
72
+ #
67
73
  def acyclic?
68
74
  topsort_iterator.length == num_vertices
69
75
  end
70
76
 
71
- end # module Graph
72
- end # module RGL
77
+ end # module Graph
78
+
79
+ end # module RGL
@@ -1,14 +1,14 @@
1
- require 'enumerator'
2
-
3
- require 'rgl/adjacency'
4
1
  require 'rgl/base'
2
+ require 'rgl/adjacency'
5
3
  require 'rgl/condensation'
6
4
 
7
5
  module RGL
6
+
8
7
  module Graph
8
+
9
9
  # Returns an RGL::DirectedAdjacencyGraph which is the transitive closure of
10
- # this graph. Meaning, for each path u -> ... -> v in this graph, the path
11
- # is copied and the edge u -> v is added. This method supports working with
10
+ # this graph. Meaning, for each path u -> ... -> v in this graph, the path
11
+ # is copied and the edge u -> v is added. This method supports working with
12
12
  # cyclic graphs by ensuring that edges are created between every pair of
13
13
  # vertices in the cycle, including self-referencing edges.
14
14
  #
@@ -16,17 +16,18 @@ module RGL
16
16
  # of vertices and edges respectively.
17
17
  #
18
18
  # Raises RGL::NotDirectedError if run on an undirected graph.
19
+ #
19
20
  def transitive_closure
20
21
  raise NotDirectedError,
21
- "transitive_closure only supported for directed graphs" unless directed?
22
+ "transitive_closure only supported for directed graphs" unless directed?
22
23
 
23
24
  # Compute a condensation graph in order to hide cycles.
24
25
  cg = condensation_graph
25
26
 
26
27
  # Use a depth first search to calculate the transitive closure over the
27
- # condensation graph. This ensures that as we traverse up the graph we
28
+ # condensation graph. This ensures that as we traverse up the graph we
28
29
  # know the transitive closure of each subgraph rooted at each node
29
- # starting at the leaves. Subsequent root nodes which consume these
30
+ # starting at the leaves. Subsequent root nodes which consume these
30
31
  # subgraphs by way of the nodes' immediate successors can then immediately
31
32
  # add edges to the roots of the subgraphs and to every successor of those
32
33
  # roots.
@@ -52,7 +53,7 @@ module RGL
52
53
  # For each NON-trivial strongly connected component in the condensed
53
54
  # graph, add each node it contains to the new graph and add edges to
54
55
  # every node in the strongly connected component, including self
55
- # referential edges. Then for each edge of the original graph from any
56
+ # referential edges. Then for each edge of the original graph from any
56
57
  # of the contained nodes, add edges from each of the contained nodes to
57
58
  # all the edge targets.
58
59
  g = DirectedAdjacencyGraph.new
@@ -61,7 +62,7 @@ module RGL
61
62
  # Add edges between all members of non-trivial strongly connected
62
63
  # components (size > 1) and ensure that self referential edges are
63
64
  # added when necessary for trivial strongly connected components.
64
- if scc.size > 1 || has_edge?(v, v) then
65
+ if scc.size > 1 || has_edge?(v, v)
65
66
  scc.each do |w|
66
67
  g.add_edge(v, w)
67
68
  end
@@ -86,8 +87,8 @@ module RGL
86
87
  end
87
88
 
88
89
  # Returns an RGL::DirectedAdjacencyGraph which is the transitive reduction
89
- # of this graph. Meaning, that each edge u -> v is omitted if path
90
- # u -> ... -> v exists. This method supports working with cyclic graphs;
90
+ # of this graph. Meaning, that each edge u -> v is omitted if path
91
+ # u -> ... -> v exists. This method supports working with cyclic graphs;
91
92
  # however, cycles are arbitrarily simplified which may lead to variant,
92
93
  # although equally valid, results on equivalent graphs.
93
94
  #
@@ -95,17 +96,18 @@ module RGL
95
96
  # of vertices and edges respectively.
96
97
  #
97
98
  # Raises RGL::NotDirectedError if run on an undirected graph.
99
+ #
98
100
  def transitive_reduction
99
101
  raise NotDirectedError,
100
- "transitive_reduction only supported for directed graphs" unless directed?
102
+ "transitive_reduction only supported for directed graphs" unless directed?
101
103
 
102
104
  # Compute a condensation graph in order to hide cycles.
103
105
  cg = condensation_graph
104
106
 
105
107
  # Use a depth first search to compute the transitive reduction over the
106
- # condensed graph. This is similar to the computation of the transitive
108
+ # condensed graph. This is similar to the computation of the transitive
107
109
  # closure over the graph in that for any node of the graph all nodes
108
- # reachable from the node are tracked. Using a depth first search ensures
110
+ # reachable from the node are tracked. Using a depth first search ensures
109
111
  # that all nodes reachable from a target node are known when considering
110
112
  # whether or not to add an edge pointing to that target.
111
113
  tr_cg = DirectedAdjacencyGraph.new
@@ -114,11 +116,9 @@ module RGL
114
116
  paths_from[v] = Set.new
115
117
  cg.each_adjacent(v) do |w|
116
118
  # Only add the edge v -> w if there is no other edge v -> x such that
117
- # w is reachable from x. Make sure to completely skip the case where
119
+ # w is reachable from x. Make sure to completely skip the case where
118
120
  # x == w.
119
- unless Enumerable::Enumerator.new(cg, :each_adjacent, v).any? do |x|
120
- x != w && paths_from[x].include?(w)
121
- end then
121
+ unless cg.to_enum(:each_adjacent, v).any? { |x| x != w && paths_from[x].include?(w) }
122
122
  tr_cg.add_edge(v, w)
123
123
 
124
124
  # For each vertex v, track all nodes reachable from v by adding node
@@ -138,7 +138,7 @@ module RGL
138
138
  # edge the node begins in the original graph.
139
139
  # For each NON-trivial strongly connected component in the condensed
140
140
  # graph, add each node it contains to the new graph and add arbitrary
141
- # edges between the nodes to form a simple cycle. Then for each strongly
141
+ # edges between the nodes to form a simple cycle. Then for each strongly
142
142
  # connected component adjacent to the current one, find and add the first
143
143
  # edge which exists in the original graph, starts in the first strongly
144
144
  # connected component, and ends in the second strongly connected
@@ -148,7 +148,7 @@ module RGL
148
148
  # Make a cycle of the contents of non-trivial strongly connected
149
149
  # components.
150
150
  scc_arr = scc.to_a
151
- if scc.size > 1 || has_edge?(scc_arr.first, scc_arr.first) then
151
+ if scc.size > 1 || has_edge?(scc_arr.first, scc_arr.first)
152
152
  0.upto(scc_arr.size - 2) do |idx|
153
153
  g.add_edge(scc_arr[idx], scc_arr[idx + 1])
154
154
  end
@@ -157,12 +157,12 @@ module RGL
157
157
 
158
158
  # Choose a single edge between the members of two different strongly
159
159
  # connected component to add to the graph.
160
- edges = Enumerable::Enumerator.new(self, :each_edge)
160
+ edges = self.to_enum(:each_edge)
161
161
  tr_cg.each_adjacent(scc) do |scc2|
162
162
  g.add_edge(
163
- *edges.find do |v, w|
164
- scc.member?(v) && scc2.member?(w)
165
- end
163
+ *edges.find do |v, w|
164
+ scc.member?(v) && scc2.member?(w)
165
+ end
166
166
  )
167
167
  end
168
168
 
@@ -175,5 +175,7 @@ module RGL
175
175
  # Finally, the transitive reduction...
176
176
  g
177
177
  end
178
- end # module Graph
179
- end # module RGL
178
+
179
+ end # module Graph
180
+
181
+ end # module RGL
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # This file defines the basic graph traversal algorithm for DFS and BFS search.
4
4
  # They are implemented as an RGL::GraphIterator, which is a Stream of vertices
5
- # of a given graph. The streams are not reversable.
5
+ # of a given graph. The streams are not reversable.
6
6
  #
7
7
  # Beside being an iterator in the sense of the Stream mixin, RGL::BFSIterator
8
8
  # and RGL::DFSIterator follow the BGL
@@ -10,153 +10,24 @@
10
10
  # in a slightly modified fashion (especially for the RGL::DFSIterator).
11
11
 
12
12
  require 'rgl/base'
13
- require 'rubygems' rescue LoadError # If using stream gem
14
- require 'stream'
13
+ require 'rgl/graph_visitor'
14
+ require 'rgl/graph_iterator'
15
15
 
16
16
  module RGL
17
17
 
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
28
-
29
- # A GraphIterator is the abstract superclass of all Iterators on graphs.
30
- # Each such iterator should implement the protocol defined in module Stream.
31
- module GraphIterator
32
- include Stream
33
- include GraphWrapper
34
- end
35
-
36
- # Module GraphVisitor defines the BGL
37
- # BFS[http://www.boost.org/libs/graph/doc/BFSVisitor.html] Visitor Concept).
38
- #
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.
42
- #
43
- # Graph algorithms typically have multiple event points where one may want to
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.
47
- #
48
- # * examine_vertex
49
- # * finish_vertex
50
- # * examine_edge
51
- # * tree_edge
52
- # * back_edge
53
- # * forward_edge
54
- #
55
- # These methods are all called handle_* and can be set to appropriate blocks,
56
- # using the methods set_*_event_handler, which are defined for each event
57
- # mentioned above.
58
- #
59
- # As an alternative, you can also override the handle_* methods in a
60
- # subclass, to configure the algorithm (as an example, see TarjanSccVisitor).
61
- #
62
- # During a graph traversal, vertices are *colored* using the colors :GRAY
63
- # (when waiting) and :BLACK when finished. All other vertices are :WHITE.
64
- # The color_map is also maintained in the visitor.
65
-
66
- module GraphVisitor
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
90
-
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
146
-
147
18
  # A BFSIterator can be used to traverse a graph from a given start vertex in
148
- # breath first search order. Since the Iterator also mixins the GraphVisitor,
19
+ # breath first search order. Since the Iterator also mixins the GraphVisitor,
149
20
  # it provides all event points defined there.
150
21
  #
151
22
  # The vertices which are not yet visited are held in the queue @waiting.
152
23
  # During the traversal, vertices are *colored* using the colors :GRAY
153
- # (when waiting) and :BLACK when finished. All other vertices are :WHITE.
24
+ # (when waiting) and :BLACK when finished. All other vertices are :WHITE.
154
25
  #
155
26
  # For more doc see the BGL
156
27
  # BFS[http://www.boost.org/libs/graph/doc/BFSVisitor.html] Visitor Concept .
157
28
  #
158
29
  # See the implementation of bfs_search_tree_from for an example usage.
159
-
30
+ #
160
31
  class BFSIterator
161
32
 
162
33
  include GraphIterator
@@ -165,96 +36,99 @@ module RGL
165
36
  attr_accessor :start_vertex
166
37
 
167
38
  # Create a new BFSIterator on _graph_, starting at vertex _start_.
168
-
169
- def initialize (graph, start=graph.detect{ |x| true })
39
+ #
40
+ def initialize(graph, start = graph.detect { |x| true })
170
41
  super(graph)
171
42
  @start_vertex = start
172
43
  set_to_begin
173
44
  end
174
45
 
175
46
  # Returns true if the @color_map has only one entry (for the start vertex).
176
-
177
- def at_beginning? # :nodoc:
47
+ #
48
+ def at_beginning? # :nodoc:
178
49
  @color_map.size == 1
179
50
  end
180
-
181
- # Returns true if @waiting is empty.
182
51
 
52
+ # Returns true if @waiting is empty.
53
+ #
183
54
  def at_end?
184
55
  @waiting.empty?
185
56
  end
186
57
 
187
58
  # Reset the iterator to the initial state (i.e. at_beginning? == true).
188
-
59
+ #
189
60
  def set_to_begin
190
61
  color_map[@start_vertex] = :GRAY
191
- @waiting = [@start_vertex] # a queue
192
- handle_tree_edge(nil, @start_vertex) # discovers start vertex
62
+ @waiting = [@start_vertex] # a queue
63
+ handle_tree_edge(nil, @start_vertex) # discovers start vertex
193
64
  end
194
65
 
195
- def basic_forward # :nodoc:
66
+ def basic_forward # :nodoc:
196
67
  u = next_vertex
197
68
  handle_examine_vertex(u)
198
- graph.each_adjacent(u) { |v|
69
+
70
+ graph.each_adjacent(u) do |v|
199
71
  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
72
+ if follow_edge?(u, v) # (u,v) is a tree edge
73
+ handle_tree_edge(u, v) # also discovers v
74
+ color_map[v] = :GRAY # color of v was :WHITE
203
75
  @waiting.push(v)
204
- else # (u,v) is a non tree edge
76
+ else # (u,v) is a non tree edge
205
77
  if color_map[v] == :GRAY
206
- handle_back_edge(u, v) # (u,v) has gray target
78
+ handle_back_edge(u, v) # (u,v) has gray target
207
79
  else
208
- handle_forward_edge(u, v) # (u,v) has black target
80
+ handle_forward_edge(u, v) # (u,v) has black target
209
81
  end
210
82
  end
211
- }
83
+ end
84
+
212
85
  color_map[u] = :BLACK
213
- handle_finish_vertex(u) # finish vertex
86
+ handle_finish_vertex(u) # finish vertex
214
87
  u
215
88
  end
216
89
 
217
90
  protected
218
91
 
219
- def next_vertex # :nodoc:
92
+ def next_vertex # :nodoc:
220
93
  # waiting is a queue
221
94
  @waiting.shift
222
95
  end
223
- end # class BFSIterator
224
96
 
97
+ end # class BFSIterator
225
98
 
226
99
  module Graph
227
100
 
228
101
  # Returns a BFSIterator, starting at vertex _v_.
229
102
 
230
- def bfs_iterator (v = self.detect { |x| true})
103
+ def bfs_iterator(v = self.detect { |x| true })
231
104
  BFSIterator.new(self, v)
232
105
  end
233
106
 
234
107
  # Returns a DirectedAdjacencyGraph, which represents a BFS search tree
235
- # starting at _v_. This method uses the tree_edge_event of BFSIterator
108
+ # starting at _v_. This method uses the tree_edge_event of BFSIterator
236
109
  # to record all tree edges of the search tree in the result.
237
110
 
238
- def bfs_search_tree_from (v)
111
+ def bfs_search_tree_from(v)
239
112
  require 'rgl/adjacency'
240
113
  bfs = bfs_iterator(v)
241
114
  tree = DirectedAdjacencyGraph.new
242
- bfs.set_tree_edge_event_handler { |from, to|
115
+
116
+ bfs.set_tree_edge_event_handler do |from, to|
243
117
  tree.add_edge(from, to)
244
- }
245
- bfs.set_to_end # does the search
118
+ end
119
+
120
+ bfs.set_to_end # does the search
246
121
  tree
247
122
  end
248
123
 
249
- end # module Graph
124
+ end # module Graph
250
125
 
251
-
252
- # Iterator for a depth first search, starting at a given vertex. The only
126
+ # Iterator for a depth first search, starting at a given vertex. The only
253
127
  # difference from BFSIterator is that @waiting is a stack, instead of a queue.
254
128
  #
255
129
  # Note that this is different from DFSVisitor, which is used in the recursive
256
130
  # version for depth first search (see depth_first_search).
257
-
131
+ #
258
132
  class DFSIterator < BFSIterator
259
133
 
260
134
  def next_vertex
@@ -262,11 +136,10 @@ module RGL
262
136
  @waiting.pop
263
137
  end
264
138
 
265
- end # class DFSIterator
266
-
139
+ end # class DFSIterator
267
140
 
268
141
  # 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
142
+ # methods of a graph. Besides the eventpoint of GraphVisitor, it provides
270
143
  # an additional eventpoint start_vertex, which is called when a
271
144
  # depth_first_search starts a new subtree of the depth first forest that is
272
145
  # defined by the search.
@@ -275,29 +148,28 @@ module RGL
275
148
  # DFSVisitor[http://www.boost.org/libs/graph/doc/DFSVisitor.html] is not
276
149
  # this is also defined in the common mixin GraphVisitor of DFSVisitor,
277
150
  # DFSIterator, and BFSIterator.
278
-
151
+ #
279
152
  class DFSVisitor
280
153
 
281
154
  include GraphVisitor
282
155
 
283
- GraphVisitor.def_event_handler("start_vertex")
284
-
285
- end # class DFSVisitor
156
+ def_event_handler 'start_vertex'
286
157
 
158
+ end # class DFSVisitor
287
159
 
288
160
  module Graph
289
161
 
290
162
  # Returns a DFSIterator staring at vertex _v_.
291
163
 
292
- def dfs_iterator (v = self.detect { |x| true })
164
+ def dfs_iterator(v = self.detect { |x| true })
293
165
  DFSIterator.new(self, v)
294
166
  end
295
167
 
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
168
+ # Do a recursive DFS search on the whole graph. If a block is passed,
169
+ # it is called on each _finish_vertex_ event. See
298
170
  # strongly_connected_components for an example usage.
299
-
300
- def depth_first_search (vis = DFSVisitor.new(self), &b)
171
+ #
172
+ def depth_first_search(vis = DFSVisitor.new(self), &b)
301
173
  each_vertex do |u|
302
174
  unless vis.finished_vertex?(u)
303
175
  vis.handle_start_vertex(u)
@@ -306,44 +178,34 @@ module RGL
306
178
  end
307
179
  end
308
180
 
309
- # Start a depth first search at vertex _u_. The block _b_ is called on
181
+ # Start a depth first search at vertex _u_. The block _b_ is called on
310
182
  # each finish_vertex event.
311
-
312
- def depth_first_visit (u, vis = DFSVisitor.new(self), &b)
183
+ #
184
+ def depth_first_visit(u, vis = DFSVisitor.new(self), &b)
313
185
  vis.color_map[u] = :GRAY
314
186
  vis.handle_examine_vertex(u)
315
- each_adjacent(u) { |v|
187
+
188
+ each_adjacent(u) do |v|
316
189
  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
190
+
191
+ if vis.follow_edge?(u, v) # (u,v) is a tree edge
192
+ vis.handle_tree_edge(u, v) # also discovers v
193
+ vis.color_map[v] = :GRAY # color of v was :WHITE
320
194
  depth_first_visit(v, vis, &b)
321
- else # (u,v) is a non tree edge
195
+ else # (u,v) is a non tree edge
322
196
  if vis.color_map[v] == :GRAY
323
- vis.handle_back_edge(u, v) # (u,v) has gray target
197
+ vis.handle_back_edge(u, v) # (u,v) has gray target
324
198
  else
325
- vis.handle_forward_edge(u, v) # (u,v) is a cross or forward edge
199
+ vis.handle_forward_edge(u, v) # (u,v) is a cross or forward edge
326
200
  end
327
201
  end
328
- }
202
+ end
203
+
329
204
  vis.color_map[u] = :BLACK
330
- vis.handle_finish_vertex(u) # finish vertex
205
+ vis.handle_finish_vertex(u) # finish vertex
331
206
  b.call(u)
332
207
  end
333
208
 
334
- end # module Graph
335
-
336
- =begin
337
- def acyclic?
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
346
- end
347
- =end
209
+ end # module Graph
348
210
 
349
- end # module RGL
211
+ end # module RGL