lib/rgl/traversal.rb in rgl-0.5.9 vs lib/rgl/traversal.rb in rgl-0.5.10

- old
+ new

@@ -1,53 +1,57 @@ # traversal.rb # -# This file defines the basic graph traversal algorithm for DFS and BFS search. -# They are implemented as an RGL::GraphIterator, which is a Stream of vertices -# of a given graph. The streams are not reversable. -# -# Beside being an iterator in the sense of the Stream mixin, RGL::BFSIterator -# and RGL::DFSIterator follow the BGL -# Visitor[http://www.boost.org/libs/graph/doc/visitor_concepts.html] Concepts -# in a slightly modified fashion (especially for the RGL::DFSIterator). - require 'rgl/base' require 'rgl/graph_visitor' require 'rgl/graph_iterator' module RGL - # A BFSIterator can be used to traverse a graph from a given start vertex in - # breath first search order. Since the Iterator also mixins the GraphVisitor, + # File +traversal.rb+ defines the basic graph traversal algorithm for DFS and + # BFS search. They are implemented as a {GraphIterator}, which is a +Stream+ + # of vertices of a given graph. The streams are not reversable. + # + # Beside being an iterator in the sense of the Stream mixin, {BFSIterator} and + # {DFSIterator} follow the + # {https://www.boost.org/libs/graph/doc/visitor_concepts.html BGL Visitor + # Concepts} in a slightly modified fashion (especially for the + # {DFSIterator}). + # + # A {BFSIterator} can be used to traverse a graph from a given start vertex in + # breath first search order. Since the iterator also mixins the {GraphVisitor}, # it provides all event points defined there. # - # The vertices which are not yet visited are held in the queue @waiting. + # The vertices which are not yet visited are held in the queue +@waiting+. # During the traversal, vertices are *colored* using the colors :GRAY # (when waiting) and :BLACK when finished. All other vertices are :WHITE. # - # For more doc see the BGL - # BFS[http://www.boost.org/libs/graph/doc/BFSVisitor.html] Visitor Concept . + # For more see the BGL {BFS Visitor + # Concept}[https://www.boost.org/libs/graph/doc/BFSVisitor.html]. # - # See the implementation of bfs_search_tree_from for an example usage. + # See the implementation of {Graph#bfs_search_tree_from} for an example usage. # + # @see Graph#bfs_iterator + # @see Graph#bfs_search_tree_from class BFSIterator include GraphIterator include GraphVisitor + # @return the vertex where the search starts attr_accessor :start_vertex - # Create a new BFSIterator on _graph_, starting at vertex _start_. + # Create a new {BFSIterator} on _graph_, starting at vertex _start_. # def initialize(graph, start = graph.detect { |x| true }) super(graph) @start_vertex = start set_to_begin end - # Returns true if the @color_map has only one entry (for the start vertex). + # Returns true if +@color_map+ has only one entry (for the start vertex). # - def at_beginning? # :nodoc: + def at_beginning? @color_map.size == 1 end # Returns true if @waiting is empty. # @@ -64,11 +68,12 @@ @waiting = [@start_vertex] # a queue handle_tree_edge(nil, @start_vertex) # discovers start vertex self end - def basic_forward # :nodoc: + # @private + def basic_forward u = next_vertex handle_examine_vertex(u) graph.each_adjacent(u) do |v| handle_examine_edge(u, v) @@ -90,29 +95,28 @@ u end protected - def next_vertex # :nodoc: + def next_vertex # waiting is a queue @waiting.shift end end # class BFSIterator module Graph - # Returns a BFSIterator, starting at vertex _v_. - + # @return [BFSIterator] starting at vertex _v_. def bfs_iterator(v = self.detect { |x| true }) BFSIterator.new(self, v) end - # Returns a DirectedAdjacencyGraph, which represents a BFS search tree - # starting at _v_. This method uses the tree_edge_event of BFSIterator + # This method uses the +tree_edge_event+ of BFSIterator # to record all tree edges of the search tree in the result. - + # + # @return [DirectedAdjacencyGraph] which represents a BFS search tree starting at _v_. def bfs_search_tree_from(v) require 'rgl/adjacency' bfs = bfs_iterator(v) tree = DirectedAdjacencyGraph.new @@ -125,80 +129,76 @@ end end # module Graph # Iterator for a depth first search, starting at a given vertex. The only - # difference from BFSIterator is that @waiting is a stack, instead of a queue. + # difference from {BFSIterator} is that +@waiting+ is a stack, instead of a queue. # - # Note that this is different from DFSVisitor, which is used in the recursive - # version for depth first search (see depth_first_search). + # Note that this is different from {DFSVisitor}, which is used in the recursive + # version for depth first search (see {Graph#depth_first_search}). # + # @see Graph#dfs_iterator class DFSIterator < BFSIterator def next_vertex # waiting is a stack @waiting.pop end end # class DFSIterator - # A DFSVisitor is needed by the depth_first_search and depth_first_visit - # methods of a graph. Besides the eventpoint of GraphVisitor, it provides - # an additional eventpoint start_vertex, which is called when a - # depth_first_search starts a new subtree of the depth first forest that is - # defined by the search. + # A DFSVisitor is needed by the {Graph#depth_first_search} and + # {Graph#depth_first_visit} methods of a graph. Besides the eventpoints of + # {GraphVisitor}, it provides an additional eventpoint +start_vertex+, which is + # called when a +depth_first_search+ starts a new subtree of the depth first + # forest that is defined by the search. # - # Note that the discover_vertex event defined in the BGL - # DFSVisitor[http://www.boost.org/libs/graph/doc/DFSVisitor.html] is not - # this is also defined in the common mixin GraphVisitor of DFSVisitor, - # DFSIterator, and BFSIterator. - # + # @see DFSIterator class DFSVisitor include GraphVisitor def_event_handler 'start_vertex' end # class DFSVisitor module Graph - # Returns a DFSIterator staring at vertex _v_. - + # @return [DFSIterator] staring at vertex _v_. def dfs_iterator(v = self.detect { |x| true }) DFSIterator.new(self, v) end - # Do a recursive DFS search on the whole graph. If a block is passed, - # it is called on each _finish_vertex_ event. See - # strongly_connected_components for an example usage. + # Do a recursive DFS search on the whole graph. If a block is passed, it is + # called on each +finish_vertex+ event. See {Graph#strongly_connected_components} + # for an example usage. # # Note that this traversal does not garantee, that roots are at the top of # each spanning subtree induced by the DFS search on a directed graph (see # also the discussion in issue #20[https://github.com/monora/rgl/issues/20]). - # + # @see DFSVisitor def depth_first_search(vis = DFSVisitor.new(self), &b) each_vertex do |u| unless vis.finished_vertex?(u) vis.handle_start_vertex(u) depth_first_visit(u, vis, &b) end end end # Start a depth first search at vertex _u_. The block _b_ is called on - # each finish_vertex event. - # + # each +finish_vertex+ event. + # @see DFSVisitor def depth_first_visit(u, vis = DFSVisitor.new(self), &b) vis.color_map[u] = :GRAY vis.handle_examine_vertex(u) each_adjacent(u) do |v| vis.handle_examine_edge(u, v) if vis.follow_edge?(u, v) # (u,v) is a tree edge vis.handle_tree_edge(u, v) # also discovers v - vis.color_map[v] = :GRAY # color of v was :WHITE + # color of v was :WHITE. Will be marked :GRAY in recursion depth_first_visit(v, vis, &b) else # (u,v) is a non tree edge if vis.color_map[v] == :GRAY vis.handle_back_edge(u, v) # (u,v) has gray target else