0
|
1 require 5;
|
|
2 package Tree::DAG_Node;
|
|
3 use Carp ();
|
|
4 use strict;
|
|
5 use vars qw(@ISA $Debug $VERSION);
|
|
6
|
|
7 $Debug = 0;
|
|
8 $VERSION = '1.06';
|
|
9
|
|
10 =head1 NAME
|
|
11
|
|
12 Tree::DAG_Node - (super)class for representing nodes in a tree
|
|
13
|
|
14 =head1 SYNOPSIS
|
|
15
|
|
16 Using as a base class:
|
|
17
|
|
18 package Game::Tree::Node; # or whatever you're doing
|
|
19 use Tree::DAG_Node;
|
|
20 @ISA = qw(Tree::DAG_Node);
|
|
21 ...your own methods overriding/extending
|
|
22 the methods in Tree::DAG_Node...
|
|
23
|
|
24 Using as a class of its own:
|
|
25
|
|
26 use Tree::DAG_Node;
|
|
27 my $root = Tree::DAG_Node->new();
|
|
28 $root->name("I'm the tops");
|
|
29 my $new_daughter = $root->new_daughter;
|
|
30 $new_daughter->name("More");
|
|
31 ...
|
|
32
|
|
33 =head1 DESCRIPTION
|
|
34
|
|
35 This class encapsulates/makes/manipulates objects that represent nodes
|
|
36 in a tree structure. The tree structure is not an object itself, but
|
|
37 is emergent from the linkages you create between nodes. This class
|
|
38 provides the methods for making linkages that can be used to build up
|
|
39 a tree, while preventing you from ever making any kinds of linkages
|
|
40 which are not allowed in a tree (such as having a node be its own
|
|
41 mother or ancestor, or having a node have two mothers).
|
|
42
|
|
43 This is what I mean by a "tree structure", a bit redundantly stated:
|
|
44
|
|
45 * A tree is a special case of an acyclic directed graph.
|
|
46
|
|
47 * A tree is a network of nodes where there's exactly one root
|
|
48 node (i.e., 'the top'), and the only primary relationship between nodes
|
|
49 is the mother-daugher relationship.
|
|
50
|
|
51 * No node can be its own mother, or its mother's mother, etc.
|
|
52
|
|
53 * Each node in the tree has exactly one "parent" (node in the "up"
|
|
54 direction) -- except the root, which is parentless.
|
|
55
|
|
56 * Each node can have any number (0 to any finite number) of daughter
|
|
57 nodes. A given node's daughter nodes constitute an I<ordered> list.
|
|
58 (However, you are free to consider this ordering irrelevant.
|
|
59 Some applications do need daughters to be ordered, so I chose to
|
|
60 consider this the general case.)
|
|
61
|
|
62 * A node can appear in only one tree, and only once in that tree.
|
|
63 Notably (notable because it doesn't follow from the two above points),
|
|
64 a node cannot appear twice in its mother's daughter list.
|
|
65
|
|
66 * In other words, there's an idea of up (toward the root) versus
|
|
67 down (away from the root), and left (i.e., toward the start (index 0)
|
|
68 of a given node's daughter list) versus right (toward the end of a
|
|
69 given node's daughter list).
|
|
70
|
|
71 Trees as described above have various applications, among them:
|
|
72 representing syntactic constituency, in formal linguistics;
|
|
73 representing contingencies in a game tree; representing abstract
|
|
74 syntax in the parsing of any computer language -- whether in
|
|
75 expression trees for programming languages, or constituency in the
|
|
76 parse of a markup language document. (Some of these might not use the
|
|
77 fact that daughters are ordered.)
|
|
78
|
|
79 (Note: B-Trees are a very special case of the above kinds of trees,
|
|
80 and are best treated with their own class. Check CPAN for modules
|
|
81 encapsulating B-Trees; or if you actually want a database, and for
|
|
82 some reason ended up looking here, go look at L<AnyDBM_File>.)
|
|
83
|
|
84 Many base classes are not usable except as such -- but Tree::DAG_Node
|
|
85 can be used as a normal class. You can go ahead and say:
|
|
86
|
|
87 use Tree::DAG_Node;
|
|
88 my $root = Tree::DAG_Node->new();
|
|
89 $root->name("I'm the tops");
|
|
90 $new_daughter = Tree::DAG_Node->new();
|
|
91 $new_daughter->name("More");
|
|
92 $root->add_daughter($new_daughter);
|
|
93
|
|
94 and so on, constructing and linking objects from Tree::DAG_Node and
|
|
95 making useful tree structures out of them.
|
|
96
|
|
97 =head1 A NOTE TO THE READER
|
|
98
|
|
99 This class is big and provides lots of methods. If your problem is
|
|
100 simple (say, just representing a simple parse tree), this class might
|
|
101 seem like using an atomic sledgehammer to swat a fly. But the
|
|
102 complexity of this module's bells and whistles shouldn't detract from
|
|
103 the efficiency of using this class for a simple purpose. In fact, I'd
|
|
104 be very surprised if any one user ever had use for more that even a
|
|
105 third of the methods in this class. And remember: an atomic
|
|
106 sledgehammer B<will> kill that fly.
|
|
107
|
|
108 =head1 OBJECT CONTENTS
|
|
109
|
|
110 Implementationally, each node in a tree is an object, in the sense of
|
|
111 being an arbitrarily complex data structure that belongs to a class
|
|
112 (presumably Tree::DAG_Node, or ones derived from it) that provides
|
|
113 methods.
|
|
114
|
|
115 The attributes of a node-object are:
|
|
116
|
|
117 =over
|
|
118
|
|
119 =item mother -- this node's mother. undef if this is a root.
|
|
120
|
|
121 =item daughters -- the (possibly empty) list of daughters of this node.
|
|
122
|
|
123 =item name -- the name for this node.
|
|
124
|
|
125 Need not be unique, or even printable. This is printed in some of the
|
|
126 various dumper methods, but it's up to you if you don't put anything
|
|
127 meaningful or printable here.
|
|
128
|
|
129 =item attributes -- whatever the user wants to use it for.
|
|
130
|
|
131 Presumably a hashref to whatever other attributes the user wants to
|
|
132 store without risk of colliding with the object's real attributes.
|
|
133 (Example usage: attributes to an SGML tag -- you definitely wouldn't
|
|
134 want the existence of a "mother=foo" pair in such a tag to collide with
|
|
135 a node object's 'mother' attribute.)
|
|
136
|
|
137 Aside from (by default) initializing it to {}, and having the access
|
|
138 method called "attributes" (described a ways below), I don't do
|
|
139 anything with the "attributes" in this module. I basically intended
|
|
140 this so that users who don't want/need to bother deriving a class
|
|
141 from Tree::DAG_Node, could still attach whatever data they wanted in a
|
|
142 node.
|
|
143
|
|
144 =back
|
|
145
|
|
146 "mother" and "daughters" are attributes that relate to linkage -- they
|
|
147 are never written to directly, but are changed as appropriate by the
|
|
148 "linkage methods", discussed below.
|
|
149
|
|
150 The other two (and whatever others you may add in derived classes) are
|
|
151 simply accessed thru the same-named methods, discussed further below.
|
|
152
|
|
153 =head2 ABOUT THE DOCUMENTED INTERFACE
|
|
154
|
|
155 Stick to the documented interface (and comments in the source --
|
|
156 especially ones saying "undocumented!" and/or "disfavored!" -- do not
|
|
157 count as documentation!), and don't rely on any behavior that's not in
|
|
158 the documented interface.
|
|
159
|
|
160 Specifically, unless the documentation for a particular method says
|
|
161 "this method returns thus-and-such a value", then you should not rely on
|
|
162 it returning anything meaningful.
|
|
163
|
|
164 A I<passing> acquintance with at least the broader details of the source
|
|
165 code for this class is assumed for anyone using this class as a base
|
|
166 class -- especially if you're overriding existing methods, and
|
|
167 B<definitely> if you're overriding linkage methods.
|
|
168
|
|
169 =head1 MAIN CONSTRUCTOR, AND INITIALIZER
|
|
170
|
|
171 =over
|
|
172
|
|
173 =item the constructor CLASS->new() or CLASS->new({...options...})
|
|
174
|
|
175 This creates a new node object, calls $object->_init({...options...})
|
|
176 to provide it sane defaults (like: undef name, undef mother, no
|
|
177 daughters, 'attributes' setting of a new empty hashref), and returns
|
|
178 the object created. (If you just said "CLASS->new()" or "CLASS->new",
|
|
179 then it pretends you called "CLASS->new({})".)
|
|
180
|
|
181 Currently no options for putting in {...options...} are part
|
|
182 of the documented interface, but the options is here in case
|
|
183 you want to add such behavior in a derived class.
|
|
184
|
|
185 Read on if you plan on using Tree::DAG_New as a base class.
|
|
186 (Otherwise feel free to skip to the description of _init.)
|
|
187
|
|
188 There are, in my mind, two ways to do object construction:
|
|
189
|
|
190 Way 1: create an object, knowing that it'll have certain uninteresting
|
|
191 sane default values, and then call methods to change those values to
|
|
192 what you want. Example:
|
|
193
|
|
194 $node = Tree::DAG_Node->new;
|
|
195 $node->name('Supahnode!');
|
|
196 $root->add_daughter($node);
|
|
197 $node->add_daughters(@some_others)
|
|
198
|
|
199 Way 2: be able to specify some/most/all the object's attributes in
|
|
200 the call to the constructor. Something like:
|
|
201
|
|
202 $node = Tree::DAG_Node->new({
|
|
203 name => 'Supahnode!',
|
|
204 mother => $root,
|
|
205 daughters => \@some_others
|
|
206 });
|
|
207
|
|
208 After some deliberation, I've decided that the second way is a Bad
|
|
209 Thing. First off, it is B<not> markedly more concise than the first
|
|
210 way. Second off, it often requires subtly different syntax (e.g.,
|
|
211 \@some_others vs @some_others). It just complicates things for the
|
|
212 programmer and the user, without making either appreciably happier.
|
|
213
|
|
214 (This is not to say that options in general for a constructor are bad
|
|
215 -- C<random_network>, discussed far below, necessarily takes options.
|
|
216 But note that those are not options for the default values of
|
|
217 attributes.)
|
|
218
|
|
219 Anyway, if you use Tree::DAG_Node as a superclass, and you add
|
|
220 attributes that need to be initialized, what you need to do is provide
|
|
221 an _init method that calls $this->SUPER::_init($options) to use its
|
|
222 superclass's _init method, and then initializes the new attributes:
|
|
223
|
|
224 sub _init {
|
|
225 my($this, $options) = @_[0,1];
|
|
226 $this->SUPER::_init($options); # call my superclass's _init to
|
|
227 # init all the attributes I'm inheriting
|
|
228
|
|
229 # Now init /my/ new attributes:
|
|
230 $this->{'amigos'} = []; # for example
|
|
231 }
|
|
232
|
|
233 ...or, as I prefer when I'm being a neat freak:
|
|
234
|
|
235 sub _init {
|
|
236 my($this, $options) = @_[0,1];
|
|
237 $this->SUPER::_init($options);
|
|
238
|
|
239 $this->_init_amigos($options);
|
|
240 }
|
|
241
|
|
242 sub _init_amigos {
|
|
243 my $this = $_[0];
|
|
244 # Or my($this,$options) = @_[0,1]; if I'm using $options
|
|
245 $this->{'amigos'} = [];
|
|
246 }
|
|
247
|
|
248
|
|
249 In other words, I like to have each attribute initialized thru a
|
|
250 method named _init_[attribute], which should expect the object as
|
|
251 $_[0] and the the options hashref (or {} if none was given) as $_[1].
|
|
252 If you insist on having your _init recognize options for setting
|
|
253 attributes, you might as well have them dealt with by the appropriate
|
|
254 _init_[attribute] method, like this:
|
|
255
|
|
256 sub _init {
|
|
257 my($this, $options) = @_[0,1];
|
|
258 $this->SUPER::_init($options);
|
|
259
|
|
260 $this->_init_amigos($options);
|
|
261 }
|
|
262
|
|
263 sub _init_amigos {
|
|
264 my($this,$options) = @_[0,1]; # I need options this time
|
|
265 $this->{'amigos'} = [];
|
|
266 $this->amigos(@{$options->{'amigos'}}) if $options->{'amigos'};
|
|
267 }
|
|
268
|
|
269 All this bookkeeping looks silly with just one new attribute in a
|
|
270 class derived straight from Tree::DAG_Node, but if there's lots of new
|
|
271 attributes running around, and if you're deriving from a class derived
|
|
272 from a class derived from Tree::DAG_Node, then tidy
|
|
273 stratification/modularization like this can keep you sane.
|
|
274
|
|
275 =item the constructor $obj->new() or $obj->new({...options...})
|
|
276
|
|
277 Just another way to get at the C<new> method. This B<does not copy>
|
|
278 $obj, but merely constructs a new object of the same class as it.
|
|
279 Saves you the bother of going $class = ref $obj; $obj2 = $class->new;
|
|
280
|
|
281 =cut
|
|
282
|
|
283 sub new { # constructor
|
|
284 # Presumably you won't EVER need to override this -- _init is what
|
|
285 # you'd override in order to set an object's default attribute values.
|
|
286 my $class = shift;
|
|
287 $class = ref($class) if ref($class); # tchristic style. why not?
|
|
288
|
|
289 my $o = ref($_[0]) eq 'HASH' ? $_[0] : {}; # o for options hashref
|
|
290 my $it = bless( {}, $class );
|
|
291 print "Constructing $it in class $class\n" if $Debug;
|
|
292 $it->_init( $o );
|
|
293 return $it;
|
|
294 }
|
|
295
|
|
296 ###########################################################################
|
|
297
|
|
298 =item the method $node->_init({...options...})
|
|
299
|
|
300 Initialize the object's attribute values. See the discussion above.
|
|
301 Presumably this should be called only by the guts of the C<new>
|
|
302 constructor -- never by the end user.
|
|
303
|
|
304 Currently there are no documented options for putting in
|
|
305 {...options...}, but (in case you want to disregard the above rant)
|
|
306 the option exists for you to use {...options...} for something useful
|
|
307 in a derived class.
|
|
308
|
|
309 Please see the source for more information.
|
|
310
|
|
311 =item see also (below) the constructors "new_daughter" and "new_daughter_left"
|
|
312
|
|
313 =back
|
|
314
|
|
315 =cut
|
|
316
|
|
317 sub _init { # method
|
|
318 my $this = shift;
|
|
319 my $o = ref($_[0]) eq 'HASH' ? $_[0] : {};
|
|
320
|
|
321 # Sane initialization.
|
|
322 $this->_init_mother($o);
|
|
323 $this->_init_daughters($o);
|
|
324 $this->_init_name($o);
|
|
325 $this->_init_attributes($o);
|
|
326
|
|
327 return;
|
|
328 }
|
|
329
|
|
330 sub _init_mother { # to be called by an _init
|
|
331 my($this, $o) = @_[0,1];
|
|
332
|
|
333 $this->{'mother'} = undef;
|
|
334
|
|
335 # Undocumented and disfavored. Consider this just an example.
|
|
336 ( $o->{'mother'} )->add_daughter($this)
|
|
337 if defined($o->{'mother'}) && ref($o->{'mother'});
|
|
338 # DO NOT use this option (as implemented) with new_daughter or
|
|
339 # new_daughter_left!!!!!
|
|
340 # BAD THINGS MAY HAPPEN!!!
|
|
341 }
|
|
342
|
|
343 sub _init_daughters { # to be called by an _init
|
|
344 my($this, $o) = @_[0,1];
|
|
345
|
|
346 $this->{'daughters'} = [];
|
|
347
|
|
348 # Undocumented and disfavored. Consider this just an example.
|
|
349 $this->set_daughters( @{$o->{'daughters'}} )
|
|
350 if ref($o->{'daughters'}) && (@{$o->{'daughters'}});
|
|
351 # DO NOT use this option (as implemented) with new_daughter or
|
|
352 # new_daughter_left!!!!!
|
|
353 # BAD THINGS MAY HAPPEN!!!
|
|
354 }
|
|
355
|
|
356 sub _init_name { # to be called by an _init
|
|
357 my($this, $o) = @_[0,1];
|
|
358
|
|
359 $this->{'name'} = undef;
|
|
360
|
|
361 # Undocumented and disfavored. Consider this just an example.
|
|
362 $this->name( $o->{'name'} ) if exists $o->{'name'};
|
|
363 }
|
|
364
|
|
365 sub _init_attributes { # to be called by an _init
|
|
366 my($this, $o) = @_[0,1];
|
|
367
|
|
368 $this->{'attributes'} = {};
|
|
369
|
|
370 # Undocumented and disfavored. Consider this just an example.
|
|
371 $this->attributes( $o->{'attributes'} ) if exists $o->{'attributes'};
|
|
372 }
|
|
373
|
|
374 ###########################################################################
|
|
375 ###########################################################################
|
|
376
|
|
377 =head1 LINKAGE-RELATED METHODS
|
|
378
|
|
379 =over
|
|
380
|
|
381 =item $node->daughters
|
|
382
|
|
383 This returns the (possibly empty) list of daughters for $node.
|
|
384
|
|
385 =cut
|
|
386
|
|
387 sub daughters { # read-only attrib-method: returns a list.
|
|
388 my $this = shift;
|
|
389
|
|
390 if(@_) { # undoc'd and disfavored to use as a write-method
|
|
391 Carp::croak "Don't set daughters with doughters anymore\n";
|
|
392 Carp::carp "my parameter must be a listref" unless ref($_[0]);
|
|
393 $this->{'daughters'} = $_[0];
|
|
394 $this->_update_daughter_links;
|
|
395 }
|
|
396 #return $this->{'daughters'};
|
|
397 return @{$this->{'daughters'} || []};
|
|
398 }
|
|
399
|
|
400 ###########################################################################
|
|
401
|
|
402 =item $node->mother
|
|
403
|
|
404 This returns what node is $node's mother. This is undef if $node has
|
|
405 no mother -- i.e., if it is a root.
|
|
406
|
|
407 =cut
|
|
408
|
|
409 sub mother { # read-only attrib-method: returns an object (the mother node)
|
|
410 my $this = shift;
|
|
411 Carp::croak "I'm a read-only method!" if @_;
|
|
412 return $this->{'mother'};
|
|
413 }
|
|
414
|
|
415 ###########################################################################
|
|
416 ###########################################################################
|
|
417
|
|
418 =item $mother->add_daughters( LIST )
|
|
419
|
|
420 This method adds the node objects in LIST to the (right) end of
|
|
421 $mother's C<daughter> list. Making a node N1 the daughter of another
|
|
422 node N2 also means that N1's C<mother> attribute is "automatically" set
|
|
423 to N2; it also means that N1 stops being anything else's daughter as
|
|
424 it becomes N2's daughter.
|
|
425
|
|
426 If you try to make a node its own mother, a fatal error results. If
|
|
427 you try to take one of a a node N1's ancestors and make it also a
|
|
428 daughter of N1, a fatal error results. A fatal error results if
|
|
429 anything in LIST isn't a node object.
|
|
430
|
|
431 If you try to make N1 a daughter of N2, but it's B<already> a daughter
|
|
432 of N2, then this is a no-operation -- it won't move such nodes to the
|
|
433 end of the list or anything; it just skips doing anything with them.
|
|
434
|
|
435 =item $node->add_daughter( LIST )
|
|
436
|
|
437 An exact synonym for $node->add_daughters(LIST)
|
|
438
|
|
439 =cut
|
|
440
|
|
441 sub add_daughters { # write-only method
|
|
442 my($mother, @daughters) = @_;
|
|
443 return unless @daughters; # no-op
|
|
444 return
|
|
445 $mother->_add_daughters_wrapper(
|
|
446 sub { push @{$_[0]}, $_[1]; },
|
|
447 @daughters
|
|
448 );
|
|
449 }
|
|
450
|
|
451 sub add_daughter { # alias
|
|
452 my($it,@them) = @_; $it->add_daughters(@them);
|
|
453 }
|
|
454
|
|
455 =item $mother->add_daughters_left( LIST )
|
|
456
|
|
457 This method is just like C<add_daughters>, except that it adds the
|
|
458 node objects in LIST to the (left) beginning of $mother's daughter
|
|
459 list, instead of the (right) end of it.
|
|
460
|
|
461 =item $node->add_daughter_left( LIST )
|
|
462
|
|
463 An exact synonym for $node->add_daughters_left( LIST )
|
|
464
|
|
465 =cut
|
|
466
|
|
467 sub add_daughters_left { # write-only method
|
|
468 my($mother, @daughters) = @_;
|
|
469 return unless @daughters;
|
|
470 return
|
|
471 $mother->_add_daughters_wrapper(
|
|
472 sub { unshift @{$_[0]}, $_[1]; },
|
|
473 @daughters
|
|
474 );
|
|
475 }
|
|
476
|
|
477 sub add_daughter_left { # alias
|
|
478 my($it,@them) = @_; $it->add_daughters_left(@them);
|
|
479 }
|
|
480
|
|
481 =item Note:
|
|
482
|
|
483 The above link-making methods perform basically an C<unshift> or
|
|
484 C<push> on the mother node's daughter list. To get the full range of
|
|
485 list-handling functionality, copy the daughter list, and change it,
|
|
486 and then call C<set_daughters> on the result:
|
|
487
|
|
488 @them = $mother->daughters;
|
|
489 @removed = splice(@them, 0,2, @new_nodes);
|
|
490 $mother->set_daughters(@them);
|
|
491
|
|
492 Or consider a structure like:
|
|
493
|
|
494 $mother->set_daughters(
|
|
495 grep($_->name =~ /NP/ ,
|
|
496 $mother->daughters
|
|
497 )
|
|
498 );
|
|
499
|
|
500 =cut
|
|
501
|
|
502
|
|
503 ###
|
|
504 ## Used by the adding methods
|
|
505 # (except maybe new_daughter, and new_daughter_left)
|
|
506
|
|
507 sub _add_daughters_wrapper {
|
|
508 my($mother, $callback, @daughters) = @_;
|
|
509 return unless @daughters;
|
|
510
|
|
511 my %ancestors;
|
|
512 @ancestors{ $mother->ancestors } = undef;
|
|
513 # This could be made more efficient by not bothering to compile
|
|
514 # the ancestor list for $mother if all the nodes to add are
|
|
515 # daughterless.
|
|
516 # But then you have to CHECK if they're daughterless.
|
|
517 # If $mother is [big number] generations down, then it's worth checking.
|
|
518
|
|
519 foreach my $daughter (@daughters) { # which may be ()
|
|
520 Carp::croak "daughter must be a node object!" unless UNIVERSAL::can($daughter, 'is_node');
|
|
521
|
|
522 printf "Mother : %s (%s)\n", $mother, ref $mother if $Debug;
|
|
523 printf "Daughter: %s (%s)\n", $daughter, ref $daughter if $Debug;
|
|
524 printf "Adding %s to %s\n",
|
|
525 ($daughter->name() || $daughter),
|
|
526 ($mother->name() || $mother) if $Debug > 1;
|
|
527
|
|
528 Carp::croak "mother can't be its own daughter!" if $mother eq $daughter;
|
|
529
|
|
530 $daughter->cyclicity_fault(
|
|
531 "$daughter (" . ($daughter->name || 'no_name') .
|
|
532 ") is an ancestor of $mother (" . ($mother->name || 'no_name') .
|
|
533 "), so can't became its daughter."
|
|
534 ) if exists $ancestors{$daughter};
|
|
535
|
|
536 my $old_mother = $daughter->{'mother'};
|
|
537
|
|
538 next if defined($old_mother) && ref($old_mother) && $old_mother eq $mother;
|
|
539 # noop if $daughter is already $mother's daughter
|
|
540
|
|
541 $old_mother->remove_daughters($daughter)
|
|
542 if defined($old_mother) && ref($old_mother);
|
|
543
|
|
544 &{$callback}($mother->{'daughters'}, $daughter);
|
|
545 }
|
|
546 $mother->_update_daughter_links; # need only do this at the end
|
|
547
|
|
548 return;
|
|
549 }
|
|
550
|
|
551 ###########################################################################
|
|
552 ###########################################################################
|
|
553
|
|
554 sub _update_daughter_links {
|
|
555 # Eliminate any duplicates in my daughters list, and update
|
|
556 # all my daughters' links to myself.
|
|
557 my $this = shift;
|
|
558
|
|
559 my $them = $this->{'daughters'};
|
|
560
|
|
561 # Eliminate duplicate daughters.
|
|
562 my %seen = ();
|
|
563 @$them = grep { ref($_) && not($seen{$_}++) } @$them;
|
|
564 # not that there should ever be duplicate daughters anyhoo.
|
|
565
|
|
566 foreach my $one (@$them) { # linkage bookkeeping
|
|
567 Carp::croak "daughter <$one> isn't an object!" unless ref $one;
|
|
568 $one->{'mother'} = $this;
|
|
569 }
|
|
570 return;
|
|
571 }
|
|
572
|
|
573 ###########################################################################
|
|
574
|
|
575 # Currently unused.
|
|
576
|
|
577 sub _update_links { # update all descendant links for ancestorship below
|
|
578 # this point
|
|
579 # note: it's "descendant", not "descendent"
|
|
580 # see <http://www.lenzo.com/~sburke/stuff/english_ant_and_ent.html>
|
|
581 my $this = shift;
|
|
582 # $this->no_cyclicity;
|
|
583 $this->walk_down({
|
|
584 'callback' => sub {
|
|
585 my $this = $_[0];
|
|
586 $this->_update_daughter_links;
|
|
587 return 1;
|
|
588 },
|
|
589 });
|
|
590 }
|
|
591
|
|
592 ###########################################################################
|
|
593 ###########################################################################
|
|
594
|
|
595 =item the constructor $daughter = $mother->new_daughter, or
|
|
596
|
|
597 =item the constructor $daughter = $mother->new_daughter({...options...})
|
|
598
|
|
599 This B<constructs> a B<new> node (of the same class as $mother), and
|
|
600 adds it to the (right) end of the daughter list of $mother. This is
|
|
601 essentially the same as going
|
|
602
|
|
603 $daughter = $mother->new;
|
|
604 $mother->add_daughter($daughter);
|
|
605
|
|
606 but is rather more efficient because (since $daughter is guaranteed new
|
|
607 and isn't linked to/from anything), it doesn't have to check that
|
|
608 $daughter isn't an ancestor of $mother, isn't already daughter to a
|
|
609 mother it needs to be unlinked from, isn't already in $mother's
|
|
610 daughter list, etc.
|
|
611
|
|
612 As you'd expect for a constructor, it returns the node-object created.
|
|
613
|
|
614 =cut
|
|
615
|
|
616 # Note that if you radically change 'mother'/'daughters' bookkeeping,
|
|
617 # you may have to change this routine, since it's one of the places
|
|
618 # that directly writes to 'daughters' and 'mother'.
|
|
619
|
|
620 sub new_daughter {
|
|
621 my($mother, @options) = @_;
|
|
622 my $daughter = $mother->new(@options);
|
|
623
|
|
624 push @{$mother->{'daughters'}}, $daughter;
|
|
625 $daughter->{'mother'} = $mother;
|
|
626
|
|
627 return $daughter;
|
|
628 }
|
|
629
|
|
630 =item the constructor $mother->new_daughter_left, or
|
|
631
|
|
632 =item $mother->new_daughter_left({...options...})
|
|
633
|
|
634 This is just like $mother->new_daughter, but adds the new daughter
|
|
635 to the left (start) of $mother's daughter list.
|
|
636
|
|
637 =cut
|
|
638
|
|
639 # Note that if you radically change 'mother'/'daughters' bookkeeping,
|
|
640 # you may have to change this routine, since it's one of the places
|
|
641 # that directly writes to 'daughters' and 'mother'.
|
|
642
|
|
643 sub new_daughter_left {
|
|
644 my($mother, @options) = @_;
|
|
645 my $daughter = $mother->new(@options);
|
|
646
|
|
647 unshift @{$mother->{'daughters'}}, $daughter;
|
|
648 $daughter->{'mother'} = $mother;
|
|
649
|
|
650 return $daughter;
|
|
651 }
|
|
652
|
|
653 ###########################################################################
|
|
654
|
|
655 =item $mother->remove_daughters( LIST )
|
|
656
|
|
657 This removes the nodes listed in LIST from $mother's daughter list.
|
|
658 This is a no-operation if LIST is empty. If there are things in LIST
|
|
659 that aren't a current daughter of $mother, they are ignored.
|
|
660
|
|
661 Not to be confused with $mother->clear_daughters.
|
|
662
|
|
663 =cut
|
|
664
|
|
665 sub remove_daughters { # write-only method
|
|
666 my($mother, @daughters) = @_;
|
|
667 Carp::croak "mother must be an object!" unless ref $mother;
|
|
668 return unless @daughters;
|
|
669
|
|
670 my %to_delete;
|
|
671 @daughters = grep {ref($_)
|
|
672 and defined($_->{'mother'})
|
|
673 and $mother eq $_->{'mother'}
|
|
674 } @daughters;
|
|
675 return unless @daughters;
|
|
676 @to_delete{ @daughters } = undef;
|
|
677
|
|
678 # This could be done better and more efficiently, I guess.
|
|
679 foreach my $daughter (@daughters) {
|
|
680 $daughter->{'mother'} = undef;
|
|
681 }
|
|
682 my $them = $mother->{'daughters'};
|
|
683 @$them = grep { !exists($to_delete{$_}) } @$them;
|
|
684
|
|
685 # $mother->_update_daughter_links; # unnecessary
|
|
686 return;
|
|
687 }
|
|
688
|
|
689 =item $node->remove_daughter( LIST )
|
|
690
|
|
691 An exact synonym for $node->remove_daughters( LIST )
|
|
692
|
|
693 =cut
|
|
694
|
|
695 sub remove_daughter { # alias
|
|
696 my($it,@them) = @_; $it->remove_daughters(@them);
|
|
697 }
|
|
698
|
|
699 =item $node->unlink_from_mother
|
|
700
|
|
701 This removes node from the daughter list of its mother. If it has no
|
|
702 mother, this is a no-operation.
|
|
703
|
|
704 Returns the mother unlinked from (if any).
|
|
705
|
|
706 =cut
|
|
707
|
|
708 sub unlink_from_mother {
|
|
709 my $node = $_[0];
|
|
710 my $mother = $node->{'mother'};
|
|
711 $mother->remove_daughters($node) if defined($mother) && ref($mother);
|
|
712 return $mother;
|
|
713 }
|
|
714
|
|
715 ###########################################################################
|
|
716
|
|
717 =item $mother->clear_daughters
|
|
718
|
|
719 This unlinks all $mother's daughters.
|
|
720 Returns the the list of what used to be $mother's daughters.
|
|
721
|
|
722 Not to be confused with $mother->remove_daughters( LIST ).
|
|
723
|
|
724 =cut
|
|
725
|
|
726 sub clear_daughters { # write-only method
|
|
727 my($mother) = $_[0];
|
|
728 my @daughters = @{$mother->{'daughters'}};
|
|
729
|
|
730 @{$mother->{'daughters'}} = ();
|
|
731 foreach my $one (@daughters) {
|
|
732 next unless UNIVERSAL::can($one, 'is_node'); # sanity check
|
|
733 $one->{'mother'} = undef;
|
|
734 }
|
|
735 # Another, simpler, way to do it:
|
|
736 # $mother->remove_daughters($mother->daughters);
|
|
737
|
|
738 return @daughters; # NEW
|
|
739 }
|
|
740 #--------------------------------------------------------------------------
|
|
741
|
|
742 =item $mother->set_daughters( LIST )
|
|
743
|
|
744 This unlinks all $mother's daughters, and replaces them with the
|
|
745 daughters in LIST.
|
|
746
|
|
747 Currently implemented as just $mother->clear_daughters followed by
|
|
748 $mother->add_daughters( LIST ).
|
|
749
|
|
750 =cut
|
|
751
|
|
752 sub set_daughters { # write-only method
|
|
753 my($mother, @them) = @_;
|
|
754 $mother->clear_daughters;
|
|
755 $mother->add_daughters(@them) if @them;
|
|
756 # yup, it's that simple
|
|
757 }
|
|
758
|
|
759 #--------------------------------------------------------------------------
|
|
760
|
|
761 =item $node->replace_with( LIST )
|
|
762
|
|
763 This replaces $node in its mother's daughter list, by unlinking $node
|
|
764 and replacing it with the items in LIST. This returns a list consisting
|
|
765 of $node followed by LIST, i.e., the nodes that replaced it.
|
|
766
|
|
767 LIST can include $node itself (presumably at most once). LIST can
|
|
768 also be empty-list. However, if any items in LIST are sisters to
|
|
769 $node, they are ignored, and are not in the copy of LIST passed as the
|
|
770 return value.
|
|
771
|
|
772 As you might expect for any linking operation, the items in LIST
|
|
773 cannot be $node's mother, or any ancestor to it; and items in LIST are,
|
|
774 of course, unlinked from their mothers (if they have any) as they're
|
|
775 linked to $node's mother.
|
|
776
|
|
777 (In the special (and bizarre) case where $node is root, this simply calls
|
|
778 $this->unlink_from_mother on all the items in LIST, making them roots of
|
|
779 their own trees.)
|
|
780
|
|
781 Note that the daughter-list of $node is not necessarily affected; nor
|
|
782 are the daughter-lists of the items in LIST. I mention this in case you
|
|
783 think replace_with switches one node for another, with respect to its
|
|
784 mother list B<and> its daughter list, leaving the rest of the tree
|
|
785 unchanged. If that's what you want, replacing $Old with $New, then you
|
|
786 want:
|
|
787
|
|
788 $New->set_daughters($Old->clear_daughters);
|
|
789 $Old->replace_with($New);
|
|
790
|
|
791 (I can't say $node's and LIST-items' daughter lists are B<never>
|
|
792 affected my replace_with -- they can be affected in this case:
|
|
793
|
|
794 $N1 = ($node->daughters)[0]; # first daughter of $node
|
|
795 $N2 = ($N1->daughters)[0]; # first daughter of $N1;
|
|
796 $N3 = Tree::DAG_Node->random_network; # or whatever
|
|
797 $node->replace_with($N1, $N2, $N3);
|
|
798
|
|
799 As a side affect of attaching $N1 and $N2 to $node's mother, they're
|
|
800 unlinked from their parents ($node, and $N1, replectively).
|
|
801 But N3's daughter list is unaffected.
|
|
802
|
|
803 In other words, this method does what it has to, as you'd expect it
|
|
804 to.
|
|
805
|
|
806 =cut
|
|
807
|
|
808 sub replace_with { # write-only method
|
|
809 my($this, @replacements) = @_;
|
|
810
|
|
811 if(not( defined($this->{'mother'}) && ref($this->{'mother'}) )) { # if root
|
|
812 foreach my $replacement (@replacements) {
|
|
813 $replacement->{'mother'}->remove_daughters($replacement)
|
|
814 if $replacement->{'mother'};
|
|
815 }
|
|
816 # make 'em roots
|
|
817 } else { # I have a mother
|
|
818 my $mother = $this->{'mother'};
|
|
819
|
|
820 #@replacements = grep(($_ eq $this || $_->{'mother'} ne $mother),
|
|
821 # @replacements);
|
|
822 @replacements = grep { $_ eq $this
|
|
823 || not(defined($_->{'mother'}) &&
|
|
824 ref($_->{'mother'}) &&
|
|
825 $_->{'mother'} eq $mother
|
|
826 )
|
|
827 }
|
|
828 @replacements;
|
|
829 # Eliminate sisters (but not self)
|
|
830 # i.e., I want myself or things NOT with the same mother as myself.
|
|
831
|
|
832 $mother->set_daughters( # old switcheroo
|
|
833 map($_ eq $this ? (@replacements) : $_ ,
|
|
834 @{$mother->{'daughters'}}
|
|
835 )
|
|
836 );
|
|
837 # and set_daughters does all the checking and possible
|
|
838 # unlinking
|
|
839 }
|
|
840 return($this, @replacements);
|
|
841 }
|
|
842
|
|
843 =item $node->replace_with_daughters
|
|
844
|
|
845 This replaces $node in its mother's daughter list, by unlinking $node
|
|
846 and replacing it with its daughters. In other words, $node becomes
|
|
847 motherless and daughterless as its daughters move up and take its place.
|
|
848 This returns a list consisting of $node followed by the nodes that were
|
|
849 its daughters.
|
|
850
|
|
851 In the special (and bizarre) case where $node is root, this simply
|
|
852 unlinks its daughters from it, making them roots of their own trees.
|
|
853
|
|
854 Effectively the same as $node->replace_with($node->daughters), but more
|
|
855 efficient, since less checking has to be done. (And I also think
|
|
856 $node->replace_with_daughters is a more common operation in
|
|
857 tree-wrangling than $node->replace_with(LIST), so deserves a named
|
|
858 method of its own, but that's just me.)
|
|
859
|
|
860 =cut
|
|
861
|
|
862 # Note that if you radically change 'mother'/'daughters' bookkeeping,
|
|
863 # you may have to change this routine, since it's one of the places
|
|
864 # that directly writes to 'daughters' and 'mother'.
|
|
865
|
|
866 sub replace_with_daughters { # write-only method
|
|
867 my($this) = $_[0]; # takes no params other than the self
|
|
868 my $mother = $this->{'mother'};
|
|
869 return($this, $this->clear_daughters)
|
|
870 unless defined($mother) && ref($mother);
|
|
871
|
|
872 my @daughters = $this->clear_daughters;
|
|
873 my $sib_r = $mother->{'daughters'};
|
|
874 @$sib_r = map($_ eq $this ? (@daughters) : $_,
|
|
875 @$sib_r # old switcheroo
|
|
876 );
|
|
877 foreach my $daughter (@daughters) {
|
|
878 $daughter->{'mother'} = $mother;
|
|
879 }
|
|
880 return($this, @daughters);
|
|
881 }
|
|
882
|
|
883 #--------------------------------------------------------------------------
|
|
884
|
|
885 =item $node->add_left_sisters( LIST )
|
|
886
|
|
887 This adds the elements in LIST (in that order) as immediate left sisters of
|
|
888 $node. In other words, given that B's mother's daughter-list is (A,B,C,D),
|
|
889 calling B->add_left_sisters(X,Y) makes B's mother's daughter-list
|
|
890 (A,X,Y,B,C,D).
|
|
891
|
|
892 If LIST is empty, this is a no-op, and returns empty-list.
|
|
893
|
|
894 This is basically implemented as a call to $node->replace_with(LIST,
|
|
895 $node), and so all replace_with's limitations and caveats apply.
|
|
896
|
|
897 The return value of $node->add_left_sisters( LIST ) is the elements of
|
|
898 LIST that got added, as returned by replace_with -- minus the copies
|
|
899 of $node you'd get from a straight call to $node->replace_with(LIST,
|
|
900 $node).
|
|
901
|
|
902 =cut
|
|
903
|
|
904 sub add_left_sisters { # write-only method
|
|
905 my($this, @new) = @_;
|
|
906 return() unless @new;
|
|
907
|
|
908 @new = $this->replace_with(@new, $this);
|
|
909 shift @new; pop @new; # kill the copies of $this
|
|
910 return @new;
|
|
911 }
|
|
912
|
|
913 =item $node->add_left_sister( LIST )
|
|
914
|
|
915 An exact synonym for $node->add_left_sisters(LIST)
|
|
916
|
|
917 =cut
|
|
918
|
|
919 sub add_left_sister { # alias
|
|
920 my($it,@them) = @_; $it->add_left_sisters(@them);
|
|
921 }
|
|
922
|
|
923 =item $node->add_right_sisters( LIST )
|
|
924
|
|
925 Just like add_left_sisters (which see), except that the the elements
|
|
926 in LIST (in that order) as immediate B<right> sisters of $node;
|
|
927
|
|
928 In other words, given that B's mother's daughter-list is (A,B,C,D),
|
|
929 calling B->add_right_sisters(X,Y) makes B's mother's daughter-list
|
|
930 (A,B,X,Y,C,D).
|
|
931
|
|
932 =cut
|
|
933
|
|
934 sub add_right_sisters { # write-only method
|
|
935 my($this, @new) = @_;
|
|
936 return() unless @new;
|
|
937 @new = $this->replace_with($this, @new);
|
|
938 shift @new; shift @new; # kill the copies of $this
|
|
939 return @new;
|
|
940 }
|
|
941
|
|
942 =item $node->add_right_sister( LIST )
|
|
943
|
|
944 An exact synonym for $node->add_right_sisters(LIST)
|
|
945
|
|
946 =cut
|
|
947
|
|
948 sub add_right_sister { # alias
|
|
949 my($it,@them) = @_; $it->add_right_sisters(@them);
|
|
950 }
|
|
951
|
|
952 ###########################################################################
|
|
953
|
|
954 =back
|
|
955
|
|
956 =cut
|
|
957
|
|
958 ###########################################################################
|
|
959 ###########################################################################
|
|
960
|
|
961 =head1 OTHER ATTRIBUTE METHODS
|
|
962
|
|
963 =over
|
|
964
|
|
965 =item $node->name or $node->name(SCALAR)
|
|
966
|
|
967 In the first form, returns the value of the node object's "name"
|
|
968 attribute. In the second form, sets it to the value of SCALAR.
|
|
969
|
|
970 =cut
|
|
971
|
|
972 sub name { # read/write attribute-method. returns/expects a scalar
|
|
973 my $this = shift;
|
|
974 $this->{'name'} = $_[0] if @_;
|
|
975 return $this->{'name'};
|
|
976 }
|
|
977
|
|
978
|
|
979 ###########################################################################
|
|
980
|
|
981 =item $node->attributes or $node->attributes(SCALAR)
|
|
982
|
|
983 In the first form, returns the value of the node object's "attributes"
|
|
984 attribute. In the second form, sets it to the value of SCALAR. I
|
|
985 intend this to be used to store a reference to a (presumably
|
|
986 anonymous) hash the user can use to store whatever attributes he
|
|
987 doesn't want to have to store as object attributes. In this case, you
|
|
988 needn't ever set the value of this. (_init has already initialized it
|
|
989 to {}.) Instead you can just do...
|
|
990
|
|
991 $node->attributes->{'foo'} = 'bar';
|
|
992
|
|
993 ...to write foo => bar.
|
|
994
|
|
995 =cut
|
|
996
|
|
997 sub attributes { # read/write attribute-method
|
|
998 # expects a ref, presumably a hashref
|
|
999 my $this = shift;
|
|
1000 if(@_) {
|
|
1001 Carp::carp "my parameter must be a reference" unless ref($_[0]);
|
|
1002 $this->{'attributes'} = $_[0];
|
|
1003 }
|
|
1004 return $this->{'attributes'};
|
|
1005 }
|
|
1006
|
|
1007 =item $node->attribute or $node->attribute(SCALAR)
|
|
1008
|
|
1009 An exact synonym for $node->attributes or $node->attributes(SCALAR)
|
|
1010
|
|
1011 =cut
|
|
1012
|
|
1013 sub attribute { # alias
|
|
1014 my($it,@them) = @_; $it->attributes(@them);
|
|
1015 }
|
|
1016
|
|
1017 ###########################################################################
|
|
1018 # Secret Stuff.
|
|
1019
|
|
1020 sub no_cyclicity { # croak iff I'm in a CYCLIC class.
|
|
1021 my($it) = $_[0];
|
|
1022 # If, God forbid, I use this to make a cyclic class, then I'd
|
|
1023 # expand the functionality of this routine to actually look for
|
|
1024 # cyclicity. Or something like that. Maybe.
|
|
1025
|
|
1026 $it->cyclicity_fault("You can't do that in a cyclic class!")
|
|
1027 if $it->cyclicity_allowed;
|
|
1028 return;
|
|
1029 }
|
|
1030
|
|
1031 sub cyclicity_fault {
|
|
1032 my($it, $bitch) = @_[0,1];
|
|
1033 Carp::croak "Cyclicity fault: $bitch"; # never return
|
|
1034 }
|
|
1035
|
|
1036 sub cyclicity_allowed {
|
|
1037 return 0;
|
|
1038 }
|
|
1039
|
|
1040 ###########################################################################
|
|
1041 # More secret stuff. Currently unused.
|
|
1042
|
|
1043 sub inaugurate_root { # no-op
|
|
1044 my($it, $tree) = @_[0,1];
|
|
1045 # flag this node as being the root of the tree $tree.
|
|
1046 return;
|
|
1047 }
|
|
1048
|
|
1049 sub decommission_root { # no-op
|
|
1050 # flag this node as no longer being the root of the tree $tree.
|
|
1051 return;
|
|
1052 }
|
|
1053
|
|
1054 ###########################################################################
|
|
1055 ###########################################################################
|
|
1056
|
|
1057 =back
|
|
1058
|
|
1059 =head1 OTHER METHODS TO DO WITH RELATIONSHIPS
|
|
1060
|
|
1061 =over
|
|
1062
|
|
1063 =item $node->is_node
|
|
1064
|
|
1065 This always returns true. More pertinently, $object->can('is_node')
|
|
1066 is true (regardless of what C<is_node> would do if called) for objects
|
|
1067 belonging to this class or for any class derived from it.
|
|
1068
|
|
1069 =cut
|
|
1070
|
|
1071 sub is_node { return 1; } # always true.
|
|
1072 # NEVER override this with anything that returns false in the belief
|
|
1073 # that this'd signal "not a node class". The existence of this method
|
|
1074 # is what I test for, with the various "can()" uses in this class.
|
|
1075
|
|
1076 ###########################################################################
|
|
1077
|
|
1078 =item $node->ancestors
|
|
1079
|
|
1080 Returns the list of this node's ancestors, starting with its mother,
|
|
1081 then grandmother, and ending at the root. It does this by simply
|
|
1082 following the 'mother' attributes up as far as it can. So if $item IS
|
|
1083 the root, this returns an empty list.
|
|
1084
|
|
1085 Consider that scalar($node->ancestors) returns the ply of this node
|
|
1086 within the tree -- 2 for a granddaughter of the root, etc., and 0 for
|
|
1087 root itself.
|
|
1088
|
|
1089 =cut
|
|
1090
|
|
1091 sub ancestors {
|
|
1092 my $this = shift;
|
|
1093 my $mama = $this->{'mother'}; # initial condition
|
|
1094 return () unless ref($mama); # I must be root!
|
|
1095
|
|
1096 # $this->no_cyclicity; # avoid infinite loops
|
|
1097
|
|
1098 # Could be defined recursively, as:
|
|
1099 # if(ref($mama = $this->{'mother'})){
|
|
1100 # return($mama, $mama->ancestors);
|
|
1101 # } else {
|
|
1102 # return ();
|
|
1103 # }
|
|
1104 # But I didn't think of that until I coded the stuff below, which is
|
|
1105 # faster.
|
|
1106
|
|
1107 my @ancestors = ( $mama ); # start off with my mama
|
|
1108 while(defined( $mama = $mama->{'mother'} ) && ref($mama)) {
|
|
1109 # Walk up the tree
|
|
1110 push(@ancestors, $mama);
|
|
1111 # This turns into an infinite loop if someone gets stupid
|
|
1112 # and makes this tree cyclic! Don't do it!
|
|
1113 }
|
|
1114 return @ancestors;
|
|
1115 }
|
|
1116
|
|
1117 ###########################################################################
|
|
1118
|
|
1119 =item $node->root
|
|
1120
|
|
1121 Returns the root of whatever tree $node is a member of. If $node is
|
|
1122 the root, then the result is $node itself.
|
|
1123
|
|
1124 =cut
|
|
1125
|
|
1126 sub root {
|
|
1127 my $it = $_[0];
|
|
1128 my @ancestors = ($it, $it->ancestors);
|
|
1129 return $ancestors[-1];
|
|
1130 }
|
|
1131
|
|
1132 ###########################################################################
|
|
1133
|
|
1134 =item $node->is_daughter_of($node2)
|
|
1135
|
|
1136 Returns true iff $node is a daughter of $node2.
|
|
1137 Currently implemented as just a test of ($it->mother eq $node2).
|
|
1138
|
|
1139 =cut
|
|
1140
|
|
1141 sub is_daughter_of {
|
|
1142 my($it,$mama) = @_[0,1];
|
|
1143 return $it->{'mother'} eq $mama;
|
|
1144 }
|
|
1145
|
|
1146 ###########################################################################
|
|
1147
|
|
1148 =item $node->self_and_descendants
|
|
1149
|
|
1150 Returns a list consisting of itself (as element 0) and all the
|
|
1151 descendants of $node. Returns just itself if $node is a
|
|
1152 terminal_node.
|
|
1153
|
|
1154 (Note that it's spelled "descendants", not "descendents".)
|
|
1155
|
|
1156 =cut
|
|
1157
|
|
1158 sub self_and_descendants {
|
|
1159 # read-only method: return a list of myself and any/all descendants
|
|
1160 my $node = shift;
|
|
1161 my @List = ();
|
|
1162 # $node->no_cyclicity;
|
|
1163 $node->walk_down({ 'callback' => sub { push @List, $_[0]; return 1;}});
|
|
1164 Carp::croak "Spork Error 919: \@List has no contents!?!?" unless @List;
|
|
1165 # impossible
|
|
1166 return @List;
|
|
1167 }
|
|
1168
|
|
1169 ###########################################################################
|
|
1170
|
|
1171 =item $node->descendants
|
|
1172
|
|
1173 Returns a list consisting of all the descendants of $node. Returns
|
|
1174 empty-list if $node is a terminal_node.
|
|
1175
|
|
1176 (Note that it's spelled "descendants", not "descendents".)
|
|
1177
|
|
1178 =cut
|
|
1179
|
|
1180 sub descendants {
|
|
1181 # read-only method: return a list of my descendants
|
|
1182 my $node = shift;
|
|
1183 my @list = $node->self_and_descendants;
|
|
1184 shift @list; # lose myself.
|
|
1185 return @list;
|
|
1186 }
|
|
1187
|
|
1188 ###########################################################################
|
|
1189
|
|
1190 =item $node->leaves_under
|
|
1191
|
|
1192 Returns a list (going left-to-right) of all the leaf nodes under
|
|
1193 $node. ("Leaf nodes" are also called "terminal nodes" -- i.e., nodes
|
|
1194 that have no daughters.) Returns $node in the degenerate case of
|
|
1195 $node being a leaf itself.
|
|
1196
|
|
1197 =cut
|
|
1198
|
|
1199 sub leaves_under {
|
|
1200 # read-only method: return a list of all leaves under myself.
|
|
1201 # Returns myself in the degenerate case of being a leaf myself.
|
|
1202 my $node = shift;
|
|
1203 my @List = ();
|
|
1204 # $node->no_cyclicity;
|
|
1205 $node->walk_down({ 'callback' =>
|
|
1206 sub {
|
|
1207 my $node = $_[0];
|
|
1208 my @daughters = @{$node->{'daughters'}};
|
|
1209 push(@List, $node) unless @daughters;
|
|
1210 return 1;
|
|
1211 }
|
|
1212 });
|
|
1213 Carp::croak "Spork Error 861: \@List has no contents!?!?" unless @List;
|
|
1214 # impossible
|
|
1215 return @List;
|
|
1216 }
|
|
1217
|
|
1218 ###########################################################################
|
|
1219
|
|
1220 =item $node->depth_under
|
|
1221
|
|
1222 Returns an integer representing the number of branches between this
|
|
1223 $node and the most distant leaf under it. (In other words, this
|
|
1224 returns the ply of subtree starting of $node. Consider
|
|
1225 scalar($it->ancestors) if you want the ply of a node within the whole
|
|
1226 tree.)
|
|
1227
|
|
1228 =cut
|
|
1229
|
|
1230 sub depth_under {
|
|
1231 my $node = shift;
|
|
1232 my $max_depth = 0;
|
|
1233 $node->walk_down({
|
|
1234 '_depth' => 0,
|
|
1235 'callback' => sub {
|
|
1236 my $depth = $_[1]->{'_depth'};
|
|
1237 $max_depth = $depth if $depth > $max_depth;
|
|
1238 return 1;
|
|
1239 },
|
|
1240 });
|
|
1241 return $max_depth;
|
|
1242 }
|
|
1243
|
|
1244 ###########################################################################
|
|
1245
|
|
1246 =item $node->generation
|
|
1247
|
|
1248 Returns a list of all nodes (going left-to-right) that are in $node's
|
|
1249 generation -- i.e., that are the some number of nodes down from
|
|
1250 the root. $root->generation is just $root.
|
|
1251
|
|
1252 Of course, $node is always in its own generation.
|
|
1253
|
|
1254 =item $node->generation_under(NODE2)
|
|
1255
|
|
1256 Like $node->generation, but returns only the nodes in $node's generation
|
|
1257 that are also descendants of NODE2 -- in other words,
|
|
1258
|
|
1259 @us = $node->generation_under( $node->mother->mother );
|
|
1260
|
|
1261 is all $node's first cousins (to borrow yet more kinship terminology) --
|
|
1262 assuming $node does indeed have a grandmother. Actually "cousins" isn't
|
|
1263 quite an apt word, because C<@us> ends up including $node's siblings and
|
|
1264 $node.
|
|
1265
|
|
1266 Actually, C<generation_under> is just an alias to C<generation>, but I
|
|
1267 figure that this:
|
|
1268
|
|
1269 @us = $node->generation_under($way_upline);
|
|
1270
|
|
1271 is a bit more readable than this:
|
|
1272
|
|
1273 @us = $node->generation($way_upline);
|
|
1274
|
|
1275 But it's up to you.
|
|
1276
|
|
1277 $node->generation_under($node) returns just $node.
|
|
1278
|
|
1279 If you call $node->generation_under($node) but NODE2 is not $node or an
|
|
1280 ancestor of $node, it behaves as if you called just $node->generation().
|
|
1281
|
|
1282 =cut
|
|
1283
|
|
1284 sub generation {
|
|
1285 my($node, $limit) = @_[0,1];
|
|
1286 # $node->no_cyclicity;
|
|
1287 return $node
|
|
1288 if $node eq $limit || not(
|
|
1289 defined($node->{'mother'}) &&
|
|
1290 ref($node->{'mother'})
|
|
1291 ); # bailout
|
|
1292
|
|
1293 return map(@{$_->{'daughters'}}, $node->{'mother'}->generation($limit));
|
|
1294 # recurse!
|
|
1295 # Yup, my generation is just all the daughters of my mom's generation.
|
|
1296 }
|
|
1297
|
|
1298 sub generation_under {
|
|
1299 my($node, @rest) = @_;
|
|
1300 return $node->generation(@rest);
|
|
1301 }
|
|
1302
|
|
1303 ###########################################################################
|
|
1304
|
|
1305 =item $node->self_and_sisters
|
|
1306
|
|
1307 Returns a list of all nodes (going left-to-right) that have the same
|
|
1308 mother as $node -- including $node itself. This is just like
|
|
1309 $node->mother->daughters, except that that fails where $node is root,
|
|
1310 whereas $root->self_and_siblings, as a special case, returns $root.
|
|
1311
|
|
1312 (Contrary to how you may interpret how this method is named, "self" is
|
|
1313 not (necessarily) the first element of what's returned.)
|
|
1314
|
|
1315 =cut
|
|
1316
|
|
1317 sub self_and_sisters {
|
|
1318 my $node = $_[0];
|
|
1319 my $mother = $node->{'mother'};
|
|
1320 return $node unless defined($mother) && ref($mother); # special case
|
|
1321 return @{$node->{'mother'}->{'daughters'}};
|
|
1322 }
|
|
1323
|
|
1324 ###########################################################################
|
|
1325
|
|
1326 =item $node->sisters
|
|
1327
|
|
1328 Returns a list of all nodes (going left-to-right) that have the same
|
|
1329 mother as $node -- B<not including> $node itself. If $node is root,
|
|
1330 this returns empty-list.
|
|
1331
|
|
1332 =cut
|
|
1333
|
|
1334 sub sisters {
|
|
1335 my $node = $_[0];
|
|
1336 my $mother = $node->{'mother'};
|
|
1337 return() unless $mother; # special case
|
|
1338 return grep($_ ne $node,
|
|
1339 @{$node->{'mother'}->{'daughters'}}
|
|
1340 );
|
|
1341 }
|
|
1342
|
|
1343 ###########################################################################
|
|
1344
|
|
1345 =item $node->left_sister
|
|
1346
|
|
1347 Returns the node that's the immediate left sister of $node. If $node
|
|
1348 is the leftmost (or only) daughter of its mother (or has no mother),
|
|
1349 then this returns undef.
|
|
1350
|
|
1351 (See also $node->add_left_sisters(LIST).)
|
|
1352
|
|
1353 =cut
|
|
1354
|
|
1355 sub left_sister {
|
|
1356 my $it = $_[0];
|
|
1357 my $mother = $it->{'mother'};
|
|
1358 return undef unless $mother;
|
|
1359 my @sisters = @{$mother->{'daughters'}};
|
|
1360
|
|
1361 return undef if @sisters == 1; # I'm an only daughter
|
|
1362
|
|
1363 my $left = undef;
|
|
1364 foreach my $one (@sisters) {
|
|
1365 return $left if $one eq $it;
|
|
1366 $left = $one;
|
|
1367 }
|
|
1368 die "SPORK ERROR 9757: I'm not in my mother's daughter list!?!?";
|
|
1369 }
|
|
1370
|
|
1371
|
|
1372 =item $node->left_sisters
|
|
1373
|
|
1374 Returns a list of nodes that're sisters to the left of $node. If
|
|
1375 $node is the leftmost (or only) daughter of its mother (or has no
|
|
1376 mother), then this returns an empty list.
|
|
1377
|
|
1378 (See also $node->add_left_sisters(LIST).)
|
|
1379
|
|
1380 =cut
|
|
1381
|
|
1382 sub left_sisters {
|
|
1383 my $it = $_[0];
|
|
1384 my $mother = $it->{'mother'};
|
|
1385 return() unless $mother;
|
|
1386 my @sisters = @{$mother->{'daughters'}};
|
|
1387 return() if @sisters == 1; # I'm an only daughter
|
|
1388
|
|
1389 my @out = ();
|
|
1390 foreach my $one (@sisters) {
|
|
1391 return @out if $one eq $it;
|
|
1392 push @out, $one;
|
|
1393 }
|
|
1394 die "SPORK ERROR 9767: I'm not in my mother's daughter list!?!?";
|
|
1395 }
|
|
1396
|
|
1397 =item $node->right_sister
|
|
1398
|
|
1399 Returns the node that's the immediate right sister of $node. If $node
|
|
1400 is the rightmost (or only) daughter of its mother (or has no mother),
|
|
1401 then this returns undef.
|
|
1402
|
|
1403 (See also $node->add_right_sisters(LIST).)
|
|
1404
|
|
1405 =cut
|
|
1406
|
|
1407 sub right_sister {
|
|
1408 my $it = $_[0];
|
|
1409 my $mother = $it->{'mother'};
|
|
1410 return undef unless $mother;
|
|
1411 my @sisters = @{$mother->{'daughters'}};
|
|
1412 return undef if @sisters == 1; # I'm an only daughter
|
|
1413
|
|
1414 my $seen = 0;
|
|
1415 foreach my $one (@sisters) {
|
|
1416 return $one if $seen;
|
|
1417 $seen = 1 if $one eq $it;
|
|
1418 }
|
|
1419 die "SPORK ERROR 9777: I'm not in my mother's daughter list!?!?"
|
|
1420 unless $seen;
|
|
1421 return undef;
|
|
1422 }
|
|
1423
|
|
1424 =item $node->right_sisters
|
|
1425
|
|
1426 Returns a list of nodes that're sisters to the right of $node. If
|
|
1427 $node is the rightmost (or only) daughter of its mother (or has no
|
|
1428 mother), then this returns an empty list.
|
|
1429
|
|
1430 (See also $node->add_right_sisters(LIST).)
|
|
1431
|
|
1432 =cut
|
|
1433
|
|
1434 sub right_sisters {
|
|
1435 my $it = $_[0];
|
|
1436 my $mother = $it->{'mother'};
|
|
1437 return() unless $mother;
|
|
1438 my @sisters = @{$mother->{'daughters'}};
|
|
1439 return() if @sisters == 1; # I'm an only daughter
|
|
1440
|
|
1441 my @out;
|
|
1442 my $seen = 0;
|
|
1443 foreach my $one (@sisters) {
|
|
1444 push @out, $one if $seen;
|
|
1445 $seen = 1 if $one eq $it;
|
|
1446 }
|
|
1447 die "SPORK ERROR 9787: I'm not in my mother's daughter list!?!?"
|
|
1448 unless $seen;
|
|
1449 return @out;
|
|
1450 }
|
|
1451
|
|
1452 ###########################################################################
|
|
1453
|
|
1454 =item $node->my_daughter_index
|
|
1455
|
|
1456 Returns what index this daughter is, in its mother's C<daughter> list.
|
|
1457 In other words, if $node is ($node->mother->daughters)[3], then
|
|
1458 $node->my_daughter_index returns 3.
|
|
1459
|
|
1460 As a special case, returns 0 if $node has no mother.
|
|
1461
|
|
1462 =cut
|
|
1463
|
|
1464 sub my_daughter_index {
|
|
1465 # returns what number is my index in my mother's daughter list
|
|
1466 # special case: 0 for root.
|
|
1467 my $node = $_[0];
|
|
1468 my $ord = -1;
|
|
1469 my $mother = $node->{'mother'};
|
|
1470
|
|
1471 return 0 unless $mother;
|
|
1472 my @sisters = @{$mother->{'daughters'}};
|
|
1473
|
|
1474 die "SPORK ERROR 6512: My mother has no kids!!!" unless @sisters;
|
|
1475
|
|
1476 Find_Self:
|
|
1477 for(my $i = 0; $i < @sisters; $i++) {
|
|
1478 if($sisters[$i] eq $node) {
|
|
1479 $ord = $i;
|
|
1480 last Find_Self;
|
|
1481 }
|
|
1482 }
|
|
1483 die "SPORK ERROR 2837: I'm not a daughter of my mother?!?!" if $ord == -1;
|
|
1484 return $ord;
|
|
1485 }
|
|
1486
|
|
1487 ###########################################################################
|
|
1488
|
|
1489 =item $node->address or $anynode->address(ADDRESS)
|
|
1490
|
|
1491 With the first syntax, returns the address of $node within its tree,
|
|
1492 based on its position within the tree. An address is formed by noting
|
|
1493 the path between the root and $node, and concatenating the
|
|
1494 daughter-indices of the nodes this passes thru (starting with 0 for
|
|
1495 the root, and ending with $node).
|
|
1496
|
|
1497 For example, if to get from node ROOT to node $node, you pass thru
|
|
1498 ROOT, A, B, and $node, then the address is determined as:
|
|
1499
|
|
1500 * ROOT's my_daughter_index is 0.
|
|
1501
|
|
1502 * A's my_daughter_index is, suppose, 2. (A is index 2 in ROOT's
|
|
1503 daughter list.)
|
|
1504
|
|
1505 * B's my_daughter_index is, suppose, 0. (B is index 0 in A's
|
|
1506 daughter list.)
|
|
1507
|
|
1508 * $node's my_daughter_index is, suppose, 4. ($node is index 4 in
|
|
1509 B's daughter list.)
|
|
1510
|
|
1511 The address of the above-described $node is, therefore, "0:2:0:4".
|
|
1512
|
|
1513 (As a somewhat special case, the address of the root is always "0";
|
|
1514 and since addresses start from the root, all addresses start with a
|
|
1515 "0".)
|
|
1516
|
|
1517 The second syntax, where you provide an address, starts from the root
|
|
1518 of the tree $anynode belongs to, and returns the node corresponding to
|
|
1519 that address. Returns undef if no node corresponds to that address.
|
|
1520 Note that this routine may be somewhat liberal in its interpretation
|
|
1521 of what can constitute an address; i.e., it accepts "0.2.0.4", besides
|
|
1522 "0:2:0:4".
|
|
1523
|
|
1524 Also note that the address of a node in a tree is meaningful only in
|
|
1525 that tree as currently structured.
|
|
1526
|
|
1527 (Consider how ($address1 cmp $address2) may be magically meaningful
|
|
1528 to you, if you mant to figure out what nodes are to the right of what
|
|
1529 other nodes.)
|
|
1530
|
|
1531 =cut
|
|
1532
|
|
1533 sub address {
|
|
1534 my($it, $address) = @_[0,1];
|
|
1535 if(defined($address) && length($address)) { # given the address, return the node.
|
|
1536 # invalid addresses return undef
|
|
1537 my $root = $it->root;
|
|
1538 my @parts = map {$_ + 0}
|
|
1539 $address =~ m/(\d+)/g; # generous!
|
|
1540 Carp::croak "Address \"$address\" is an ill-formed address" unless @parts;
|
|
1541 Carp::croak "Address \"$address\" must start with '0'" unless shift(@parts) == 0;
|
|
1542
|
|
1543 my $current_node = $root;
|
|
1544 while(@parts) { # no-op for root
|
|
1545 my $ord = shift @parts;
|
|
1546 my @daughters = @{$current_node->{'daughters'}};
|
|
1547
|
|
1548 if($#daughters < $ord) { # illegal address
|
|
1549 print "* $address has an out-of-range index ($ord)!" if $Debug;
|
|
1550 return undef;
|
|
1551 }
|
|
1552 $current_node = $daughters[$ord];
|
|
1553 unless(ref($current_node)) {
|
|
1554 print "* $address points to or thru a non-node!" if $Debug;
|
|
1555 return undef;
|
|
1556 }
|
|
1557 }
|
|
1558 return $current_node;
|
|
1559
|
|
1560 } else { # given the node, return the address
|
|
1561 my @parts = ();
|
|
1562 my $current_node = $it;
|
|
1563 my $mother;
|
|
1564
|
|
1565 while(defined( $mother = $current_node->{'mother'} ) && ref($mother)) {
|
|
1566 unshift @parts, $current_node->my_daughter_index;
|
|
1567 $current_node = $mother;
|
|
1568 }
|
|
1569 return join(':', 0, @parts);
|
|
1570 }
|
|
1571 }
|
|
1572
|
|
1573 ###########################################################################
|
|
1574
|
|
1575 =item $node->common(LIST)
|
|
1576
|
|
1577 Returns the lowest node in the tree that is ancestor-or-self to the
|
|
1578 nodes $node and LIST.
|
|
1579
|
|
1580 If the nodes are far enough apart in the tree, the answer is just the
|
|
1581 root.
|
|
1582
|
|
1583 If the nodes aren't all in the same tree, the answer is undef.
|
|
1584
|
|
1585 As a degenerate case, if LIST is empty, returns $node.
|
|
1586
|
|
1587 =cut
|
|
1588
|
|
1589 sub common { # Return the lowest node common to all these nodes...
|
|
1590 # Called as $it->common($other) or $it->common(@others)
|
|
1591 my @ones = @_; # all nodes I was given
|
|
1592 my($first, @others) = @_;
|
|
1593
|
|
1594 return $first unless @others; # degenerate case
|
|
1595
|
|
1596 my %ones;
|
|
1597 @ones{ @ones } = undef;
|
|
1598
|
|
1599 foreach my $node (@others) {
|
|
1600 Carp::croak "TILT: node \"$node\" is not a node"
|
|
1601 unless UNIVERSAL::can($node, 'is_node');
|
|
1602 my %first_lineage;
|
|
1603 @first_lineage{$first, $first->ancestors} = undef;
|
|
1604 my $higher = undef; # the common of $first and $node
|
|
1605 my @my_lineage = $node->ancestors;
|
|
1606
|
|
1607 Find_Common:
|
|
1608 while(@my_lineage) {
|
|
1609 if(exists $first_lineage{$my_lineage[0]}) {
|
|
1610 $higher = $my_lineage[0];
|
|
1611 last Find_Common;
|
|
1612 }
|
|
1613 shift @my_lineage;
|
|
1614 }
|
|
1615 return undef unless $higher;
|
|
1616 $first = $higher;
|
|
1617 }
|
|
1618 return $first;
|
|
1619 }
|
|
1620
|
|
1621
|
|
1622 ###########################################################################
|
|
1623
|
|
1624 =item $node->common_ancestor(LIST)
|
|
1625
|
|
1626 Returns the lowest node that is ancestor to all the nodes given (in
|
|
1627 nodes $node and LIST). In other words, it answers the question: "What
|
|
1628 node in the tree, as low as possible, is ancestor to the nodes given
|
|
1629 ($node and LIST)?"
|
|
1630
|
|
1631 If the nodes are far enough apart, the answer is just the root --
|
|
1632 except if any of the nodes are the root itself, in which case the
|
|
1633 answer is undef (since the root has no ancestor).
|
|
1634
|
|
1635 If the nodes aren't all in the same tree, the answer is undef.
|
|
1636
|
|
1637 As a degenerate case, if LIST is empty, returns $node's mother;
|
|
1638 that'll be undef if $node is root.
|
|
1639
|
|
1640 =cut
|
|
1641
|
|
1642 sub common_ancestor {
|
|
1643 my @ones = @_; # all nodes I was given
|
|
1644 my($first, @others) = @_;
|
|
1645
|
|
1646 return $first->{'mother'} unless @others;
|
|
1647 # which may be undef if $first is the root!
|
|
1648
|
|
1649 my %ones;
|
|
1650 @ones{ @ones } = undef; # my arguments
|
|
1651
|
|
1652 my $common = $first->common(@others);
|
|
1653 if(exists($ones{$common})) { # if the common is one of my nodes...
|
|
1654 return $common->{'mother'};
|
|
1655 # and this might be undef, if $common is root!
|
|
1656 } else {
|
|
1657 return $common;
|
|
1658 # which might be null if that's all common came up with
|
|
1659 }
|
|
1660 }
|
|
1661
|
|
1662 ###########################################################################
|
|
1663 ###########################################################################
|
|
1664
|
|
1665 =back
|
|
1666
|
|
1667 =head1 YET MORE METHODS
|
|
1668
|
|
1669 =over
|
|
1670
|
|
1671 =item $node->walk_down({ callback => \&foo, callbackback => \&foo, ... })
|
|
1672
|
|
1673 Performs a depth-first traversal of the structure at and under $node.
|
|
1674 What it does at each node depends on the value of the options hashref,
|
|
1675 which you must provide. There are three options, "callback" and
|
|
1676 "callbackback" (at least one of which must be defined, as a sub
|
|
1677 reference), and "_depth". This is what C<walk_down> does, in
|
|
1678 pseudocode form:
|
|
1679
|
|
1680 * Start at the $node given.
|
|
1681
|
|
1682 * If there's a C<callback>, call it with $node as the first argument,
|
|
1683 and the options hashref as the second argument (which contains the
|
|
1684 potentially useful C<_depth>, remember). This function must return
|
|
1685 true or false -- if false, it will block the next step:
|
|
1686
|
|
1687 * If $node has any daughter nodes, increment C<_depth>, and call
|
|
1688 $daughter->walk_down(options_hashref) for each daughter (in order, of
|
|
1689 course), where options_hashref is the same hashref it was called with.
|
|
1690 When this returns, decrements C<_depth>.
|
|
1691
|
|
1692 * If there's a C<callbackback>, call just it as with C<callback> (but
|
|
1693 tossing out the return value). Note that C<callback> returning false
|
|
1694 blocks traversal below $node, but doesn't block calling callbackback
|
|
1695 for $node. (Incidentally, in the unlikely case that $node has stopped
|
|
1696 being a node object, C<callbackback> won't get called.)
|
|
1697
|
|
1698 * Return.
|
|
1699
|
|
1700 $node->walk_down is the way to recursively do things to a tree (if you
|
|
1701 start at the root) or part of a tree; if what you're doing is best done
|
|
1702 via pre-pre order traversal, use C<callback>; if what you're doing is
|
|
1703 best done with post-order traversal, use C<callbackback>.
|
|
1704 C<walk_down> is even the basis for plenty of the methods in this
|
|
1705 class. See the source code for examples both simple and horrific.
|
|
1706
|
|
1707 Note that if you don't specify C<_depth>, it effectively defaults to
|
|
1708 0. You should set it to scalar($node->ancestors) if you want
|
|
1709 C<_depth> to reflect the true depth-in-the-tree for the nodes called,
|
|
1710 instead of just the depth below $node. (If $node is the root, there's
|
|
1711 difference, of course.)
|
|
1712
|
|
1713 And B<by the way>, it's a bad idea to modify the tree from the callback.
|
|
1714 Unpredictable things may happen. I instead suggest having your callback
|
|
1715 add to a stack of things that need changing, and then, once C<walk_down>
|
|
1716 is all finished, changing those nodes from that stack.
|
|
1717
|
|
1718 Note that the existence of C<walk_down> doesn't mean you can't write
|
|
1719 you own special-use traversers.
|
|
1720
|
|
1721 =cut
|
|
1722
|
|
1723 sub walk_down {
|
|
1724 my($this, $o) = @_[0,1];
|
|
1725
|
|
1726 # All the can()s are in case an object changes class while I'm
|
|
1727 # looking at it.
|
|
1728
|
|
1729 Carp::croak "I need options!" unless ref($o);
|
|
1730 Carp::croak "I need a callback or a callbackback" unless
|
|
1731 ( ref($o->{'callback'}) || ref($o->{'callbackback'}) );
|
|
1732
|
|
1733 # $this->no_cyclicity;
|
|
1734 my $callback = ref($o->{'callback'}) ? $o->{'callback'} : undef;
|
|
1735 my $callbackback = ref($o->{'callbackback'}) ? $o->{'callbackback'} : undef;
|
|
1736 my $callback_status = 1;
|
|
1737
|
|
1738 print "Callback: $callback Callbackback: $callbackback\n" if $Debug;
|
|
1739
|
|
1740 printf "* Entering %s\n", ($this->name || $this) if $Debug;
|
|
1741 $callback_status = &{ $callback }( $this, $o ) if $callback;
|
|
1742
|
|
1743 if($callback_status) {
|
|
1744 # Keep recursing unless callback returned false... and if there's
|
|
1745 # anything to recurse into, of course.
|
|
1746 my @daughters = UNIVERSAL::can($this, 'is_node') ? @{$this->{'daughters'}} : ();
|
|
1747 if(@daughters) {
|
|
1748 $o->{'_depth'} += 1;
|
|
1749 #print "Depth " , $o->{'_depth'}, "\n";
|
|
1750 foreach my $one (@daughters) {
|
|
1751 $one->walk_down($o) if UNIVERSAL::can($one, 'is_node');
|
|
1752 # and if it can do "is_node", it should provide a walk_down!
|
|
1753 }
|
|
1754 $o->{'_depth'} -= 1;
|
|
1755 }
|
|
1756 } else {
|
|
1757 printf "* Recursing below %s pruned\n", ($this->name || $this) if $Debug;
|
|
1758 }
|
|
1759
|
|
1760 # Note that $callback_status doesn't block callbackback from being called
|
|
1761 if($callbackback){
|
|
1762 if(UNIVERSAL::can($this, 'is_node')) { # if it's still a node!
|
|
1763 print "* Calling callbackback\n" if $Debug;
|
|
1764 scalar( &{ $callbackback }( $this, $o ) );
|
|
1765 # scalar to give it the same context as callback
|
|
1766 } else {
|
|
1767 print "* Can't call callbackback -- $this isn't a node anymore\n"
|
|
1768 if $Debug;
|
|
1769 }
|
|
1770 }
|
|
1771 if($Debug) {
|
|
1772 if(UNIVERSAL::can($this, 'is_node')) { # if it's still a node!
|
|
1773 printf "* Leaving %s\n", ($this->name || $this)
|
|
1774 } else {
|
|
1775 print "* Leaving [no longer a node]\n";
|
|
1776 }
|
|
1777 }
|
|
1778 return;
|
|
1779 }
|
|
1780
|
|
1781 ###########################################################################
|
|
1782
|
|
1783 =item @lines = $node->dump_names({ ...options... });
|
|
1784
|
|
1785 Dumps, as an indented list, the names of the nodes starting at $node,
|
|
1786 and continuing under it. Options are:
|
|
1787
|
|
1788 * _depth -- A nonnegative number. Indicating the depth to consider
|
|
1789 $node as being at (and so the generation under that is that plus one,
|
|
1790 etc.). Defaults to 0. You may choose to use set _depth =>
|
|
1791 scalar($node->ancestors).
|
|
1792
|
|
1793 * tick -- a string to preface each entry with, between the
|
|
1794 indenting-spacing and the node's name. Defaults to empty-string. You
|
|
1795 may prefer "*" or "-> " or someting.
|
|
1796
|
|
1797 * indent -- the string used to indent with. Defaults to " " (two
|
|
1798 spaces). Another sane value might be ". " (period, space). Setting it
|
|
1799 to empty-string suppresses indenting.
|
|
1800
|
|
1801 The dump is not printed, but is returned as a list, where each
|
|
1802 item is a line, with a "\n" at the end.
|
|
1803
|
|
1804 =cut
|
|
1805
|
|
1806 sub dump_names {
|
|
1807 my($it, $o) = @_[0,1];
|
|
1808 $o = {} unless ref $o;
|
|
1809 my @out = ();
|
|
1810 $o->{'_depth'} ||= 0;
|
|
1811 $o->{'indent'} ||= ' ';
|
|
1812 $o->{'tick'} ||= '';
|
|
1813
|
|
1814 $o->{'callback'} = sub {
|
|
1815 my($this, $o) = @_[0,1];
|
|
1816 push(@out,
|
|
1817 join('',
|
|
1818 $o->{'indent'} x $o->{'_depth'},
|
|
1819 $o->{'tick'},
|
|
1820 &Tree::DAG_Node::_dump_quote($this->name || $this),
|
|
1821 "\n"
|
|
1822 )
|
|
1823 );
|
|
1824 return 1;
|
|
1825 }
|
|
1826 ;
|
|
1827 $it->walk_down($o);
|
|
1828 return @out;
|
|
1829 }
|
|
1830
|
|
1831 ###########################################################################
|
|
1832 ###########################################################################
|
|
1833
|
|
1834 =item the constructor CLASS->random_network({...options...})
|
|
1835
|
|
1836 =item the method $node->random_network({...options...})
|
|
1837
|
|
1838 In the first case, constructs a randomly arranged network under a new
|
|
1839 node, and returns the root node of that tree. In the latter case,
|
|
1840 constructs the network under $node.
|
|
1841
|
|
1842 Currently, this is implemented a bit half-heartedly, and
|
|
1843 half-wittedly. I basically needed to make up random-looking networks
|
|
1844 to stress-test the various tree-dumper methods, and so wrote this. If
|
|
1845 you actually want to rely on this for any application more
|
|
1846 serious than that, I suggest examining the source code and seeing if
|
|
1847 this does really what you need (say, in reliability of randomness);
|
|
1848 and feel totally free to suggest changes to me (especially in the form
|
|
1849 of "I rewrote C<random_network>, here's the code...")
|
|
1850
|
|
1851 It takes four options:
|
|
1852
|
|
1853 * max_node_count -- maximum number of nodes this tree will be allowed
|
|
1854 to have (counting the root). Defaults to 25.
|
|
1855
|
|
1856 * min_depth -- minimum depth for the tree. Defaults to 2. Leaves can
|
|
1857 be generated only after this depth is reached, so the tree will be at
|
|
1858 least this deep -- unless max_node_count is hit first.
|
|
1859
|
|
1860 * max_depth -- maximum depth for the tree. Defaults to 3 plus
|
|
1861 min_depth. The tree will not be deeper than this.
|
|
1862
|
|
1863 * max_children -- maximum number of children any mother in the tree
|
|
1864 can have. Defaults to 4.
|
|
1865
|
|
1866 =cut
|
|
1867
|
|
1868 sub random_network { # constructor or method.
|
|
1869 my $class = $_[0];
|
|
1870 my $o = ref($_[1]) ? $_[1] : {};
|
|
1871 my $am_cons = 0;
|
|
1872 my $root;
|
|
1873
|
|
1874 if(ref($class)){ # I'm a method.
|
|
1875 $root = $_[0]; # build under the given node, from same class.
|
|
1876 $class = ref $class;
|
|
1877 $am_cons = 0;
|
|
1878 } else { # I'm a constructor
|
|
1879 $root = $class->new; # build under a new node, with class named.
|
|
1880 $root->name("Root");
|
|
1881 $am_cons = 1;
|
|
1882 }
|
|
1883
|
|
1884 my $min_depth = $o->{'min_depth'} || 2;
|
|
1885 my $max_depth = $o->{'max_depth'} || ($min_depth + 3);
|
|
1886 my $max_children = $o->{'max_children'} || 4;
|
|
1887 my $max_node_count = $o->{'max_node_count'} || 25;
|
|
1888
|
|
1889 Carp::croak "max_children has to be positive" if int($max_children) < 1;
|
|
1890
|
|
1891 my @mothers = ( $root );
|
|
1892 my @children = ( );
|
|
1893 my $node_count = 1; # the root
|
|
1894
|
|
1895 Gen:
|
|
1896 foreach my $depth (1 .. $max_depth) {
|
|
1897 last if $node_count > $max_node_count;
|
|
1898 Mother:
|
|
1899 foreach my $mother (@mothers) {
|
|
1900 last Gen if $node_count > $max_node_count;
|
|
1901 my $children_number;
|
|
1902 if($depth <= $min_depth) {
|
|
1903 until( $children_number = int(rand(1 + $max_children)) ) {}
|
|
1904 } else {
|
|
1905 $children_number = int(rand($max_children));
|
|
1906 }
|
|
1907 Beget:
|
|
1908 foreach (1 .. $children_number) {
|
|
1909 last Gen if $node_count > $max_node_count;
|
|
1910 my $node = $mother->new_daughter;
|
|
1911 $node->name("Node$node_count");
|
|
1912 ++$node_count;
|
|
1913 push(@children, $node);
|
|
1914 }
|
|
1915 }
|
|
1916 @mothers = @children;
|
|
1917 @children = ();
|
|
1918 last unless @mothers;
|
|
1919 }
|
|
1920
|
|
1921 return $root;
|
|
1922 }
|
|
1923
|
|
1924 =item the constructor CLASS->lol_to_tree($lol);
|
|
1925
|
|
1926 Converts something like bracket-notation for "Chomsky trees" (or
|
|
1927 rather, the closest you can come with Perl
|
|
1928 list-of-lists(-of-lists(-of-lists))) into a tree structure. Returns
|
|
1929 the root of the tree converted.
|
|
1930
|
|
1931 The conversion rules are that: 1) if the last (possibly the only) item
|
|
1932 in a given list is a scalar, then that is used as the "name" attribute
|
|
1933 for the node based on this list. 2) All other items in the list
|
|
1934 represent daughter nodes of the current node -- recursively so, if
|
|
1935 they are list references; otherwise, (non-terminal) scalars are
|
|
1936 considered to denote nodes with that name. So ['Foo', 'Bar', 'N'] is
|
|
1937 an alternate way to represent [['Foo'], ['Bar'], 'N'].
|
|
1938
|
|
1939 An example will illustrate:
|
|
1940
|
|
1941 use Tree::DAG_Node;
|
|
1942 $lol =
|
|
1943 [
|
|
1944 [
|
|
1945 [ [ 'Det:The' ],
|
|
1946 [ [ 'dog' ], 'N'], 'NP'],
|
|
1947 [ '/with rabies\\', 'PP'],
|
|
1948 'NP'
|
|
1949 ],
|
|
1950 [ 'died', 'VP'],
|
|
1951 'S'
|
|
1952 ];
|
|
1953 $tree = Tree::DAG_Node->lol_to_tree($lol);
|
|
1954 $diagram = $tree->draw_ascii_tree;
|
|
1955 print map "$_\n", @$diagram;
|
|
1956
|
|
1957 ...returns this tree:
|
|
1958
|
|
1959 |
|
|
1960 <S>
|
|
1961 |
|
|
1962 /------------------\
|
|
1963 | |
|
|
1964 <NP> <VP>
|
|
1965 | |
|
|
1966 /---------------\ <died>
|
|
1967 | |
|
|
1968 <NP> <PP>
|
|
1969 | |
|
|
1970 /-------\ </with rabies\>
|
|
1971 | |
|
|
1972 <Det:The> <N>
|
|
1973 |
|
|
1974 <dog>
|
|
1975
|
|
1976 By the way (and this rather follows from the above rules), when
|
|
1977 denoting a LoL tree consisting of just one node, this:
|
|
1978
|
|
1979 $tree = Tree::DAG_Node->lol_to_tree( 'Lonely' );
|
|
1980
|
|
1981 is okay, although it'd probably occur to you to denote it only as:
|
|
1982
|
|
1983 $tree = Tree::DAG_Node->lol_to_tree( ['Lonely'] );
|
|
1984
|
|
1985 which is of course fine, too.
|
|
1986
|
|
1987 =cut
|
|
1988
|
|
1989 sub lol_to_tree {
|
|
1990 my($class, $lol, $seen_r) = @_[0,1,2];
|
|
1991 $seen_r = {} unless ref($seen_r) eq 'HASH';
|
|
1992 return if ref($lol) && $seen_r->{$lol}++; # catch circularity
|
|
1993
|
|
1994 $class = ref($class) || $class;
|
|
1995 my $node = $class->new();
|
|
1996
|
|
1997 unless(ref($lol) eq 'ARRAY') { # It's a terminal node.
|
|
1998 $node->name($lol) if defined $lol;
|
|
1999 return $node;
|
|
2000 }
|
|
2001 return $node unless @$lol; # It's a terminal node, oddly represented
|
|
2002
|
|
2003 # It's a non-terminal node.
|
|
2004
|
|
2005 my @options = @$lol;
|
|
2006 unless(ref($options[-1]) eq 'ARRAY') {
|
|
2007 # This is what separates this method from simple_lol_to_tree
|
|
2008 $node->name(pop(@options));
|
|
2009 }
|
|
2010
|
|
2011 foreach my $d (@options) { # Scan daughters (whether scalars or listrefs)
|
|
2012 $node->add_daughter( $class->lol_to_tree($d, $seen_r) ); # recurse!
|
|
2013 }
|
|
2014
|
|
2015 return $node;
|
|
2016 }
|
|
2017
|
|
2018 #--------------------------------------------------------------------------
|
|
2019
|
|
2020 =item $node->tree_to_lol_notation({...options...})
|
|
2021
|
|
2022 Dumps a tree (starting at $node) as the sort of LoL-like bracket
|
|
2023 notation you see in the above example code. Returns just one big
|
|
2024 block of text. The only option is "multiline" -- if true, it dumps
|
|
2025 the text as the sort of indented structure as seen above; if false
|
|
2026 (and it defaults to false), dumps it all on one line (with no
|
|
2027 indenting, of course).
|
|
2028
|
|
2029 For example, starting with the tree from the above example,
|
|
2030 this:
|
|
2031
|
|
2032 print $tree->tree_to_lol_notation, "\n";
|
|
2033
|
|
2034 prints the following (which I've broken over two lines for sake of
|
|
2035 printablitity of documentation):
|
|
2036
|
|
2037 [[[['Det:The'], [['dog'], 'N'], 'NP'], [["/with rabies\x5c"],
|
|
2038 'PP'], 'NP'], [['died'], 'VP'], 'S'],
|
|
2039
|
|
2040 Doing this:
|
|
2041
|
|
2042 print $tree->tree_to_lol_notation({ multiline => 1 });
|
|
2043
|
|
2044 prints the same content, just spread over many lines, and prettily
|
|
2045 indented.
|
|
2046
|
|
2047 =cut
|
|
2048
|
|
2049 #--------------------------------------------------------------------------
|
|
2050
|
|
2051 sub tree_to_lol_notation {
|
|
2052 my $root = $_[0];
|
|
2053 my($it, $o) = @_[0,1];
|
|
2054 $o = {} unless ref $o;
|
|
2055 my @out = ();
|
|
2056 $o->{'_depth'} ||= 0;
|
|
2057 $o->{'multiline'} = 0 unless exists($o->{'multiline'});
|
|
2058
|
|
2059 my $line_end;
|
|
2060 if($o->{'multiline'}) {
|
|
2061 $o->{'indent'} ||= ' ';
|
|
2062 $line_end = "\n";
|
|
2063 } else {
|
|
2064 $o->{'indent'} ||= '';
|
|
2065 $line_end = '';
|
|
2066 }
|
|
2067
|
|
2068 $o->{'callback'} = sub {
|
|
2069 my($this, $o) = @_[0,1];
|
|
2070 push(@out,
|
|
2071 $o->{'indent'} x $o->{'_depth'},
|
|
2072 "[$line_end",
|
|
2073 );
|
|
2074 return 1;
|
|
2075 }
|
|
2076 ;
|
|
2077 $o->{'callbackback'} = sub {
|
|
2078 my($this, $o) = @_[0,1];
|
|
2079 my $name = $this->name;
|
|
2080 if(!defined($name)) {
|
|
2081 $name = 'undef';
|
|
2082 } else {
|
|
2083 $name = &Tree::DAG_Node::_dump_quote($name);
|
|
2084 }
|
|
2085 push(@out,
|
|
2086 $o->{'indent'} x ($o->{'_depth'} + 1),
|
|
2087 "$name$line_end",
|
|
2088 $o->{'indent'} x $o->{'_depth'},
|
|
2089 "], $line_end",
|
|
2090 );
|
|
2091 return 1;
|
|
2092 }
|
|
2093 ;
|
|
2094 $it->walk_down($o);
|
|
2095 return join('', @out);
|
|
2096 }
|
|
2097
|
|
2098 #--------------------------------------------------------------------------
|
|
2099
|
|
2100 =item $node->tree_to_lol
|
|
2101
|
|
2102 Returns that tree (starting at $node) represented as a LoL, like what
|
|
2103 $lol, above, holds. (This is as opposed to C<tree_to_lol_notation>,
|
|
2104 which returns the viewable code like what gets evaluated and stored in
|
|
2105 $lol, above.)
|
|
2106
|
|
2107 Lord only knows what you use this for -- maybe for feeding to
|
|
2108 Data::Dumper, in case C<tree_to_lol_notation> doesn't do just what you
|
|
2109 want?
|
|
2110
|
|
2111 =cut
|
|
2112
|
|
2113 sub tree_to_lol {
|
|
2114 # I haven't /rigorously/ tested this.
|
|
2115 my($it, $o) = @_[0,1]; # $o is currently unused anyway
|
|
2116 $o = {} unless ref $o;
|
|
2117
|
|
2118 my $out = [];
|
|
2119 my @lol_stack = ($out);
|
|
2120 $o->{'callback'} = sub {
|
|
2121 my($this, $o) = @_[0,1];
|
|
2122 my $new = [];
|
|
2123 push @{$lol_stack[-1]}, $new;
|
|
2124 push(@lol_stack, $new);
|
|
2125 return 1;
|
|
2126 }
|
|
2127 ;
|
|
2128 $o->{'callbackback'} = sub {
|
|
2129 my($this, $o) = @_[0,1];
|
|
2130 push @{$lol_stack[-1]}, $this->name;
|
|
2131 pop @lol_stack;
|
|
2132 return 1;
|
|
2133 }
|
|
2134 ;
|
|
2135 $it->walk_down($o);
|
|
2136 die "totally bizarre error 12416" unless ref($out->[0]);
|
|
2137 $out = $out->[0]; # the real root
|
|
2138 return $out;
|
|
2139 }
|
|
2140
|
|
2141 ###########################################################################
|
|
2142
|
|
2143 =item the constructor CLASS->simple_lol_to_tree($simple_lol);
|
|
2144
|
|
2145 This is like lol_to_tree, except that rule 1 doesn't apply -- i.e.,
|
|
2146 all scalars (or really, anything not a listref) in the LoL-structure
|
|
2147 end up as named terminal nodes, and only terminal nodes get names
|
|
2148 (and, of course, that name comes from that scalar value). This method
|
|
2149 is useful for making things like expression trees, or at least
|
|
2150 starting them off. Consider that this:
|
|
2151
|
|
2152 $tree = Tree::DAG_Node->simple_lol_to_tree(
|
|
2153 [ 'foo', ['bar', ['baz'], 'quux'], 'zaz', 'pati' ]
|
|
2154 );
|
|
2155
|
|
2156 converts from something like a Lispish or Iconish tree, if you pretend
|
|
2157 the brackets are parentheses.
|
|
2158
|
|
2159 Note that there is a (possibly surprising) degenerate case of what I'm
|
|
2160 calling a "simple-LoL", and it's like this:
|
|
2161
|
|
2162 $tree = Tree::DAG_Node->simple_lol_to_tree('Lonely');
|
|
2163
|
|
2164 This is the (only) way you can specify a tree consisting of only a
|
|
2165 single node, which here gets the name 'Lonely'.
|
|
2166
|
|
2167 =cut
|
|
2168
|
|
2169 sub simple_lol_to_tree {
|
|
2170 my($class, $lol, $seen_r) = @_[0,1,2];
|
|
2171 $class = ref($class) || $class;
|
|
2172 $seen_r = {} unless ref($seen_r) eq 'HASH';
|
|
2173 return if ref($lol) && $seen_r->{$lol}++; # catch circularity
|
|
2174
|
|
2175 my $node = $class->new();
|
|
2176
|
|
2177 unless(ref($lol) eq 'ARRAY') { # It's a terminal node.
|
|
2178 $node->name($lol) if defined $lol;
|
|
2179 return $node;
|
|
2180 }
|
|
2181
|
|
2182 # It's a non-terminal node.
|
|
2183 foreach my $d (@$lol) { # scan daughters (whether scalars or listrefs)
|
|
2184 $node->add_daughter( $class->simple_lol_to_tree($d, $seen_r) ); # recurse!
|
|
2185 }
|
|
2186
|
|
2187 return $node;
|
|
2188 }
|
|
2189
|
|
2190 #--------------------------------------------------------------------------
|
|
2191
|
|
2192 =item $node->tree_to_simple_lol
|
|
2193
|
|
2194 Returns that tree (starting at $node) represented as a simple-LoL --
|
|
2195 i.e., one where non-terminal nodes are represented as listrefs, and
|
|
2196 terminal nodes are gotten from the contents of those nodes' "name'
|
|
2197 attributes.
|
|
2198
|
|
2199 Note that in the case of $node being terminal, what you get back is
|
|
2200 the same as $node->name.
|
|
2201
|
|
2202 Compare to tree_to_simple_lol_notation.
|
|
2203
|
|
2204 =cut
|
|
2205
|
|
2206 sub tree_to_simple_lol {
|
|
2207 # I haven't /rigorously/ tested this.
|
|
2208 my $root = $_[0];
|
|
2209
|
|
2210 return $root->name unless scalar($root->daughters);
|
|
2211 # special case we have to nip in the bud
|
|
2212
|
|
2213 my($it, $o) = @_[0,1]; # $o is currently unused anyway
|
|
2214 $o = {} unless ref $o;
|
|
2215
|
|
2216 my $out = [];
|
|
2217 my @lol_stack = ($out);
|
|
2218 $o->{'callback'} = sub {
|
|
2219 my($this, $o) = @_[0,1];
|
|
2220 my $new;
|
|
2221 $new = scalar($this->daughters) ? [] : $this->name;
|
|
2222 # Terminal nodes are scalars, the rest are listrefs we'll fill in
|
|
2223 # as we recurse the tree below here.
|
|
2224 push @{$lol_stack[-1]}, $new;
|
|
2225 push(@lol_stack, $new);
|
|
2226 return 1;
|
|
2227 }
|
|
2228 ;
|
|
2229 $o->{'callbackback'} = sub { pop @lol_stack; return 1; };
|
|
2230 $it->walk_down($o);
|
|
2231 die "totally bizarre error 12416" unless ref($out->[0]);
|
|
2232 $out = $out->[0]; # the real root
|
|
2233 return $out;
|
|
2234 }
|
|
2235
|
|
2236 #--------------------------------------------------------------------------
|
|
2237
|
|
2238 =item $node->tree_to_simple_lol_notation({...options...})
|
|
2239
|
|
2240 A simple-LoL version of tree_to_lol_notation (which see); takes the
|
|
2241 same options.
|
|
2242
|
|
2243 =cut
|
|
2244
|
|
2245 sub tree_to_simple_lol_notation {
|
|
2246 my($it, $o) = @_[0,1];
|
|
2247 $o = {} unless ref $o;
|
|
2248 my @out = ();
|
|
2249 $o->{'_depth'} ||= 0;
|
|
2250 $o->{'multiline'} = 0 unless exists($o->{'multiline'});
|
|
2251
|
|
2252 my $line_end;
|
|
2253 if($o->{'multiline'}) {
|
|
2254 $o->{'indent'} ||= ' ';
|
|
2255 $line_end = "\n";
|
|
2256 } else {
|
|
2257 $o->{'indent'} ||= '';
|
|
2258 $line_end = '';
|
|
2259 }
|
|
2260
|
|
2261 $o->{'callback'} = sub {
|
|
2262 my($this, $o) = @_[0,1];
|
|
2263 if(scalar($this->daughters)) { # Nonterminal
|
|
2264 push(@out,
|
|
2265 $o->{'indent'} x $o->{'_depth'},
|
|
2266 "[$line_end",
|
|
2267 );
|
|
2268 } else { # Terminal
|
|
2269 my $name = $this->name;
|
|
2270 push @out,
|
|
2271 $o->{'indent'} x $o->{'_depth'},
|
|
2272 defined($name) ? &Tree::DAG_Node::_dump_quote($name) : 'undef',
|
|
2273 ",$line_end";
|
|
2274 }
|
|
2275 return 1;
|
|
2276 }
|
|
2277 ;
|
|
2278 $o->{'callbackback'} = sub {
|
|
2279 my($this, $o) = @_[0,1];
|
|
2280 push(@out,
|
|
2281 $o->{'indent'} x $o->{'_depth'},
|
|
2282 "], $line_end",
|
|
2283 ) if scalar($this->daughters);
|
|
2284 return 1;
|
|
2285 }
|
|
2286 ;
|
|
2287
|
|
2288 $it->walk_down($o);
|
|
2289 return join('', @out);
|
|
2290 }
|
|
2291
|
|
2292 ###########################################################################
|
|
2293 # $list_r = $root_node->draw_ascii_tree({ h_compact => 1});
|
|
2294 # print map("$_\n", @$list_r);
|
|
2295
|
|
2296 =item $list_r = $node->draw_ascii_tree({ ... options ... })
|
|
2297
|
|
2298 Draws a nice ASCII-art representation of the tree structure
|
|
2299 at-and-under $node, with $node at the top. Returns a reference to the
|
|
2300 list of lines (with no "\n"s or anything at the end of them) that make
|
|
2301 up the picture.
|
|
2302
|
|
2303 Example usage:
|
|
2304
|
|
2305 print map("$_\n", @{$tree->draw_ascii_tree});
|
|
2306
|
|
2307 draw_ascii_tree takes parameters you set in the options hashref:
|
|
2308
|
|
2309 * "no_name" -- if true, C<draw_ascii_tree> doesn't print the name of
|
|
2310 the node; simply prints a "*". Defaults to 0 (i.e., print the node
|
|
2311 name.)
|
|
2312
|
|
2313 * "h_spacing" -- number 0 or greater. Sets the number of spaces
|
|
2314 inserted horizontally between nodes (and groups of nodes) in a tree.
|
|
2315 Defaults to 1.
|
|
2316
|
|
2317 * "h_compact" -- number 0 or 1. Sets the extent to which
|
|
2318 C<draw_ascii_tree> tries to save horizontal space. Defaults to 1. If
|
|
2319 I think of a better scrunching algorithm, there'll be a "2" setting
|
|
2320 for this.
|
|
2321
|
|
2322 * "v_compact" -- number 0, 1, or 2. Sets the degree to which
|
|
2323 C<draw_ascii_tree> tries to save vertical space. Defaults to 1.
|
|
2324
|
|
2325 This occasionally returns trees that are a bit cock-eyed in parts; if
|
|
2326 anyone can suggest a better drawing algorithm, I'd be appreciative.
|
|
2327
|
|
2328 =cut
|
|
2329
|
|
2330 sub draw_ascii_tree {
|
|
2331 # Make a "box" for this node and its possible daughters, recursively.
|
|
2332
|
|
2333 # The guts of this routine are horrific AND recursive!
|
|
2334
|
|
2335 # Feel free to send me better code. I worked on this until it
|
|
2336 # gave me a headache and it worked passably, and then I stopped.
|
|
2337
|
|
2338 my $it = $_[0];
|
|
2339 my $o = ref($_[1]) ? $_[1] : {};
|
|
2340 my(@box, @daughter_boxes, $width, @daughters);
|
|
2341 @daughters = @{$it->{'daughters'}};
|
|
2342
|
|
2343 # $it->no_cyclicity;
|
|
2344
|
|
2345 $o->{'no_name'} = 0 unless exists $o->{'no_name'};
|
|
2346 $o->{'h_spacing'} = 1 unless exists $o->{'h_spacing'};
|
|
2347 $o->{'h_compact'} = 1 unless exists $o->{'h_compact'};
|
|
2348 $o->{'v_compact'} = 1 unless exists $o->{'v_compact'};
|
|
2349
|
|
2350 my $printable_name;
|
|
2351 if($o->{'no_name'}) {
|
|
2352 $printable_name = '*';
|
|
2353 } else {
|
|
2354 $printable_name = $it->name || $it;
|
|
2355 $printable_name =~ tr<\cm\cj\t >< >s;
|
|
2356 $printable_name = "<$printable_name>";
|
|
2357 }
|
|
2358
|
|
2359 if(!scalar(@daughters)) { # I am a leaf!
|
|
2360 # Now add the top parts, and return.
|
|
2361 @box = ("|", $printable_name);
|
|
2362 } else {
|
|
2363 @daughter_boxes = map { &draw_ascii_tree($_, $o) } @daughters;
|
|
2364
|
|
2365 my $max_height = 0;
|
|
2366 foreach my $box (@daughter_boxes) {
|
|
2367 my $h = @$box;
|
|
2368 $max_height = $h if $h > $max_height;
|
|
2369 }
|
|
2370
|
|
2371 @box = ('') x $max_height; # establish the list
|
|
2372
|
|
2373 foreach my $one (@daughter_boxes) {
|
|
2374 my $length = length($one->[0]);
|
|
2375 my $height = @$one;
|
|
2376
|
|
2377 #now make all the same height.
|
|
2378 my $deficit = $max_height - $height;
|
|
2379 if($deficit > 0) {
|
|
2380 push @$one, ( scalar( ' ' x $length ) ) x $deficit;
|
|
2381 $height = scalar(@$one);
|
|
2382 }
|
|
2383
|
|
2384
|
|
2385 # Now tack 'em onto @box
|
|
2386 ##########################################################
|
|
2387 # This used to be a sub of its own. Ho-hum.
|
|
2388
|
|
2389 my($b1, $b2) = (\@box, $one);
|
|
2390 my($h1, $h2) = (scalar(@$b1), scalar(@$b2));
|
|
2391
|
|
2392 my(@diffs, $to_chop);
|
|
2393 if($o->{'h_compact'}) { # Try for h-scrunching.
|
|
2394 my @diffs;
|
|
2395 my $min_diff = length($b1->[0]); # just for starters
|
|
2396 foreach my $line (0 .. ($h1 - 1)) {
|
|
2397 my $size_l = 0; # length of terminal whitespace
|
|
2398 my $size_r = 0; # length of initial whitespace
|
|
2399 $size_l = length($1) if $b1->[$line] =~ /( +)$/s;
|
|
2400 $size_r = length($1) if $b2->[$line] =~ /^( +)/s;
|
|
2401 my $sum = $size_l + $size_r;
|
|
2402
|
|
2403 $min_diff = $sum if $sum < $min_diff;
|
|
2404 push @diffs, [$sum, $size_l, $size_r];
|
|
2405 }
|
|
2406 $to_chop = $min_diff - $o->{'h_spacing'};
|
|
2407 $to_chop = 0 if $to_chop < 0;
|
|
2408 }
|
|
2409
|
|
2410 if(not( $o->{'h_compact'} and $to_chop )) {
|
|
2411 # No H-scrunching needed/possible
|
|
2412 foreach my $line (0 .. ($h1 - 1)) {
|
|
2413 $b1->[ $line ] .= $b2->[ $line ] . (' ' x $o->{'h_spacing'});
|
|
2414 }
|
|
2415 } else {
|
|
2416 # H-scrunching is called for.
|
|
2417 foreach my $line (0 .. ($h1 - 1)) {
|
|
2418 my $r = $b2->[$line]; # will be the new line
|
|
2419 my $remaining = $to_chop;
|
|
2420 if($remaining) {
|
|
2421 my($l_chop, $r_chop) = @{$diffs[$line]}[1,2];
|
|
2422
|
|
2423 if($l_chop) {
|
|
2424 if($l_chop > $remaining) {
|
|
2425 $l_chop = $remaining;
|
|
2426 $remaining = 0;
|
|
2427 } elsif($l_chop == $remaining) {
|
|
2428 $remaining = 0;
|
|
2429 } else { # remaining > l_chop
|
|
2430 $remaining -= $l_chop;
|
|
2431 }
|
|
2432 }
|
|
2433 if($r_chop) {
|
|
2434 if($r_chop > $remaining) {
|
|
2435 $r_chop = $remaining;
|
|
2436 $remaining = 0;
|
|
2437 } elsif($r_chop == $remaining) {
|
|
2438 $remaining = 0;
|
|
2439 } else { # remaining > r_chop
|
|
2440 $remaining -= $r_chop; # should never happen!
|
|
2441 }
|
|
2442 }
|
|
2443
|
|
2444 substr($b1->[$line], -$l_chop) = '' if $l_chop;
|
|
2445 substr($r, 0, $r_chop) = '' if $r_chop;
|
|
2446 } # else no-op
|
|
2447 $b1->[ $line ] .= $r . (' ' x $o->{'h_spacing'});
|
|
2448 }
|
|
2449 # End of H-scrunching ickyness
|
|
2450 }
|
|
2451 # End of ye big tack-on
|
|
2452
|
|
2453 }
|
|
2454 # End of the foreach daughter_box loop
|
|
2455
|
|
2456 # remove any fencepost h_spacing
|
|
2457 if($o->{'h_spacing'}) {
|
|
2458 foreach my $line (@box) {
|
|
2459 substr($line, -$o->{'h_spacing'}) = '' if length($line);
|
|
2460 }
|
|
2461 }
|
|
2462
|
|
2463 # end of catenation
|
|
2464 die "SPORK ERROR 958203: Freak!!!!!" unless @box;
|
|
2465
|
|
2466 # Now tweak the pipes
|
|
2467 my $new_pipes = $box[0];
|
|
2468 my $pipe_count = $new_pipes =~ tr<|><+>;
|
|
2469 if($pipe_count < 2) {
|
|
2470 $new_pipes = "|";
|
|
2471 } else {
|
|
2472 my($init_space, $end_space);
|
|
2473
|
|
2474 # Thanks to Gilles Lamiral for pointing out the need to set to '',
|
|
2475 # to avoid -w warnings about undeffiness.
|
|
2476
|
|
2477 if( $new_pipes =~ s<^( +)><>s ) {
|
|
2478 $init_space = $1;
|
|
2479 } else {
|
|
2480 $init_space = '';
|
|
2481 }
|
|
2482
|
|
2483 if( $new_pipes =~ s<( +)$><>s ) {
|
|
2484 $end_space = $1
|
|
2485 } else {
|
|
2486 $end_space = '';
|
|
2487 }
|
|
2488
|
|
2489 $new_pipes =~ tr< ><->;
|
|
2490 substr($new_pipes,0,1) = "/";
|
|
2491 substr($new_pipes,-1,1) = "\\";
|
|
2492
|
|
2493 $new_pipes = $init_space . $new_pipes . $end_space;
|
|
2494 # substr($new_pipes, int((length($new_pipes)), 1)) / 2) = "^"; # feh
|
|
2495 }
|
|
2496
|
|
2497 # Now tack on the formatting for this node.
|
|
2498 if($o->{'v_compact'} == 2) {
|
|
2499 if(@daughters == 1) {
|
|
2500 unshift @box, "|", $printable_name;
|
|
2501 } else {
|
|
2502 unshift @box, "|", $printable_name, $new_pipes;
|
|
2503 }
|
|
2504 } elsif ($o->{'v_compact'} == 1 and @daughters == 1) {
|
|
2505 unshift @box, "|", $printable_name;
|
|
2506 } else { # general case
|
|
2507 unshift @box, "|", $printable_name, $new_pipes;
|
|
2508 }
|
|
2509 }
|
|
2510
|
|
2511 # Flush the edges:
|
|
2512 my $max_width = 0;
|
|
2513 foreach my $line (@box) {
|
|
2514 my $w = length($line);
|
|
2515 $max_width = $w if $w > $max_width;
|
|
2516 }
|
|
2517 foreach my $one (@box) {
|
|
2518 my $space_to_add = $max_width - length($one);
|
|
2519 next unless $space_to_add;
|
|
2520 my $add_left = int($space_to_add / 2);
|
|
2521 my $add_right = $space_to_add - $add_left;
|
|
2522 $one = (' ' x $add_left) . $one . (' ' x $add_right);
|
|
2523 }
|
|
2524
|
|
2525 return \@box; # must not return a null list!
|
|
2526 }
|
|
2527
|
|
2528 ###########################################################################
|
|
2529
|
|
2530 =item $node->copy_tree or $node->copy_tree({...options...})
|
|
2531
|
|
2532 This returns the root of a copy of the tree that $node is a member of.
|
|
2533 If you pass no options, copy_tree pretends you've passed {}.
|
|
2534
|
|
2535 This method is currently implemented as just a call to
|
|
2536 $this->root->copy_at_and_under({...options...}), but magic may be
|
|
2537 added in the future.
|
|
2538
|
|
2539 Options you specify are passed down to calls to $node->copy.
|
|
2540
|
|
2541 =cut
|
|
2542
|
|
2543 sub copy_tree {
|
|
2544 my($this, $o) = @_[0,1];
|
|
2545 my $root = $this->root;
|
|
2546 $o = {} unless ref $o;
|
|
2547
|
|
2548 my $new_root = $root->copy_at_and_under($o);
|
|
2549
|
|
2550 return $new_root;
|
|
2551 }
|
|
2552
|
|
2553 =item $node->copy_at_and_under or $node->copy_at_and_under({...options...})
|
|
2554
|
|
2555 This returns a copy of the subtree consisting of $node and everything
|
|
2556 under it.
|
|
2557
|
|
2558 If you pass no options, copy_at_and_under pretends you've passed {}.
|
|
2559
|
|
2560 This works by recursively building up the new tree from the leaves,
|
|
2561 duplicating nodes using $orig_node->copy($options_ref) and then
|
|
2562 linking them up into a new tree of the same shape.
|
|
2563
|
|
2564 Options you specify are passed down to calls to $node->copy.
|
|
2565
|
|
2566 =cut
|
|
2567
|
|
2568 sub copy_at_and_under {
|
|
2569 my($from, $o) = @_[0,1];
|
|
2570 $o = {} unless ref $o;
|
|
2571 my @daughters = map($_->copy_at_and_under($o), @{$from->{'daughters'}});
|
|
2572 my $to = $from->copy($o);
|
|
2573 $to->set_daughters(@daughters) if @daughters;
|
|
2574 return $to;
|
|
2575 }
|
|
2576
|
|
2577 =item the constructor $node->copy or $node->copy({...options...})
|
|
2578
|
|
2579 Returns a copy of $node, B<minus> its daughter or mother attributes
|
|
2580 (which are set back to default values).
|
|
2581
|
|
2582 If you pass no options, C<copy> pretends you've passed {}.
|
|
2583
|
|
2584 Magic happens with the 'attributes' attribute: if it's a hashref (and
|
|
2585 it usually is), the new node doesn't end up with the same hashref, but
|
|
2586 with ref to a hash with the content duplicated from the original's
|
|
2587 hashref. If 'attributes' is not a hashref, but instead an object that
|
|
2588 belongs to a class that provides a method called "copy", then that
|
|
2589 method is called, and the result saved in the clone's 'attribute'
|
|
2590 attribute. Both of these kinds of magic are disabled if the options
|
|
2591 you pass to C<copy> (maybe via C<copy_tree>, or C<copy_at_and_under>)
|
|
2592 includes (C<no_attribute_copy> => 1).
|
|
2593
|
|
2594 The options hashref you pass to C<copy> (derictly or indirectly) gets
|
|
2595 changed slightly after you call C<copy> -- it gets an entry called
|
|
2596 "from_to" added to it. Chances are you would never know nor care, but
|
|
2597 this is reserved for possible future use. See the source if you are
|
|
2598 wildly curious.
|
|
2599
|
|
2600 Note that if you are using $node->copy (whether directly or via
|
|
2601 $node->copy_tree or $node->copy_at_or_under), and it's not properly
|
|
2602 copying object attributes containing references, you probably
|
|
2603 shouldn't fight it or try to fix it -- simply override copy_tree with:
|
|
2604
|
|
2605 sub copy_tree {
|
|
2606 use Storable qw(dclone);
|
|
2607 my $this = $_[0];
|
|
2608 return dclone($this->root);
|
|
2609 # d for "deep"
|
|
2610 }
|
|
2611
|
|
2612 or
|
|
2613
|
|
2614 sub copy_tree {
|
|
2615 use Data::Dumper;
|
|
2616 my $this = $_[0];
|
|
2617 $Data::Dumper::Purity = 1;
|
|
2618 return eval(Dumper($this->root));
|
|
2619 }
|
|
2620
|
|
2621 Both of these avoid you having to reinvent the wheel.
|
|
2622
|
|
2623 How to override copy_at_or_under with something that uses Storable
|
|
2624 or Data::Dumper is left as an exercise to the reader.
|
|
2625
|
|
2626 Consider that if in a derived class, you add attributes with really
|
|
2627 bizarre contents (like a unique-for-all-time-ID), you may need to
|
|
2628 override C<copy>. Consider:
|
|
2629
|
|
2630 sub copy {
|
|
2631 my($it, @etc) = @_;
|
|
2632 $it->SUPER::copy(@etc);
|
|
2633 $it->{'UID'} = &get_new_UID;
|
|
2634 }
|
|
2635
|
|
2636 ...or the like. See the source of Tree::DAG_Node::copy for
|
|
2637 inspiration.
|
|
2638
|
|
2639 =cut
|
|
2640
|
|
2641 sub copy {
|
|
2642 my($from,$o) = @_[0,1];
|
|
2643 $o = {} unless ref $o;
|
|
2644
|
|
2645 # Straight dupe, and bless into same class:
|
|
2646 my $to = bless { %$from }, ref($from);
|
|
2647
|
|
2648 # Null out linkages.
|
|
2649 $to->_init_mother;
|
|
2650 $to->_init_daughters;
|
|
2651
|
|
2652 # dupe the 'attributes' attribute:
|
|
2653 unless($o->{'no_attribute_copy'}) {
|
|
2654 my $attrib_copy = ref($to->{'attributes'});
|
|
2655 if($attrib_copy) {
|
|
2656 if($attrib_copy eq 'HASH') {
|
|
2657 $to->{'attributes'} = { %{$to->{'attributes'}} };
|
|
2658 # dupe the hashref
|
|
2659 } elsif ($attrib_copy = UNIVERSAL::can($to->{'attributes'}, 'copy') ) {
|
|
2660 # $attrib_copy now points to the copier method
|
|
2661 $to->{'attributes'} = &{$attrib_copy}($from);
|
|
2662 } # otherwise I don't know how to copy it; leave as is
|
|
2663 }
|
|
2664 }
|
|
2665 $o->{'from_to'}->{$from} = $to; # SECRET VOODOO
|
|
2666 # ...autovivifies an anon hashref for 'from_to' if need be
|
|
2667 # This is here in case I later want/need a table corresponding
|
|
2668 # old nodes to new.
|
|
2669 return $to;
|
|
2670 }
|
|
2671
|
|
2672
|
|
2673 ###########################################################################
|
|
2674
|
|
2675 =item $node->delete_tree
|
|
2676
|
|
2677 Destroys the entire tree that $node is a member of (starting at the
|
|
2678 root), by nulling out each node-object's attributes (including, most
|
|
2679 importantly, its linkage attributes -- hopefully this is more than
|
|
2680 sufficient to eliminate all circularity in the data structure), and
|
|
2681 then moving it into the class DEADNODE.
|
|
2682
|
|
2683 Use this when you're finished with the tree in question, and want to
|
|
2684 free up its memory. (If you don't do this, it'll get freed up anyway
|
|
2685 when your program ends.)
|
|
2686
|
|
2687 If you try calling any methods on any of the node objects in the tree
|
|
2688 you've destroyed, you'll get an error like:
|
|
2689
|
|
2690 Can't locate object method "leaves_under"
|
|
2691 via package "DEADNODE".
|
|
2692
|
|
2693 So if you see that, that's what you've done wrong. (Actually, the
|
|
2694 class DEADNODE does provide one method: a no-op method "delete_tree".
|
|
2695 So if you want to delete a tree, but think you may have deleted it
|
|
2696 already, it's safe to call $node->delete_tree on it (again).)
|
|
2697
|
|
2698 The C<delete_tree> method is needed because Perl's garbage collector
|
|
2699 would never (as currently implemented) see that it was time to
|
|
2700 de-allocate the memory the tree uses -- until either you call
|
|
2701 $node->delete_tree, or until the program stops (at "global
|
|
2702 destruction" time, when B<everything> is unallocated).
|
|
2703
|
|
2704 Incidentally, there are better ways to do garbage-collecting on a
|
|
2705 tree, ways which don't require the user to explicitly call a method
|
|
2706 like C<delete_tree> -- they involve dummy classes, as explained at
|
|
2707 C<http://mox.perl.com/misc/circle-destroy.pod>
|
|
2708
|
|
2709 However, introducing a dummy class concept into Tree::DAG_Node would
|
|
2710 be rather a distraction. If you want to do this with your derived
|
|
2711 classes, via a DESTROY in a dummy class (or in a tree-metainformation
|
|
2712 class, maybe), then feel free to.
|
|
2713
|
|
2714 The only case where I can imagine C<delete_tree> failing to totally
|
|
2715 void the tree, is if you use the hashref in the "attributes" attribute
|
|
2716 to store (presumably among other things) references to other nodes'
|
|
2717 "attributes" hashrefs -- which 1) is maybe a bit odd, and 2) is your
|
|
2718 problem, because it's your hash structure that's circular, not the
|
|
2719 tree's. Anyway, consider:
|
|
2720
|
|
2721 # null out all my "attributes" hashes
|
|
2722 $anywhere->root->walk_down({
|
|
2723 'callback' => sub {
|
|
2724 $hr = $_[0]->attributes; %$hr = (); return 1;
|
|
2725 }
|
|
2726 });
|
|
2727 # And then:
|
|
2728 $anywhere->delete_tree;
|
|
2729
|
|
2730 (I suppose C<delete_tree> is a "destructor", or as close as you can
|
|
2731 meaningfully come for a circularity-rich data structure in Perl.)
|
|
2732
|
|
2733 =cut
|
|
2734
|
|
2735 sub delete_tree {
|
|
2736 my $it = $_[0];
|
|
2737 $it->root->walk_down({ # has to be callbackback, not callback
|
|
2738 'callbackback' => sub {
|
|
2739 %{$_[0]} = ();
|
|
2740 bless($_[0], 'DEADNODE'); # cause become dead! cause become dead!
|
|
2741 return 1;
|
|
2742 }
|
|
2743 });
|
|
2744 return;
|
|
2745 # Why DEADNODE? Because of the nice error message:
|
|
2746 # "Can't locate object method "leaves_under" via package "DEADNODE"."
|
|
2747 # Moreover, DEADNODE doesn't provide is_node, so fails my can() tests.
|
|
2748 }
|
|
2749
|
|
2750 sub DEADNODE::delete_tree { return; }
|
|
2751 # in case you kill it AGAIN!!!!! AND AGAIN AND AGAIN!!!!!! OO-HAHAHAHA!
|
|
2752
|
|
2753 ###########################################################################
|
|
2754 # stolen from MIDI.pm
|
|
2755
|
|
2756 sub _dump_quote {
|
|
2757 my @stuff = @_;
|
|
2758 return
|
|
2759 join(", ",
|
|
2760 map
|
|
2761 { # the cleaner-upper function
|
|
2762 if(!length($_)) { # empty string
|
|
2763 "''";
|
|
2764 } elsif( m/^-?\d+(?:\.\d+)?$/s ) { # a number
|
|
2765 $_;
|
|
2766 } elsif( # text with junk in it
|
|
2767 s<([^\x20\x21\x23\x27-\x3F\x41-\x5B\x5D-\x7E])>
|
|
2768 <'\\x'.(unpack("H2",$1))>eg
|
|
2769 ) {
|
|
2770 "\"$_\"";
|
|
2771 } else { # text with no junk in it
|
|
2772 s<'><\\'>g;
|
|
2773 "\'$_\'";
|
|
2774 }
|
|
2775 }
|
|
2776 @stuff
|
|
2777 );
|
|
2778 }
|
|
2779
|
|
2780 ###########################################################################
|
|
2781
|
|
2782 =back
|
|
2783
|
|
2784 =head2 When and How to Destroy
|
|
2785
|
|
2786 It should be clear to you that if you've built a big parse tree or
|
|
2787 something, and then you're finished with it, you should call
|
|
2788 $some_node->delete_tree on it if you want the memory back.
|
|
2789
|
|
2790 But consider this case: you've got this tree:
|
|
2791
|
|
2792 A
|
|
2793 / | \
|
|
2794 B C D
|
|
2795 | | \
|
|
2796 E X Y
|
|
2797
|
|
2798 Let's say you decide you don't want D or any of its descendants in the
|
|
2799 tree, so you call D->unlink_from_mother. This does NOT automagically
|
|
2800 destroy the tree D-X-Y. Instead it merely splits the tree into two:
|
|
2801
|
|
2802 A D
|
|
2803 / \ / \
|
|
2804 B C X Y
|
|
2805 |
|
|
2806 E
|
|
2807
|
|
2808 To destroy D and its little tree, you have to explicitly call
|
|
2809 delete_tree on it.
|
|
2810
|
|
2811 Note, however, that if you call C->unlink_from_mother, and if you don't
|
|
2812 have a link to C anywhere, then it B<does> magically go away. This is
|
|
2813 because nothing links to C -- whereas with the D-X-Y tree, D links to
|
|
2814 X and Y, and X and Y each link back to D. Note that calling
|
|
2815 C->delete_tree is harmless -- after all, a tree of only one node is
|
|
2816 still a tree.
|
|
2817
|
|
2818 So, this is a surefire way of getting rid of all $node's children and
|
|
2819 freeing up the memory associated with them and their descendants:
|
|
2820
|
|
2821 foreach my $it ($node->clear_daughters) { $it->delete_tree }
|
|
2822
|
|
2823 Just be sure not to do this:
|
|
2824
|
|
2825 foreach my $it ($node->daughters) { $it->delete_tree }
|
|
2826 $node->clear_daughters;
|
|
2827
|
|
2828 That's bad; the first call to $_->delete_tree will climb to the root
|
|
2829 of $node's tree, and nuke the whole tree, not just the bits under $node.
|
|
2830 You might as well have just called $node->delete_tree.
|
|
2831 (Moreavor, once $node is dead, you can't call clear_daughters on it,
|
|
2832 so you'll get an error there.)
|
|
2833
|
|
2834 =head1 BUG REPORTS
|
|
2835
|
|
2836 If you find a bug in this library, report it to me as soon as possible,
|
|
2837 at the address listed in the MAINTAINER section, below. Please try to
|
|
2838 be as specific as possible about how you got the bug to occur.
|
|
2839
|
|
2840 =head1 HELP!
|
|
2841
|
|
2842 If you develop a given routine for dealing with trees in some way, and
|
|
2843 use it a lot, then if you think it'd be of use to anyone else, do email
|
|
2844 me about it; it might be helpful to others to include that routine, or
|
|
2845 something based on it, in a later version of this module.
|
|
2846
|
|
2847 It's occurred to me that you might like to (and might yourself develop
|
|
2848 routines to) draw trees in something other than ASCII art. If you do so
|
|
2849 -- say, for PostScript output, or for output interpretable by some
|
|
2850 external plotting program -- I'd be most interested in the results.
|
|
2851
|
|
2852 =head1 RAMBLINGS
|
|
2853
|
|
2854 This module uses "strict", but I never wrote it with -w warnings in
|
|
2855 mind -- so if you use -w, do not be surprised if you see complaints
|
|
2856 from the guts of DAG_Node. As long as there is no way to turn off -w
|
|
2857 for a given module (instead of having to do it in every single
|
|
2858 subroutine with a "local $^W"), I'm not going to change this. However,
|
|
2859 I do, at points, get bursts of ambition, and I try to fix code in
|
|
2860 DAG_Node that generates warnings, I<as I come across them> -- which is
|
|
2861 only occasionally. Feel free to email me any patches for any such
|
|
2862 fixes you come up with, tho.
|
|
2863
|
|
2864 Currently I don't assume (or enforce) anything about the class
|
|
2865 membership of nodes being manipulated, other than by testing whether
|
|
2866 each one provides a method C<is_node>, a la:
|
|
2867
|
|
2868 die "Not a node!!!" unless UNIVERSAL::can($node, "is_node");
|
|
2869
|
|
2870 So, as far as I'm concerned, a given tree's nodes are free to belong to
|
|
2871 different classes, just so long as they provide/inherit C<is_node>, the
|
|
2872 few methods that this class relies on to navigate the tree, and have the
|
|
2873 same internal object structure, or a superset of it. Presumably this
|
|
2874 would be the case for any object belonging to a class derived from
|
|
2875 C<Tree::DAG_Node>, or belonging to C<Tree::DAG_Node> itself.
|
|
2876
|
|
2877 When routines in this class access a node's "mother" attribute, or its
|
|
2878 "daughters" attribute, they (generally) do so directly (via
|
|
2879 $node->{'mother'}, etc.), for sake of efficiency. But classes derived
|
|
2880 from this class should probably do this instead thru a method (via
|
|
2881 $node->mother, etc.), for sake of portability, abstraction, and general
|
|
2882 goodness.
|
|
2883
|
|
2884 However, no routines in this class (aside from, necessarily, C<_init>,
|
|
2885 C<_init_name>, and C<name>) access the "name" attribute directly;
|
|
2886 routines (like the various tree draw/dump methods) get the "name" value
|
|
2887 thru a call to $obj->name(). So if you want the object's name to not be
|
|
2888 a real attribute, but instead have it derived dynamically from some feature
|
|
2889 of the object (say, based on some of its other attributes, or based on
|
|
2890 its address), you can to override the C<name> method, without causing
|
|
2891 problems. (Be sure to consider the case of $obj->name as a write
|
|
2892 method, as it's used in C<lol_to_tree> and C<random_network>.)
|
|
2893
|
|
2894 =head1 SEE ALSO
|
|
2895
|
|
2896 L<HTML::Element>
|
|
2897
|
|
2898 Wirth, Niklaus. 1976. I<Algorithms + Data Structures = Programs>
|
|
2899 Prentice-Hall, Englewood Cliffs, NJ.
|
|
2900
|
|
2901 Knuth, Donald Ervin. 1997. I<Art of Computer Programming, Volume 1,
|
|
2902 Third Edition: Fundamental Algorithms>. Addison-Wesley, Reading, MA.
|
|
2903
|
|
2904 Wirth's classic, currently and lamentably out of print, has a good
|
|
2905 section on trees. I find it clearer than Knuth's (if not quite as
|
|
2906 encyclopedic), probably because Wirth's example code is in a
|
|
2907 block-structured high-level language (basically Pascal), instead
|
|
2908 of in assembler (MIX).
|
|
2909
|
|
2910 Until some kind publisher brings out a new printing of Wirth's book,
|
|
2911 try poking around used bookstores (or C<www.abebooks.com>) for a copy.
|
|
2912 I think it was also republished in the 1980s under the title
|
|
2913 I<Algorithms and Data Structures>, and in a German edition called
|
|
2914 I<Algorithmen und Datenstrukturen>. (That is, I'm sure books by Knuth
|
|
2915 were published under those titles, but I'm I<assuming> that they're just
|
|
2916 later printings/editions of I<Algorithms + Data Structures =
|
|
2917 Programs>.)
|
|
2918
|
|
2919 =head1 MAINTAINER
|
|
2920
|
|
2921 David Hand, C<< <cogent@cpan.org> >>
|
|
2922
|
|
2923 =head1 AUTHOR
|
|
2924
|
|
2925 Sean M. Burke, C<< <sburke@cpan.org> >>
|
|
2926
|
|
2927 =head1 COPYRIGHT, LICENSE, AND DISCLAIMER
|
|
2928
|
|
2929 Copyright 1998-2001, 2004, 2007 by Sean M. Burke and David Hand.
|
|
2930
|
|
2931 This program is free software; you can redistribute it and/or modify it
|
|
2932 under the same terms as Perl itself.
|
|
2933
|
|
2934 This program is distributed in the hope that it will be useful, but
|
|
2935 without any warranty; without even the implied warranty of
|
|
2936 merchantability or fitness for a particular purpose.
|
|
2937
|
|
2938 =cut
|
|
2939
|
|
2940 1;
|
|
2941
|
|
2942 __END__
|