home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / Traversal.pm < prev    next >
Encoding:
Perl POD Document  |  1999-08-19  |  8.4 KB  |  396 lines

  1. package Graph::Traversal;
  2.  
  3. use strict;
  4. local $^W = 1;
  5.  
  6. use Graph::Base;
  7.  
  8. use vars qw(@ISA);
  9. @ISA = qw(Graph::Base);
  10.  
  11. =head1 NAME
  12.  
  13. Graph::Traversal - graph traversal
  14.  
  15. =head1 SYNOPSIS
  16.  
  17.     use Graph::Traversal;
  18.  
  19. =head1 DESCRIPTION
  20.  
  21. =over 4
  22.  
  23. =cut
  24.  
  25. =pod
  26. =item new
  27.  
  28.     $s = Graph::Traversal->new($G, %param)
  29.  
  30. Returns a new graph search object for the graph $G
  31. and the parameters %param.
  32.  
  33. Usually not used directly but instead via frontends like
  34. Graph::DFS for depth-first searching and Graph::BFS for
  35. breadth-first searching:
  36.  
  37.     $dfs = Graph::DFS->new($G, %param)
  38.     $bfs = Graph::BFS->new($G, %param)
  39.  
  40. I<%param documentation to be written>
  41.  
  42. =cut
  43. sub new {
  44.     my $class  = shift;
  45.     my $G      = shift;
  46.  
  47.     my $S = { G => $G };
  48.  
  49.     bless $S, $class;
  50.  
  51.     $S->reset(@_);
  52.  
  53.     return $S;
  54. }
  55.  
  56. =pod
  57. =item reset
  58.  
  59.     $S->reset
  60.  
  61. Resets a graph search object $S to its initial state.
  62.  
  63. =cut
  64. sub reset {
  65.     my $S = shift;
  66.     my $G = $S->{ G };
  67.  
  68.     @{ $S->{ pool } }{ $G->vertices } = ( );
  69.     $S->{ active_list       }         = [ ];
  70.     $S->{ root_list         }         = [ ];
  71.     $S->{ preorder_list     }         = [ ];
  72.     $S->{ postorder_list    }         = [ ];
  73.     $S->{ active_pool       }         = { };
  74.     $S->{ vertex_found      }         = { };
  75.     $S->{ vertex_root       }         = { };
  76.     $S->{ vertex_successors }         = { };
  77.     $S->{ param             }         = { @_ };
  78.     $S->{ when              }         = 0;
  79. }
  80.  
  81. # _get_next_root_vertex
  82. #
  83. #    $o = $S->_get_next_root_vertex(\%param)
  84. #
  85. #    (INTERNAL USE ONLY)
  86. #    Returns a vertex hopefully suitable as a root vertex of a tree.
  87. #
  88. #    If $param->{ get_next_root } exists, it will be used the determine
  89. #    the root.  If it is a code reference, the result of running it
  90. #    with parameters ($S, %param) will be the next root.  Otherwise
  91. #    it is assumed to be the next root vertex as it is.
  92. #
  93. #    Otherwise an unseen vertex having the maximal out-degree
  94. #    will be selected.
  95. #
  96. sub _get_next_root_vertex {
  97.     my $S      = shift;
  98.     my %param  = ( %{ $S->{ param } }, @_ ? %{ $_[0] } : ( ));
  99.     my $G      = $S->{ G };
  100.  
  101.     if ( exists $param{ get_next_root } ) {
  102.     if ( ref $param{ get_next_root } eq 'CODE' ) {
  103.         return $param{ get_next_root }->( $S, %param ); # Dynamic.
  104.     } else {
  105.         my $get_next_root = $param{ get_next_root };    # Static.
  106.  
  107.         # Use only once.
  108.         delete $S->{ param }->{ get_next_root };
  109.         delete $_[0]->{ get_next_root } if @_;
  110.  
  111.         return $get_next_root;
  112.     }
  113.     } else {
  114.     return $G->largest_out_degree( keys %{ $S->{ pool } } );
  115.     }
  116. }
  117.  
  118. # _mark_vertex_found
  119. #
  120. #    $S->_mark_vertex_found( $u )
  121. #
  122. #    (INTERNAL USE ONLY)
  123. #    Marks the vertex $u as a new vertex in the search object $S.
  124. #
  125. sub _mark_vertex_found {
  126.     my ( $S, $u ) = @_;
  127.  
  128.     $S->{ vertex_found }->{ $u } = $S->{ when }++;
  129.     delete $S->{ pool }->{ $u };
  130. }
  131.  
  132. # _next_state
  133. #
  134. #    $o = $S->_next_state(%param)
  135. #
  136. #    (INTERNAL USE ONLY)
  137. #    Returns a graph search object.
  138. #
  139. sub _next_state {
  140.     my $S = shift;    # The current state.
  141.  
  142.     my $G = $S->{ G };    # The current graph.
  143.     my %param = ( %{ $S->{ param } }, @_);
  144.     my ($u, $v);    # The current vertex and its successor.
  145.     my $return = 0;    # Return when this becomes true.
  146.  
  147.     until ( $return ) {
  148.  
  149.     # Initialize our search when needed.
  150.     # (Start up a new tree.)
  151.     unless ( @{ $S->{ active_list } } ) {
  152.         do {
  153.         $u = $S->_get_next_root_vertex(\%param);
  154.         return wantarray ? ( ) : $u unless defined $u;
  155.         } while exists $S->{ vertex_found }->{ $u };
  156.  
  157.         # A new root vertex found.
  158.         push @{ $S->{ active_list } }, $u;
  159.         $S->{ active_pool }->{ $u } = 1;
  160.         push @{ $S->{ root_list   } }, $u;
  161.         $S->{ vertex_root }->{ $u } = $#{ $S->{ root_list } };
  162.     }
  163.  
  164.     # Get the current vertex.
  165.     $u = $param{ current }->( $S );
  166.     return wantarray ? () : $u unless defined $u;
  167.  
  168.     # Record the vertex if necessary.
  169.     unless ( exists $S->{ vertex_found }->{ $u } ) {
  170.         $S->_mark_vertex_found( $u );
  171.         push @{ $S->{ preorder_list } }, $u;
  172.         # Time to return?
  173.         $return++ if $param{ return_next_preorder };
  174.     }
  175.  
  176.     # Initialized the list successors if necessary.
  177.     $S->{ vertex_successors }->{ $u } = [ $G->successors( $u ) ]
  178.         unless exists $S->{ vertex_successors }->{ $u };
  179.  
  180.     # Get the next successor vertex.
  181.     $v = shift @{ $S->{ vertex_successors }->{ $u } };
  182.  
  183.     if ( defined $v ) {
  184.         # Something to do for each successor?
  185.         $param{ successor }->( $u, $v, $S )
  186.         if exists $param{ successor };
  187.  
  188.         unless ( exists $S->{ vertex_found }->{ $v } ) {
  189.         # An unseen successor.
  190.         $S->_mark_vertex_found( $v );
  191.         push @{ $S->{ preorder_list } }, $v;
  192.         $S->{ vertex_root }->{ $v } = $S->{ vertex_root }->{ $u };
  193.         push @{ $S->{ active_list } }, $v;
  194.         $S->{ active_pool }->{ $v } = 1;
  195.  
  196.         # Something to for each unseen edge?
  197.         # For multiedges, triggered only for the first edge.
  198.         $param{ unseen_successor }->( $u, $v, $S )
  199.             if exists $param{ unseen_successor };
  200.         } else {
  201.         # Something to do for each seen edge?
  202.         # For multiedges, triggered for the 2nd, etc, edges.
  203.         $param{ seen_successor }->( $u, $v, $S )
  204.             if exists $param{ seen_successor };
  205.         }
  206.  
  207.         # Time to return?
  208.         $return++ if $param{ return_next_edge };
  209.  
  210.     } elsif ( not exists $S->{ vertex_finished }->{ $u } ) {
  211.         # Finish off with this vertex (we run out of descendants).
  212.         $param{ finish }->( $S );
  213.  
  214.         $S->{ vertex_finished }->{ $u } = $S->{ when }++;
  215.         push @{ $S->{ postorder_list } }, $u;
  216.         delete $S->{ active_pool }->{ $u };
  217.  
  218.         # Time to return?
  219.         $return++ if $param{ return_next_postorder };
  220.     }
  221.     }
  222.  
  223.     # Return an edge if so asked.
  224.     return ( $u, $v ) if $param{ return_next_edge };
  225.  
  226.     # Return a vertex.
  227.     return $u;
  228. }
  229.  
  230. =pod
  231. =item next_preorder
  232.  
  233.     $v = $s->next_preorder
  234.  
  235. Returns the next vertex in preorder of the graph
  236. encapsulated within the search object $s.
  237.  
  238. =cut
  239. sub next_preorder {
  240.     my $S = shift;
  241.  
  242.     $S->_next_state( return_next_preorder => 1, @_ );
  243. }
  244.  
  245. =cut
  246. =item next_postorder
  247.  
  248.     $v = $S->next_postorder
  249.  
  250. Returns the next vertex in postorder of the graph
  251. encapsulated within the search object $S.
  252.  
  253. =cut
  254. sub next_postorder {
  255.     my $S = shift;
  256.  
  257.     $S->_next_state( return_next_postorder => 1, @_ );
  258. }
  259.  
  260. =pod
  261. =item next_edge
  262.  
  263.     ($u, $v) = $s->next_edge
  264.  
  265. Returns the vertices of the next edge of the graph
  266. encapsulated within the search object $s.
  267.  
  268. =cut
  269. sub next_edge {
  270.     my $S = shift;
  271.  
  272.     $S->_next_state( return_next_edge => 1, @_ );
  273. }
  274.  
  275. =pod
  276. =item preorder
  277.  
  278.     @V = $S->preorder
  279.  
  280. Returns all the vertices in preorder of the graph
  281. encapsulated within the search object $S.
  282.  
  283. =cut
  284. sub preorder {
  285.     my $S = shift;
  286.  
  287.     1 while defined $S->next_preorder;  # Process entire graph.
  288.  
  289.     return @{ $S->{ preorder_list } };
  290. }
  291.  
  292. =pod
  293. =item postorder
  294.  
  295.     @V = $S->postorder
  296.  
  297. Returns all the vertices in postorder of the graph
  298. encapsulated within the search object $S.
  299.  
  300. =cut
  301. sub postorder {
  302.     my $S = shift;
  303.  
  304.     1 while defined $S->next_postorder; # Process entire graph.
  305.  
  306.     return @{ $S->{ postorder_list } };
  307. }
  308.  
  309. =pod
  310. =item edges
  311.  
  312.     @V = $S->edges
  313.  
  314. Returns all the edges of the graph
  315. encapsulated within the search object $S.
  316.  
  317. =cut
  318. sub edges {
  319.     my $S = shift;
  320.     my (@E, $u, $v);
  321.  
  322.     push @E, $u, $v while ($u, $v) = $S->next_edge;
  323.  
  324.     return @E;
  325. }
  326.  
  327. =pod
  328. =item roots
  329.  
  330.     @R = $S->roots
  331.  
  332. Returns all the root vertices of the trees of
  333. the graph encapsulated within the search object $S.
  334. "The root vertices" is ambiguous: what really happens
  335. is that either the roots from the previous search made
  336. on the $s are returned; or a preorder search is done
  337. and the roots of this search are returned.
  338.  
  339. =cut
  340. sub roots {
  341.     my $S = shift;
  342.  
  343.     $S->preorder
  344.     unless exists $S->{ preorder_list } and
  345.            @{ $S->{ preorder_list } } == $S->{ G }->vertices;
  346.  
  347.     return @{ $S->{ root_list } };
  348. }
  349.  
  350. =pod
  351. =item vertex_roots
  352.  
  353.     %R = $S->vertex_roots
  354.  
  355. Returns as a hash of ($vertex, $root) pairs all the vertices
  356. and the root vertices of their search trees of the graph
  357. encapsulated within the search object $S.
  358. "The root vertices" is ambiguous; see the documentation of
  359. the roots() method for more details.
  360.  
  361. =cut
  362. sub vertex_roots {
  363.     my $S = shift;
  364.     my $G = $S->{ G };
  365.  
  366.     $S->preorder
  367.         unless exists $S->{ preorder_list } and
  368.            @{ $S->{ preorder_list } } == $G->vertices;
  369.  
  370.     return 
  371.     map { ( $_, $S->{ vertex_root }->{ $_ } ) } $G->vertices;
  372. }
  373.  
  374. # DELETE
  375. #
  376. #    (INTERNAL USE ONLY)
  377. #    The Destructor.
  378. #
  379. sub DELETE {
  380.     my $S = shift;
  381.  
  382.     delete $S->{ G }; # Release the graph.
  383. }
  384.  
  385. =pod
  386.  
  387. =head1 COPYRIGHT
  388.  
  389. Copyright 1999, O'Reilly & Associates.
  390.  
  391. This code is distributed under the same copyright terms as Perl itself.
  392.  
  393. =cut
  394.  
  395. 1;
  396.