ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/SCRAM/src/Graph/Traversal.pm
Revision: 1.2
Committed: Fri Dec 10 13:41:40 2004 UTC (20 years, 5 months ago) by sashby
Content type: text/plain
Branch: MAIN
CVS Tags: V1_1_7, V1_1_6, V1_1_5, V1_2_0-cand1, V1_1_4, V1_1_3, V1_1_2, V1_1_0_reltag8, V1_1_0_reltag7, V1_1_0_reltag6, V1_1_1, V1_1_0_reltag5, V1_1_0_reltag4, V1_1_0_reltag3, V1_1_0_reltag2, V1_1_0_reltag1, V1_1_0_reltag, V1_0_3-p4, V1_1_0_cand3, V1_1_0_cand2, V1_1_0_cand1, HEAD_SM_071214, forV1_1_0, v103_xml_071106, V1_0_3-p3, V1_0_3-p2, V1_1_0, v110p1, V110p6, V110p5, V110p4, V110p3, before110xmlBRmerge, V110p2, V110p1, V1_0_4p1, V1_0_3-p1, V1_0_3, V1_0_2, V1_0_2_p1, v102p1, V1_0_1, V1_0_0
Branch point for: forBinLess_SCRAM, HEAD_BRANCH_SM_071214, v200branch, v103_with_xml, v103_branch
Changes since 1.1: +240 -0 lines
Log Message:
Merged V1_0 branch to HEAD

File Contents

# User Rev Content
1 sashby 1.2 package Graph::Traversal;
2     use strict;
3     local $^W = 1;
4     use Graph::Base;
5     use vars qw(@ISA);
6     @ISA = qw(Graph::Base);
7    
8     sub new
9     {
10     my $class = shift;
11     my $G = shift;
12     my $S = { G => $G };
13     bless $S, $class;
14     $S->reset(@_);
15     return $S;
16     }
17    
18     sub reset
19     {
20     my $S = shift;
21     my $G = $S->{ G };
22    
23     @{ $S->{ pool } }{ $G->vertices } = ( );
24     $S->{ active_list } = [ ];
25     $S->{ root_list } = [ ];
26     $S->{ preorder_list } = [ ];
27     $S->{ postorder_list } = [ ];
28     $S->{ active_pool } = { };
29     $S->{ vertex_found } = { };
30     $S->{ vertex_root } = { };
31     $S->{ vertex_successors } = { };
32     $S->{ param } = { @_ };
33     $S->{ when } = 0;
34     }
35    
36     sub _get_next_root_vertex
37     {
38     my $S = shift;
39     my %param = ( %{ $S->{ param } }, @_ ? %{ $_[0] } : ( ));
40     my $G = $S->{ G };
41    
42     if ( exists $param{ get_next_root } )
43     {
44     if ( ref $param{ get_next_root } eq 'CODE' )
45     {
46     return $param{ get_next_root }->( $S, %param ); # Dynamic.
47     }
48     else
49     {
50     my $get_next_root = $param{ get_next_root }; # Static.
51    
52     # Use only once.
53     delete $S->{ param }->{ get_next_root };
54     delete $_[0]->{ get_next_root } if @_;
55    
56     return $get_next_root;
57     }
58     }
59     else
60     {
61     return $G->largest_out_degree( keys %{ $S->{ pool } } );
62     }
63     }
64    
65     sub _mark_vertex_found
66     {
67     my ( $S, $u ) = @_;
68    
69     $S->{ vertex_found }->{ $u } = $S->{ when }++;
70     delete $S->{ pool }->{ $u };
71     }
72    
73     sub _next_state
74     {
75     my $S = shift; # The current state.
76     my $G = $S->{ G }; # The current graph.
77     my %param = ( %{ $S->{ param } }, @_);
78     my ($u, $v); # The current vertex and its successor.
79     my $return = 0; # Return when this becomes true.
80    
81     until ( $return )
82     {
83     # Initialize our search when needed.
84     # (Start up a new tree.)
85     unless ( @{ $S->{ active_list } } )
86     {
87     do
88     {
89     $u = $S->_get_next_root_vertex(\%param);
90     return wantarray ? ( ) : $u unless defined $u;
91     } while exists $S->{ vertex_found }->{ $u };
92    
93     # A new root vertex found.
94     push @{ $S->{ active_list } }, $u;
95     $S->{ active_pool }->{ $u } = 1;
96     push @{ $S->{ root_list } }, $u;
97     $S->{ vertex_root }->{ $u } = $#{ $S->{ root_list } };
98     }
99    
100     # Get the current vertex.
101     $u = $param{ current }->( $S );
102     return wantarray ? () : $u unless defined $u;
103    
104     # Record the vertex if necessary.
105     unless ( exists $S->{ vertex_found }->{ $u } )
106     {
107     $S->_mark_vertex_found( $u );
108     push @{ $S->{ preorder_list } }, $u;
109     # Time to return?
110     $return++ if $param{ return_next_preorder };
111     }
112    
113     # Initialized the list successors if necessary.
114     $S->{ vertex_successors }->{ $u } = [ $G->successors( $u ) ]
115     unless exists $S->{ vertex_successors }->{ $u };
116    
117     # Get the next successor vertex.
118     $v = shift @{ $S->{ vertex_successors }->{ $u } };
119    
120     if ( defined $v )
121     {
122     # Something to do for each successor?
123     $param{ successor }->( $u, $v, $S )
124     if exists $param{ successor };
125    
126     unless ( exists $S->{ vertex_found }->{ $v } )
127     {
128     # An unseen successor.
129     $S->_mark_vertex_found( $v );
130     push @{ $S->{ preorder_list } }, $v;
131     $S->{ vertex_root }->{ $v } = $S->{ vertex_root }->{ $u };
132     push @{ $S->{ active_list } }, $v;
133     $S->{ active_pool }->{ $v } = 1;
134    
135     # Something to for each unseen edge?
136     # For multiedges, triggered only for the first edge.
137     $param{ unseen_successor }->( $u, $v, $S )
138     if exists $param{ unseen_successor };
139     }
140     else
141     {
142     # Something to do for each seen edge?
143     # For multiedges, triggered for the 2nd, etc, edges.
144     $param{ seen_successor }->( $u, $v, $S )
145     if exists $param{ seen_successor };
146     }
147    
148     # Time to return?
149     $return++ if $param{ return_next_edge };
150    
151     }
152     elsif ( not exists $S->{ vertex_finished }->{ $u } )
153     {
154     # Finish off with this vertex (we run out of descendants).
155     $param{ finish }->( $S );
156     $S->{ vertex_finished }->{ $u } = $S->{ when }++;
157     push @{ $S->{ postorder_list } }, $u;
158     delete $S->{ active_pool }->{ $u };
159    
160     # Time to return?
161     $return++ if $param{ return_next_postorder };
162     }
163     }
164    
165     # Return an edge if so asked.
166     return ( $u, $v ) if $param{ return_next_edge };
167    
168     # Return a vertex.
169     return $u;
170     }
171    
172     sub next_preorder
173     {
174     my $S = shift;
175     $S->_next_state( return_next_preorder => 1, @_ );
176     }
177    
178     sub next_postorder
179     {
180     my $S = shift;
181     $S->_next_state( return_next_postorder => 1, @_ );
182     }
183    
184     sub next_edge
185     {
186     my $S = shift;
187     $S->_next_state( return_next_edge => 1, @_ );
188     }
189    
190     sub preorder
191     {
192     my $S = shift;
193     1 while defined $S->next_preorder; # Process entire graph.
194     return @{ $S->{ preorder_list } };
195     }
196    
197     sub postorder
198     {
199     my $S = shift;
200     1 while defined $S->next_postorder; # Process entire graph.
201     return @{ $S->{ postorder_list } };
202     }
203    
204     sub edges
205     {
206     my $S = shift;
207     my (@E, $u, $v);
208     push @E, $u, $v while ($u, $v) = $S->next_edge;
209     return @E;
210     }
211    
212     sub roots
213     {
214     my $S = shift;
215    
216     $S->preorder
217     unless exists $S->{ preorder_list } and
218     @{ $S->{ preorder_list } } == $S->{ G }->vertices;
219     return @{ $S->{ root_list } };
220     }
221    
222     sub vertex_roots
223     {
224     my $S = shift;
225     my $G = $S->{ G };
226    
227     $S->preorder
228     unless exists $S->{ preorder_list } and
229     @{ $S->{ preorder_list } } == $G->vertices;
230     return
231     map { ( $_, $S->{ vertex_root }->{ $_ } ) } $G->vertices;
232     }
233    
234     sub DELETE
235     {
236     my $S = shift;
237     delete $S->{ G }; # Release the graph.
238     }
239    
240     1;