File Coverage

blib/lib/Bio/Phylo/Forest/NodeRole.pm
Criterion Covered Total %
statement 606 824 73.5
branch 189 320 59.0
condition 73 109 66.9
subroutine 70 101 69.3
pod 58 77 75.3
total 996 1431 69.6


line stmt bran cond sub pod time code
1             package Bio::Phylo::Forest::NodeRole;
2 34     34   189 use strict;
  34         66  
  34         1075  
3 34     34   149 use warnings;
  34         64  
  34         654  
4 34     34   704 use Bio::Phylo::Util::MOP;
  34         63  
  34         222  
5 34     34   150 use base qw'Bio::Phylo::Taxa::TaxonLinker Bio::Phylo::Listable';
  34         55  
  34         9515  
6 34     34   2467 use Bio::Phylo::Util::OptionalInterface 'Bio::Tree::NodeI';
  34         62  
  34         186  
7 34     34   203 use Bio::Phylo::Util::CONSTANT qw':objecttypes /looks_like/';
  34         64  
  34         7461  
8 34     34   220 use Bio::Phylo::Util::Exceptions 'throw';
  34         73  
  34         1351  
9 34     34   9252 use Bio::Phylo::Util::Math ':all';
  34         79  
  34         3090  
10 34     34   212 use Bio::Phylo::NeXML::Writable;
  34         61  
  34         326  
11 34     34   154 use Bio::Phylo::Factory;
  34         63  
  34         193  
12 34     34   148 use Scalar::Util 'weaken';
  34         58  
  34         1335  
13 34     34   182 use List::Util qw[sum min max];
  34         64  
  34         1953  
14 34     34   169 no warnings 'recursion';
  34         62  
  34         7520  
15              
16             my $LOADED_WRAPPERS = 0;
17              
18             # store type constant
19             my ( $TYPE_CONSTANT, $CONTAINER_CONSTANT ) = ( _NODE_, _TREE_ );
20              
21             # logger singleton
22             my $logger = __PACKAGE__->get_logger;
23              
24             # factory object
25             my $fac = Bio::Phylo::Factory->new;
26              
27             =head1 NAME
28              
29             Bio::Phylo::Forest::NodeRole - Extra behaviours for a node in a phylogenetic tree
30              
31             =head1 SYNOPSIS
32              
33             # some way to get nodes:
34             use Bio::Phylo::IO;
35             my $string = '((A,B),C);';
36             my $forest = Bio::Phylo::IO->parse(
37             -format => 'newick',
38             -string => $string
39             );
40              
41             # prints 'Bio::Phylo::Forest'
42             print ref $forest;
43              
44             foreach my $tree ( @{ $forest->get_entities } ) {
45              
46             # prints 'Bio::Phylo::Forest::Tree'
47             print ref $tree;
48              
49             foreach my $node ( @{ $tree->get_entities } ) {
50              
51             # prints 'Bio::Phylo::Forest::Node'
52             print ref $node;
53              
54             # node has a parent, i.e. is not root
55             if ( $node->get_parent ) {
56             $node->set_branch_length(1);
57             }
58              
59             # node is root
60             else {
61             $node->set_branch_length(0);
62             }
63             }
64             }
65              
66             =head1 DESCRIPTION
67              
68             This module defines a node object and its methods. The node is fairly
69             syntactically rich in terms of navigation, and additional getters are provided to
70             further ease navigation from node to node. Typical first daughter -> next sister
71             traversal and recursion is possible, but there are also shrinkwrapped methods
72             that return for example all terminal descendants of the focal node, or all
73             internals, etc.
74              
75             Node objects are inserted into tree objects, although technically the tree
76             object is only a container holding all the nodes together. Unless there are
77             orphans all nodes can be reached without recourse to the tree object.
78              
79             =head1 METHODS
80              
81             =over
82              
83             =item new()
84              
85             Node constructor.
86              
87             Type : Constructor
88             Title : new
89             Usage : my $node = Bio::Phylo::Forest::Node->new;
90             Function: Instantiates a Bio::Phylo::Forest::Node object
91             Returns : Bio::Phylo::Forest::Node
92             Args : All optional:
93             -parent => $parent,
94             -taxon => $taxon,
95             -branch_length => 0.423e+2,
96             -first_daughter => $f_daughter,
97             -last_daughter => $l_daughter,
98             -next_sister => $n_sister,
99             -previous_sister => $p_sister,
100             -name => 'node_name',
101             -desc => 'this is a node',
102             -score => 0.98,
103             -generic => {
104             -posterior => 0.98,
105             -bootstrap => 0.80
106             }
107              
108             =cut
109              
110             sub new : Constructor {
111              
112             # could be child class
113 9575     9575 1 16165 my $class = shift;
114              
115             # process bioperl args
116 9575         24143 my %args = looks_like_hash @_;
117 9575 50       19652 if ( exists $args{'-leaf'} ) {
118 0         0 delete $args{'-leaf'};
119             }
120 9575 50       19876 if ( exists $args{'-id'} ) {
121 0         0 my $name = $args{'-id'};
122 0         0 delete $args{'-id'};
123 0         0 $args{'-name'} = $name;
124             }
125 9575 50       17270 if ( exists $args{'-nhx'} ) {
126 0         0 my $hash = $args{'-nhx'};
127 0         0 delete $args{'-nhx'};
128 0         0 $args{'-generic'} = $hash;
129             }
130              
131             # if ( not exists $args{'-tag'} ) {
132             # $args{'-tag'} = __PACKAGE__->_tag;
133             # }
134             # go up inheritance tree, eventually get an ID
135 9575         30513 my $self = $class->SUPER::new(%args);
136 9575 100       19381 if ( not $LOADED_WRAPPERS ) {
137 29 0 0 0 0 71 eval do { local $/; <DATA> };
  29 0   0 0 129  
  29 0   0 0 19877  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0   0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
138 29         85 $LOADED_WRAPPERS++;
139             }
140 9575         26018 return $self;
141 34     34   211 }
  34         64  
  34         193  
142              
143             =item new_from_bioperl()
144              
145             Node constructor from bioperl L<Bio::Tree::NodeI> argument.
146              
147             Type : Constructor
148             Title : new_from_bioperl
149             Usage : my $node =
150             Bio::Phylo::Forest::Node->new_from_bioperl(
151             $bpnode
152             );
153             Function: Instantiates a Bio::Phylo::Forest::Node object
154             from a bioperl node object.
155             Returns : Bio::Phylo::Forest::Node
156             Args : An objects that implements Bio::Tree::NodeI
157             Notes : The following BioPerl properties are copied:
158             BioPerl output: Bio::Phylo output:
159             ------------------------------------------------
160             id get_name
161             branch_length get_branch_length
162             description get_desc
163             bootstrap get_generic('bootstrap')
164            
165             In addition all BioPerl tags and values are copied
166             to set_generic( 'tag' => 'value' );
167              
168             =cut
169              
170             sub new_from_bioperl {
171 0     0 1 0 my ( $class, $bpnode ) = @_;
172 0         0 my $node = $class->new;
173              
174             # copy name
175 0         0 my $name = $bpnode->id;
176 0 0       0 $node->set_name($name) if defined $name;
177              
178             # copy branch length
179 0         0 my $branch_length = $bpnode->branch_length;
180 0 0       0 $node->set_branch_length($branch_length) if defined $branch_length;
181              
182             # copy description
183 0         0 my $desc = $bpnode->description;
184 0 0       0 $node->set_desc($desc) if defined $desc;
185              
186             # copy bootstrap
187 0         0 my $bootstrap = $bpnode->bootstrap;
188 0 0 0     0 $node->set_score($bootstrap)
189             if defined $bootstrap and looks_like_number $bootstrap;
190              
191             # copy other tags
192 0         0 for my $tag ( $bpnode->get_all_tags ) {
193 0         0 my @values = $bpnode->get_tag_values($tag);
194 0         0 $node->set_generic( $tag => \@values );
195             }
196 0         0 return $node;
197             }
198              
199             =item prune_child()
200              
201             Removes argument child node (and its descendants) from invocants children.
202              
203             Type : Mutator
204             Title : prune_child
205             Usage : $parent->prune_child($child);
206             Function: Removes $child (and its descendants) from $parent's children
207             Returns : Modified object.
208             Args : A valid argument is Bio::Phylo::Forest::Node object.
209              
210             =cut
211              
212             sub prune_child {
213 346     346 1 596 my ( $self, $child ) = @_;
214 346         1020 $self->delete($child);
215 346         556 return $self;
216             }
217              
218             =item collapse()
219              
220             Collapse node.
221              
222             Type : Mutator
223             Title : collapse
224             Usage : $node->collapse;
225             Function: Attaches invocant's children to invocant's parent.
226             Returns : Modified object.
227             Args : NONE
228             Comments: If defined, adds invocant's branch
229             length to that of its children. If
230             $node is in a tree, removes itself
231             from that tree.
232              
233             =cut
234              
235             sub collapse {
236 110     110 1 169 my $self = shift;
237              
238             # can't collapse root
239 110 50       245 if ( my $parent = $self->get_parent ) {
240              
241             # can't collapse terminal nodes
242 110 50       180 if ( my @children = @{ $self->get_children } ) {
  110         249  
243              
244             # add node's branch length to that of children
245 110         267 my $length = $self->get_branch_length;
246 110         222 for my $child (@children) {
247 220 50       448 if ( defined $length ) {
248 220   50     497 my $child_length = $child->get_branch_length || 0;
249 220         852 $child->set_branch_length( $length + $child_length );
250             }
251              
252             # attach children to node's parent
253 220         535 $child->set_parent($parent);
254             }
255              
256             # prune node from parent
257 110         270 $parent->prune_child($self);
258              
259             # delete node from tree
260 110 50       298 if ( my $tree = $self->get_tree ) {
261 110         267 $tree->delete($self);
262             }
263             }
264             else {
265 0         0 return $self;
266             }
267             }
268             else {
269 0         0 return $self;
270             }
271             }
272              
273             =item set_first_daughter()
274              
275             Sets argument as invocant's first daughter.
276              
277             Type : Mutator
278             Title : set_first_daughter
279             Usage : $node->set_first_daughter($f_daughter);
280             Function: Assigns a node's leftmost daughter.
281             Returns : Modified object.
282             Args : Undefines the first daughter if no
283             argument given. A valid argument is
284             a Bio::Phylo::Forest::Node object.
285              
286             =cut
287              
288             sub set_first_daughter {
289 336     336 1 464 my ( $self, $fd ) = @_;
290 336         717 $self->set_child( $fd, 0 );
291 335         559 return $self;
292             }
293              
294             =item set_last_daughter()
295              
296             Sets argument as invocant's last daughter.
297              
298             Type : Mutator
299             Title : set_last_daughter
300             Usage : $node->set_last_daughter($l_daughter);
301             Function: Assigns a node's rightmost daughter.
302             Returns : Modified object.
303             Args : A valid argument consists of a
304             Bio::Phylo::Forest::Node object. If
305             no argument is given, the value is
306             set to undefined.
307              
308             =cut
309              
310             sub set_last_daughter {
311 336     336 1 484 my ( $self, $ld ) = @_;
312 336         393 $self->set_child( $ld, scalar @{ $self->get_children } );
  336         537  
313 335         604 return $self;
314             }
315              
316             =item set_previous_sister()
317              
318             Sets argument as invocant's previous sister.
319              
320             Type : Mutator
321             Title : set_previous_sister
322             Usage : $node->set_previous_sister($p_sister);
323             Function: Assigns a node's previous sister (to the left).
324             Returns : Modified object.
325             Args : A valid argument consists of
326             a Bio::Phylo::Forest::Node object.
327             If no argument is given, the value
328             is set to undefined.
329              
330             =cut
331              
332             sub set_previous_sister {
333 237     237 1 318 my ( $self, $ps ) = @_;
334 237 100 100     410 if ( $ps and looks_like_object $ps, $TYPE_CONSTANT ) {
335 6 50       16 if ( my $parent = $self->get_parent ) {
336 6         13 my $children = $parent->get_children;
337 6         9 my $j = 0;
338 6         15 FINDSELF: for ( my $i = $#{$children} ; $i >= 0 ; $i-- ) {
  6         18  
339 13 100       28 if ( $children->[$i] == $self ) {
340 6         8 $j = $i - 1;
341 6         8 last FINDSELF;
342             }
343             }
344 6 50       15 $j = 0 if $j == -1;
345 6         15 $parent->set_child( $ps, $j );
346             }
347             }
348 236         341 return $self;
349             }
350              
351             =item set_next_sister()
352              
353             Sets argument as invocant's next sister.
354              
355             Type : Mutator
356             Title : set_next_sister
357             Usage : $node->set_next_sister($n_sister);
358             Function: Assigns or retrieves a node's
359             next sister (to the right).
360             Returns : Modified object.
361             Args : A valid argument consists of a
362             Bio::Phylo::Forest::Node object.
363             If no argument is given, the
364             value is set to undefined.
365              
366             =cut
367              
368             sub set_next_sister {
369 237     237 1 322 my ( $self, $ns ) = @_;
370 237 100 100     423 if ( $ns and looks_like_object $ns, $TYPE_CONSTANT ) {
371 6 50       18 if ( my $parent = $self->get_parent ) {
372 6         15 my $children = $parent->get_children;
373 6         12 my $last = scalar @{$children};
  6         11  
374 6         6 my $j = $last;
375 6         11 FINDSELF: for my $i ( 0 .. $#{$children} ) {
  6         16  
376 16 100       31 if ( $children->[$i] == $self ) {
377 6         8 $j = $i + 1;
378 6         11 last FINDSELF;
379             }
380             }
381 6         17 $parent->set_child( $ns, $j );
382             }
383             }
384 236         369 return $self;
385             }
386              
387             =item set_node_below()
388              
389             Sets new (unbranched) node below invocant.
390              
391             Type : Mutator
392             Title : set_node_below
393             Usage : my $new_node = $node->set_node_below;
394             Function: Creates a new node below $node
395             Returns : New node if tree was modified, undef otherwise
396             Args : NONE
397              
398             =cut
399              
400             sub set_node_below {
401 0     0 1 0 my $self = shift;
402              
403             # can't set node below root
404 0 0       0 if ( $self->is_root ) {
405 0         0 return;
406             }
407              
408             # instantiate new node from $self's class
409 0         0 my $new_node = ( ref $self )->new(@_);
410              
411             # attach new node to $child's parent
412 0         0 my $parent = $self->get_parent;
413 0         0 $parent->set_child($new_node);
414              
415             # insert new node in tree
416             # if ( my $tree = $self->_get_container ) {
417             # $tree->insert( $new_node );
418             # }
419             # attach $self to new node
420 0         0 $new_node->set_child($self);
421              
422             # done
423 0         0 return $new_node;
424             }
425              
426             =item set_root_below()
427              
428             Reroots below invocant.
429              
430             Type : Mutator
431             Title : set_root_below
432             Usage : $node->set_root_below;
433             Function: Creates a new tree root below $node
434             Returns : New root if tree was modified, undef otherwise
435             Args : NONE
436             Comments: This implementation is a port of @lh3's kn_reroot algorithm
437             found here: http://lh3lh3.users.sourceforge.net/knhx.js
438              
439             =cut
440              
441             sub set_root_below {
442 9     9 1 39 my $node = shift;
443 9   100     31 my $dist = shift || 0;
444 9   50     30 my $force = shift || 0;
445 9         31 my $tree = $node->get_tree;
446 9         37 my $root = $tree->get_root;
447            
448             # do nothing if the focal node already is the root,
449             # or already has the root below it
450 9 100       22 return if $node->get_id == $root->get_id;
451 8 100 66     25 return if $node->get_parent and $node->get_parent->get_id == $root->get_id and not $force;
      66        
452            
453             # p: the central multi-parent node
454             # q: the new parent, previous a child of p
455             # r: old parent
456             # i: previous position of q in p
457             # d: previous distance p->d
458 7         25 my ( $q, $s, $new_root );
459 7         21 my $p = $node->get_parent;
460 7         44 my $i = $p->get_index_of( $node );
461 7         20 my $r = $p->get_parent;
462 7         22 my $d = $p->get_branch_length;
463 7   100     20 my $tmp = $node->get_branch_length || 0;
464            
465             # adjust $dist to a useable value
466 7 50 33     37 $dist = $tmp / 2 if ($dist < 0.0 || $dist > $tmp);
467              
468             # instantiate new root, add $node as first child with new length
469 7         44 $q = $new_root = $fac->create_node( '-name' => 'root' );
470 7         33 $q->set_raw_child( $node => 0 );
471 7         29 $node->set_raw_parent( $q );
472 7         22 $node->set_branch_length( $dist );
473            
474             # add $node's parent as child with new length
475 7         20 $q->set_raw_child( $p => 1 );
476 7         25 $p->set_raw_parent( $q );
477 7         29 $p->set_branch_length( $tmp - $dist );
478            
479             # traverse along previous ancestors, swap them
480             # and update the branch lengths
481 7         19 while ( $r ) {
482 18         45 $s = $r->get_parent; # store r's parent
483 18         53 $p->set_raw_child( $r => $i ); # change r to p's child
484 18         41 $i = $r->get_index_of( $p ); # update $i
485 18         50 $r->set_raw_parent( $p ); # update r's parent
486            
487             # swap r->d and d, i.e. update r->d
488 18         38 $tmp = $r->get_branch_length;
489 18         42 $r->set_branch_length( $d );
490 18         24 $d = $tmp;
491            
492             # update p, q and r
493 18         25 $q = $p; $p = $r; $r = $s;
  18         21  
  18         32  
494             }
495            
496             # now $p is the root node
497 7         11 my @children = @{ $p->get_children };
  7         19  
498 7 50       19 if ( scalar(@children) == 2 ) { # remove p and link the other child of p to q
499 7         15 $r = $children[1 - $i]; # get the other child
500 7         21 $i = $q->get_index_of( $p ); # the position of p in q
501 7   100     16 my $bl = ( $r->get_branch_length || 0 ) + ( $p->get_branch_length || 0 );
      100        
502 7         25 $r->set_branch_length( $bl );
503            
504             # link r to q
505 7         20 $q->set_raw_child( $r => $i );
506 7         23 $r->set_raw_parent( $q );
507             }
508            
509             # remove one child in p
510             else {
511 0         0 my $k = 0;
512 0         0 for my $j ( 0 .. $#children ) {
513 0         0 $children[$k] = $children[$j];
514 0 0       0 $k++ if $j != $i;
515             }
516 0         0 pop @children;
517 0         0 $p->clear();
518 0 0       0 $p->insert( @children ) if @children;
519             }
520 7         22 $tree->insert($new_root);
521 7         19 return $new_root;
522             }
523              
524              
525             =back
526              
527             =head2 ACCESSORS
528              
529             =over
530              
531             =item get_first_daughter()
532              
533             Gets invocant's first daughter.
534              
535             Type : Accessor
536             Title : get_first_daughter
537             Usage : my $f_daughter = $node->get_first_daughter;
538             Function: Retrieves a node's leftmost daughter.
539             Returns : Bio::Phylo::Forest::Node
540             Args : NONE
541              
542             =cut
543              
544             sub get_first_daughter {
545 50971     50971 1 93785 return $_[0]->get_child(0);
546             }
547              
548             =item get_last_daughter()
549              
550             Gets invocant's last daughter.
551              
552             Type : Accessor
553             Title : get_last_daughter
554             Usage : my $l_daughter = $node->get_last_daughter;
555             Function: Retrieves a node's rightmost daughter.
556             Returns : Bio::Phylo::Forest::Node
557             Args : NONE
558              
559             =cut
560              
561             sub get_last_daughter {
562 22     22 1 51 return $_[0]->get_child(-1);
563             }
564              
565             =item get_previous_sister()
566              
567             Gets invocant's previous sister.
568              
569             Type : Accessor
570             Title : get_previous_sister
571             Usage : my $p_sister = $node->get_previous_sister;
572             Function: Retrieves a node's previous sister (to the left).
573             Returns : Bio::Phylo::Forest::Node
574             Args : NONE
575              
576             =cut
577              
578             sub get_previous_sister {
579 230     230 1 306 my $self = shift;
580 230         401 my $id = $self->get_id;
581 230 50       410 if ( my $parent = $self->get_parent ) {
582 230         431 my $children = $parent->get_children;
583 230         316 for ( my $i = $#{$children} ; $i >= 1 ; $i-- ) {
  230         496  
584 280 100       537 if ( $children->[$i]->get_id == $id ) {
585 119         301 return $children->[ $i - 1 ];
586             }
587             }
588             }
589 111         248 return;
590             }
591              
592             =item get_next_sister()
593              
594             Gets invocant's next sister.
595              
596             Type : Accessor
597             Title : get_next_sister
598             Usage : my $n_sister = $node->get_next_sister;
599             Function: Retrieves a node's next sister (to the right).
600             Returns : Bio::Phylo::Forest::Node
601             Args : NONE
602              
603             =cut
604              
605             sub get_next_sister {
606 8131     8131 1 10726 my $self = shift;
607 8131         13804 my $id = $self->get_id;
608 8131 100       16742 if ( my $parent = $self->get_parent ) {
609 7914         14499 my $children = $parent->get_children;
610 7914         11133 for my $i ( 0 .. $#{$children} ) {
  7914         17112  
611 12297 100       22886 if ( $children->[$i]->get_id == $id ) {
612 7914         24283 return $children->[ $i + 1 ];
613             }
614             }
615             }
616 217         487 return;
617             }
618              
619             =item get_ancestors()
620              
621             Gets invocant's ancestors.
622              
623             Type : Query
624             Title : get_ancestors
625             Usage : my @ancestors = @{ $node->get_ancestors };
626             Function: Returns an array reference of ancestral nodes,
627             ordered from young to old (i.e. $ancestors[-1] is root).
628             Returns : Array reference of Bio::Phylo::Forest::Node
629             objects.
630             Args : NONE
631              
632             =cut
633              
634             sub get_ancestors {
635 71     71 1 101 my $self = shift;
636 71         88 my @ancestors;
637 71         87 my $node = $self;
638 71 100       143 if ( $node = $node->get_parent ) {
639 69         127 while ($node) {
640 219         338 push @ancestors, $node;
641 219         393 $node = $node->get_parent;
642             }
643 69         187 return \@ancestors;
644             }
645             else {
646 2         10 return;
647             }
648             }
649              
650             =item get_root()
651              
652             Gets root relative to the invocant, i.e. by walking up the path of ancestors
653              
654             Type : Query
655             Title : get_root
656             Usage : my $root = $node->get_root;
657             Function: Gets root relative to the invocant
658             Returns : Bio::Phylo::Forest::Node
659             Args : NONE
660              
661             =cut
662              
663             sub get_root {
664 3     3 1 8 my $self = shift;
665 3 50       9 if ( my $anc = $self->get_ancestors ) {
666 3         8 return $anc->[-1];
667             }
668             else {
669 0         0 return $self;
670             }
671             }
672              
673             =item get_farthest_node()
674              
675             Gets node farthest away from the invocant. By default this is nodal distance,
676             but when supplied an optional true argument it is based on patristic distance
677             instead.
678              
679             Type : Query
680             Title : get_farthest_node
681             Usage : my $farthest = $node->get_farthest_node;
682             Function: Gets node farthest away from the invocant.
683             Returns : Bio::Phylo::Forest::Node
684             Args : Optional, TRUE value to use patristic instead of nodal distance
685              
686             =cut
687              
688             sub get_farthest_node {
689 3     3 1 776 my ( $self, $patristic ) = @_;
690 3 100       11 my $criterion = $patristic ? 'patristic' : 'nodal';
691 3         24 my $method = sprintf 'calc_%s_distance', $criterion;
692 3         16 my $root = $self->get_root;
693 3 50       14 if ( my $terminals = $root->get_terminals ) {
694 3         7 my ( $furthest_distance, $furthest_node ) = (0);
695 3         6 for my $tip ( @{$terminals} ) {
  3         8  
696 24         73 my $distance = $self->$method($tip);
697 24 100       61 if ( $distance > $furthest_distance ) {
698 13         17 $furthest_distance = $distance;
699 13         26 $furthest_node = $tip;
700             }
701             }
702 3         13 return $furthest_node;
703             }
704             else {
705 0         0 $logger->error("no terminals!");
706             }
707             }
708              
709             =item get_sisters()
710              
711             Gets invocant's sisters.
712              
713             Type : Query
714             Title : get_sisters
715             Usage : my @sisters = @{ $node->get_sisters };
716             Function: Returns an array reference of sisters,
717             ordered from left to right.
718             Returns : Array reference of
719             Bio::Phylo::Forest::Node objects.
720             Args : NONE
721              
722             =cut
723              
724             sub get_sisters {
725 2     2 1 5 my $self = shift;
726 2         3 my $sisters;
727 2 50       7 if ( my $parent = $self->get_parent ) {
728 2         6 $sisters = $parent->get_children;
729             }
730 2         8 return $sisters;
731             }
732              
733             =item get_child()
734              
735             Gets invocant's i'th child.
736              
737             Type : Query
738             Title : get_child
739             Usage : my $child = $node->get_child($i);
740             Function: Returns the child at index $i
741             Returns : A Bio::Phylo::Forest::Node object.
742             Args : An index (integer) $i
743             Comments: if no index is specified, first
744             child is returned
745              
746             =cut
747              
748             sub get_child {
749 50998     50998 1 75864 my ( $self, $i ) = @_;
750 50998 50       82634 $i = 0 if not defined $i;
751 50998         94715 my $children = $self->get_children;
752 50998         178624 return $children->[$i];
753             }
754              
755             =item get_descendants()
756              
757             Gets invocant's descendants.
758              
759             Type : Query
760             Title : get_descendants
761             Usage : my @descendants = @{ $node->get_descendants };
762             Function: Returns an array reference of
763             descendants, recursively ordered
764             breadth first.
765             Returns : Array reference of
766             Bio::Phylo::Forest::Node objects.
767             Args : none.
768              
769             =cut
770              
771             sub get_descendants {
772 595     595 1 1067 my $self = shift;
773 595         1102 my @current = ($self);
774 595         799 my @desc;
775 595         1442 while ( $self->_desc(@current) ) {
776 4110         7417 @current = $self->_desc(@current);
777 4110         12161 push @desc, @current;
778             }
779 595         1485 return \@desc;
780             }
781              
782             =begin comment
783              
784             Type : Internal method
785             Title : _desc
786             Usage : $node->_desc(\@nodes);
787             Function: Performs recursion for Bio::Phylo::Forest::Node::get_descendants()
788             Returns : A Bio::Phylo::Forest::Node object.
789             Args : A Bio::Phylo::Forest::Node object.
790             Comments: This method works in conjunction with
791             Bio::Phylo::Forest::Node::get_descendants() - the latter simply calls
792             the former with a set of nodes, and the former returns their
793             children. Bio::Phylo::Forest::Node::get_descendants() then calls
794             Bio::Phylo::Forest::Node::_desc with this set of children, and so on
795             until all nodes are terminals. A first_daughter ->
796             next_sister postorder traversal in a single method would
797             have been more elegant - though not more efficient, in
798             terms of visited nodes.
799              
800             =end comment
801              
802             =cut
803              
804             sub _desc {
805 8815     8815   11064 my $self = shift;
806 8815         12941 my @current = @_;
807 8815         10390 my @return;
808 8815         11828 foreach (@current) {
809 44170         75179 my $children = $_->get_children;
810 44170 50       74577 if ($children) {
811 44170         49621 push @return, @{$children};
  44170         72757  
812             }
813             }
814 8815         18967 return @return;
815             }
816              
817             =item get_terminals()
818              
819             Gets invocant's terminal descendants.
820              
821             Type : Query
822             Title : get_terminals
823             Usage : my @terminals = @{ $node->get_terminals };
824             Function: Returns an array reference
825             of terminal descendants.
826             Returns : Array reference of
827             Bio::Phylo::Forest::Node objects.
828             Args : NONE
829              
830             =cut
831              
832             sub get_terminals {
833 585     585 1 927 my $self = shift;
834 585 50       1021 if ( $self->is_terminal ) {
835 0         0 return [$self];
836             }
837             else {
838 585         944 return [ grep { $_->is_terminal } @{ $self->get_descendants } ];
  22134         42072  
  585         1354  
839             }
840             }
841              
842             =item get_internals()
843              
844             Gets invocant's internal descendants.
845              
846             Type : Query
847             Title : get_internals
848             Usage : my @internals = @{ $node->get_internals };
849             Function: Returns an array reference
850             of internal descendants.
851             Returns : Array reference of
852             Bio::Phylo::Forest::Node objects.
853             Args : NONE
854              
855             =cut
856              
857             sub get_internals {
858 1     1 1 3 my $self = shift;
859 1         3 my @internals;
860 1         4 my $desc = $self->get_descendants;
861 1 50       2 if ( @{$desc} ) {
  1         4  
862 1         3 foreach ( @{$desc} ) {
  1         3  
863 14 100       24 if ( $_->is_internal ) {
864 6         12 push @internals, $_;
865             }
866             }
867             }
868 1         5 return \@internals;
869             }
870              
871             =item get_mrca()
872              
873             Gets invocant's most recent common ancestor shared with argument.
874              
875             Type : Query
876             Title : get_mrca
877             Usage : my $mrca = $node->get_mrca($other_node);
878             Function: Returns the most recent common ancestor
879             of $node and $other_node.
880             Returns : Bio::Phylo::Forest::Node
881             Args : A Bio::Phylo::Forest::Node
882             object in the same tree.
883              
884             =cut
885              
886             sub get_mrca {
887 40     40 1 80 my ( $self, $other_node ) = @_;
888 40 100       86 if ( $self->get_id == $other_node->get_id ) {
889 7         21 return $self;
890             }
891 33   50     84 my $self_anc = $self->get_ancestors || [$self];
892 33   100     65 my $other_anc = $other_node->get_ancestors || [$other_node];
893 33         55 for my $i ( 0 .. $#{$self_anc} ) {
  33         80  
894 67         140 my $self_anc_id = $self_anc->[$i]->get_id;
895 67         89 for my $j ( 0 .. $#{$other_anc} ) {
  67         131  
896 200 100       361 if ( $self_anc_id == $other_anc->[$j]->get_id ) {
897 32         97 return $self_anc->[$i];
898             }
899             }
900             }
901 1         5 return $self_anc->[-1];
902             }
903              
904             =item get_leftmost_terminal()
905              
906             Gets invocant's leftmost terminal descendant.
907              
908             Type : Query
909             Title : get_leftmost_terminal
910             Usage : my $leftmost_terminal =
911             $node->get_leftmost_terminal;
912             Function: Returns the leftmost
913             terminal descendant of $node.
914             Returns : Bio::Phylo::Forest::Node
915             Args : NONE
916              
917             =cut
918              
919             sub get_leftmost_terminal {
920 4     4 1 9 my $self = shift;
921 4         7 my $daughter = $self;
922 4         12 FIRST_DAUGHTER: while ($daughter) {
923 10 100       23 if ( my $grand_daughter = $daughter->get_first_daughter ) {
924 6         9 $daughter = $grand_daughter;
925 6         14 next FIRST_DAUGHTER;
926             }
927             else {
928 4         7 last FIRST_DAUGHTER;
929             }
930             }
931 4         18 return $daughter;
932             }
933              
934             =item get_rightmost_terminal()
935              
936             Gets invocant's rightmost terminal descendant
937              
938             Type : Query
939             Title : get_rightmost_terminal
940             Usage : my $rightmost_terminal =
941             $node->get_rightmost_terminal;
942             Function: Returns the rightmost
943             terminal descendant of $node.
944             Returns : Bio::Phylo::Forest::Node
945             Args : NONE
946              
947             =cut
948              
949             sub get_rightmost_terminal {
950 4     4 1 11 my $self = shift;
951 4         6 my $daughter = $self;
952 4         12 LAST_DAUGHTER: while ($daughter) {
953 20 100       41 if ( my $grand_daughter = $daughter->get_last_daughter ) {
954 16         23 $daughter = $grand_daughter;
955 16         33 next LAST_DAUGHTER;
956             }
957             else {
958 4         8 last LAST_DAUGHTER;
959             }
960             }
961 4         19 return $daughter;
962             }
963              
964             =item get_subtree()
965              
966             Returns the tree subtended by the invocant
967              
968             Type : Query
969             Title : get_subtree
970             Usage : my $tree = $node->get_subtree;
971             Function: Returns the tree subtended by the invocant
972             Returns : Bio::Phylo::Forest::Tree
973             Args : NONE
974              
975             =cut
976              
977             sub get_subtree {
978 0     0 1 0 my $self = shift;
979 0         0 my $tree = $fac->create_tree;
980             $self->visit_depth_first(
981             '-pre' => sub {
982 0     0   0 my $node = shift;
983 0         0 my $clone = $node->clone;
984 0         0 $node->set_generic( 'clone' => $clone );
985 0         0 $tree->insert($clone);
986 0 0       0 if ( my $parent = $node->get_parent ) {
987 0 0       0 if ( my $pclone = $parent->get_generic('clone') ) {
988 0         0 $clone->set_parent($pclone);
989             }
990             else {
991 0         0 $clone->set_parent;
992             }
993             }
994             },
995             '-post' => sub {
996 0     0   0 my $node = shift;
997 0         0 my $gen = $node->get_generic;
998 0         0 delete $gen->{'clone'};
999             }
1000 0         0 );
1001 0         0 return $tree->_analyze;
1002             }
1003              
1004             =item get_subtrees()
1005              
1006             Returns the subtree rooted at the common ancestor of u and v, and the respective
1007             subtrees that contain u and v
1008              
1009             Type : Query
1010             Title : get_subtrees
1011             Usage : my ( $found_u, $found_v, $subtree, $subtree_u, $subtree_v ) = $root->get_subtrees($u,$v);
1012             Function: Returns the tree subtended by the invocant
1013             Returns : A list containing the following variables:
1014             - boolean: did we find u
1015             - boolean: did we find v
1016             - Bio::Phylo::Forest::Node - the root node of the connecting subtree
1017             - Bio::Phylo::Forest::Node - the root node of the subtree for $u
1018             - Bio::Phylo::Forest::Node - the root node of the subtree for $v
1019             Args : Two nodes, $u and $v
1020             Comments: This is a recursive method that is used by the RANKPROB calculations (see
1021             below). Typically you would invoke this method on the root node of the tree
1022             containing $u and $v, and the method then recurses up the tree. The tree must
1023             be bifurcating, or an exception is thrown.
1024              
1025             =cut
1026              
1027             sub get_subtrees {
1028 1904     1904 1 2579 my ($node,$u,$v) = @_;
1029            
1030             # node is terminal
1031 1904         2099 my @child = @{ $node->get_children };
  1904         2964  
1032 1904 100       3607 if ( not @child ) {
    50          
1033 1008         1880 return undef, undef, undef, undef, undef;
1034             }
1035             elsif ( @child != 2 ) {
1036 0         0 throw 'BadArgs' => "Tree must be bifurcating";
1037             }
1038            
1039             # recurse left and right
1040 896         1509 my ( $found_ul, $found_vl, $subtree_l, $subtree_ul, $subtree_vl ) = $child[0]->get_subtrees( $u, $v );
1041 896         1530 my ( $found_ur, $found_vr, $subtree_r, $subtree_ur, $subtree_vr ) = $child[1]->get_subtrees( $u, $v );
1042            
1043             # both were left descendants of focal node, return result
1044 896 100 100     1759 if ( $found_ul and $found_vl ) {
1045 16         52 return $found_ul, $found_vl, $subtree_l, $subtree_ul, $subtree_vl;
1046             }
1047            
1048             # both were right descendants of focal node, return result
1049 880 100 100     1521 if ( $found_ur and $found_vr ) {
1050 24         81 return $found_ur, $found_vr, $subtree_r, $subtree_ur, $subtree_vr;
1051             }
1052            
1053             # have we found either?
1054 856   100     2558 my $found_u = ( $found_ul or $found_ur or $node->is_equal($u) );
1055 856   100     2443 my $found_v = ( $found_vl or $found_vr or $node->is_equal($v) );
1056            
1057             # initialize and assign subtrees
1058 856         1204 my ( $subtree_u, $subtree_v );
1059 856 100       1295 $subtree_u = $subtree_ul if $found_ul;
1060 856 100       1150 $subtree_v = $subtree_vl if $found_vl;
1061 856 100       1224 $subtree_u = $subtree_ur if $found_ur;
1062 856 100       1163 $subtree_v = $subtree_vr if $found_vr;
1063 856 100 100     2325 if ( $found_u and (not $found_v) ) {
    100 100        
1064 142         184 $subtree_u = $node;
1065             }
1066             elsif ( $found_v and (not $found_u) ) {
1067 142         173 $subtree_v = $node;
1068             }
1069 856 100       1441 $subtree_u = $node if $node->is_equal($u);
1070 856 100       1517 $subtree_v = $node if $node->is_equal($v);
1071            
1072             # return results
1073 856         2152 return $found_u, $found_v, $node, $subtree_u, $subtree_v;
1074             }
1075              
1076             =back
1077              
1078             =head2 TESTS
1079              
1080             =over
1081              
1082             =item is_terminal()
1083              
1084             Tests if invocant is a terminal node.
1085              
1086             Type : Test
1087             Title : is_terminal
1088             Usage : if ( $node->is_terminal ) {
1089             # do something
1090             }
1091             Function: Returns true if node has
1092             no children (i.e. is terminal).
1093             Returns : BOOLEAN
1094             Args : NONE
1095              
1096             =cut
1097              
1098             sub is_terminal {
1099 39618     39618 1 68576 return !shift->get_first_daughter;
1100             }
1101              
1102             =item is_internal()
1103              
1104             Tests if invocant is an internal node.
1105              
1106             Type : Test
1107             Title : is_internal
1108             Usage : if ( $node->is_internal ) {
1109             # do something
1110             }
1111             Function: Returns true if node
1112             has children (i.e. is internal).
1113             Returns : BOOLEAN
1114             Args : NONE
1115              
1116             =cut
1117              
1118             sub is_internal {
1119 147     147 1 354 return !!shift->get_first_daughter;
1120             }
1121              
1122             =item is_preterminal()
1123              
1124             Tests if all direct descendents are terminal
1125              
1126             Type : Test
1127             Title : is_preterminal
1128             Usage : if ( $node->is_preterminal ) {
1129             # do something
1130             }
1131             Function: Returns true if all direct descendents are terminal
1132             Returns : BOOLEAN
1133             Args : NONE
1134              
1135             =cut
1136              
1137             sub is_preterminal {
1138 9     9 1 28 my $self = shift;
1139 9         21 my $children = $self->get_children;
1140 9         35 for my $child ( @{$children} ) {
  9         20  
1141 11 100       20 return 0 if $child->is_internal;
1142             }
1143 8         17 return !!scalar @{$children};
  8         24  
1144             }
1145              
1146             =item is_first()
1147              
1148             Tests if invocant is first sibling in left-to-right order.
1149              
1150             Type : Test
1151             Title : is_first
1152             Usage : if ( $node->is_first ) {
1153             # do something
1154             }
1155             Function: Returns true if first sibling
1156             in left-to-right order.
1157             Returns : BOOLEAN
1158             Args : NONE
1159              
1160             =cut
1161              
1162             sub is_first {
1163 0     0 1 0 return !shift->get_previous_sister;
1164             }
1165              
1166             =item is_last()
1167              
1168             Tests if invocant is last sibling in left-to-right order.
1169              
1170             Type : Test
1171             Title : is_last
1172             Usage : if ( $node->is_last ) {
1173             # do something
1174             }
1175             Function: Returns true if last sibling
1176             in left-to-right order.
1177             Returns : BOOLEAN
1178             Args : NONE
1179              
1180             =cut
1181              
1182             sub is_last {
1183 0     0 1 0 return !shift->get_next_sister;
1184             }
1185              
1186             =item is_root()
1187              
1188             Tests if invocant is a root.
1189              
1190             Type : Test
1191             Title : is_root
1192             Usage : if ( $node->is_root ) {
1193             # do something
1194             }
1195             Function: Returns true if node is a root
1196             Returns : BOOLEAN
1197             Args : NONE
1198              
1199             =cut
1200              
1201             sub is_root {
1202 558     558 1 1005 return !shift->get_parent;
1203             }
1204              
1205             =item is_descendant_of()
1206              
1207             Tests if invocant is descendant of argument.
1208              
1209             Type : Test
1210             Title : is_descendant_of
1211             Usage : if ( $node->is_descendant_of($grandparent) ) {
1212             # do something
1213             }
1214             Function: Returns true if the node is
1215             a descendant of the argument.
1216             Returns : BOOLEAN
1217             Args : putative ancestor - a
1218             Bio::Phylo::Forest::Node object.
1219              
1220             =cut
1221              
1222             sub is_descendant_of {
1223 9612     9612 1 14510 my ( $self, $ancestor ) = @_;
1224 9612         17767 my $ancestor_id = $ancestor->get_id;
1225 9612         23027 while ($self) {
1226 142422 100       234953 if ( my $parent = $self->get_parent ) {
1227 132813         163989 $self = $parent;
1228             }
1229             else {
1230 9609         20643 return;
1231             }
1232 132813 100       224516 if ( $self->get_id == $ancestor_id ) {
1233 3         8 return 1;
1234             }
1235             }
1236             }
1237              
1238             =item is_ancestor_of()
1239              
1240             Tests if invocant is ancestor of argument.
1241              
1242             Type : Test
1243             Title : is_ancestor_of
1244             Usage : if ( $node->is_ancestor_of($grandchild) ) {
1245             # do something
1246             }
1247             Function: Returns true if the node
1248             is an ancestor of the argument.
1249             Returns : BOOLEAN
1250             Args : putative descendant - a
1251             Bio::Phylo::Forest::Node object.
1252              
1253             =cut
1254              
1255             sub is_ancestor_of {
1256 9611     9611 1 15677 my ( $self, $child ) = @_;
1257 9611 100       17431 if ( $child->is_descendant_of($self) ) {
1258 3         18 return 1;
1259             }
1260             else {
1261 9608         21513 return;
1262             }
1263             }
1264              
1265             =item is_sister_of()
1266              
1267             Tests if invocant is sister of argument.
1268              
1269             Type : Test
1270             Title : is_sister_of
1271             Usage : if ( $node->is_sister_of($sister) ) {
1272             # do something
1273             }
1274             Function: Returns true if the node is
1275             a sister of the argument.
1276             Returns : BOOLEAN
1277             Args : putative sister - a
1278             Bio::Phylo::Forest::Node object.
1279              
1280             =cut
1281              
1282             sub is_sister_of {
1283 4     4 1 9 my ( $self, $sister ) = @_;
1284 4         12 my ( $self_parent, $sister_parent ) =
1285             ( $self->get_parent, $sister->get_parent );
1286 4 100 100     27 if ( $self_parent
      100        
1287             && $sister_parent
1288             && $self_parent->get_id == $sister_parent->get_id )
1289             {
1290 1         4 return 1;
1291             }
1292             else {
1293 3         12 return;
1294             }
1295             }
1296              
1297             =item is_child_of()
1298              
1299             Tests if invocant is child of argument.
1300              
1301             Type : Test
1302             Title : is_child_of
1303             Usage : if ( $node->is_child_of($parent) ) {
1304             # do something
1305             }
1306             Function: Returns true if the node is
1307             a child of the argument.
1308             Returns : BOOLEAN
1309             Args : putative parent - a
1310             Bio::Phylo::Forest::Node object.
1311              
1312             =cut
1313              
1314             sub is_child_of {
1315 9917     9917 1 17553 my ( $self, $node ) = @_;
1316 9917 100       21351 if ( my $parent = $self->get_parent ) {
1317 547         1008 return $parent->get_id == $node->get_id;
1318             }
1319 9370         27205 return 0;
1320             }
1321              
1322             =item is_outgroup_of()
1323              
1324             Test if invocant is outgroup of argument nodes.
1325              
1326             Type : Test
1327             Title : is_outgroup_of
1328             Usage : if ( $node->is_outgroup_of(\@ingroup) ) {
1329             # do something
1330             }
1331             Function: Tests whether the set of
1332             \@ingroup is monophyletic
1333             with respect to the $node.
1334             Returns : BOOLEAN
1335             Args : A reference to an array of
1336             Bio::Phylo::Forest::Node objects;
1337             Comments: This method is essentially the same as
1338             &Bio::Phylo::Forest::Tree::is_monophyletic.
1339              
1340             =cut
1341              
1342             sub is_outgroup_of {
1343 2     2 1 5 my ( $outgroup, $nodes ) = @_;
1344 2         5 for my $i ( 0 .. $#{$nodes} ) {
  2         5  
1345 3         5 for my $j ( ( $i + 1 ) .. $#{$nodes} ) {
  3         7  
1346 2         9 my $mrca = $nodes->[$i]->get_mrca( $nodes->[$j] );
1347 2 100       6 return if $mrca->is_ancestor_of($outgroup);
1348             }
1349             }
1350 1         9 return 1;
1351             }
1352              
1353             =item can_contain()
1354              
1355             Test if argument(s) can be a child/children of invocant.
1356              
1357             Type : Test
1358             Title : can_contain
1359             Usage : if ( $parent->can_contain(@children) ) {
1360             # do something
1361             }
1362             Function: Test if arguments can be children of invocant.
1363             Returns : BOOLEAN
1364             Args : An array of Bio::Phylo::Forest::Node objects;
1365             Comments: This method is an override of
1366             Bio::Phylo::Listable::can_contain. Since node
1367             objects hold a list of their children, they
1368             inherit from the listable class and so they
1369             need to be able to validate the contents
1370             of that list before they are inserted.
1371              
1372             =cut
1373              
1374             sub can_contain {
1375 19739     19739 1 27434 my $self = shift;
1376 19739         32407 my $type = $self->_type;
1377 19739         33848 for (@_) {
1378 19759 50       29475 return 0 if $type != $_->_type;
1379             }
1380 19739         43785 return 1;
1381             }
1382              
1383             =back
1384              
1385             =head2 CALCULATIONS
1386              
1387             =over
1388              
1389             =item calc_path_to_root()
1390              
1391             Calculates path to root.
1392              
1393             Type : Calculation
1394             Title : calc_path_to_root
1395             Usage : my $path_to_root =
1396             $node->calc_path_to_root;
1397             Function: Returns the sum of branch
1398             lengths from $node to the root.
1399             Returns : FLOAT
1400             Args : NONE
1401              
1402             =cut
1403              
1404             sub calc_path_to_root {
1405 81     81 1 119 my $self = shift;
1406 81         101 my $node = $self;
1407 81         115 my $path = 0;
1408 81         143 while ($node) {
1409 379         675 my $branch_length = $node->get_branch_length;
1410 379 50       647 if ( defined $branch_length ) {
1411 379         557 $path += $branch_length;
1412             }
1413 379 100       682 if ( my $parent = $node->get_parent ) {
1414 298         564 $node = $parent;
1415             }
1416             else {
1417 81         175 last;
1418             }
1419             }
1420 81         203 return $path;
1421             }
1422              
1423             =item calc_nodes_to_root()
1424              
1425             Calculates number of nodes to root.
1426              
1427             Type : Calculation
1428             Title : calc_nodes_to_root
1429             Usage : my $nodes_to_root =
1430             $node->calc_nodes_to_root;
1431             Function: Returns the number of nodes
1432             from $node to the root.
1433             Returns : INT
1434             Args : NONE
1435              
1436             =cut
1437              
1438             sub calc_nodes_to_root {
1439 2     2 1 4 my $self = shift;
1440 2         3 my ( $nodes, $parent ) = ( 0, $self );
1441 2         6 while ($parent) {
1442 2         3 $nodes++;
1443 2         4 $parent = $parent->get_parent;
1444 2 100       5 if ($parent) {
1445 1 50       5 if ( my $cntr = $parent->calc_nodes_to_root ) {
1446 1         7 $nodes += $cntr;
1447 1         3 last;
1448             }
1449             }
1450             }
1451 2         8 return $nodes;
1452             }
1453              
1454             =item calc_max_nodes_to_tips()
1455              
1456             Calculates maximum number of nodes to tips.
1457              
1458             Type : Calculation
1459             Title : calc_max_nodes_to_tips
1460             Usage : my $max_nodes_to_tips =
1461             $node->calc_max_nodes_to_tips;
1462             Function: Returns the maximum number
1463             of nodes from $node to tips.
1464             Returns : INT
1465             Args : NONE
1466              
1467             =cut
1468              
1469             sub calc_max_nodes_to_tips {
1470 1     1 1 30 my $self = shift;
1471 1         13 my $self_id = $self->get_id;
1472 1         3 my ( $nodes, $maxnodes ) = ( 0, 0 );
1473 1         2 foreach my $child ( @{ $self->get_terminals } ) {
  1         3  
1474 8         11 $nodes = 0;
1475 8   66     19 while ( $child && $child->get_id != $self_id ) {
1476 35         39 $nodes++;
1477 35         53 $child = $child->get_parent;
1478             }
1479 8 100       14 if ( $nodes > $maxnodes ) {
1480 7         10 $maxnodes = $nodes;
1481             }
1482             }
1483 1         5 return $maxnodes;
1484             }
1485              
1486             =item calc_min_nodes_to_tips()
1487              
1488             Calculates minimum number of nodes to tips.
1489              
1490             Type : Calculation
1491             Title : calc_min_nodes_to_tips
1492             Usage : my $min_nodes_to_tips =
1493             $node->calc_min_nodes_to_tips;
1494             Function: Returns the minimum number of
1495             nodes from $node to tips.
1496             Returns : INT
1497             Args : NONE
1498              
1499             =cut
1500              
1501             sub calc_min_nodes_to_tips {
1502 2     2 1 4 my $self = shift;
1503 2         6 my $self_id = $self->get_id;
1504 2         3 my ( $nodes, $minnodes );
1505 2         5 foreach my $child ( @{ $self->get_terminals } ) {
  2         6  
1506 34         39 $nodes = 0;
1507 34   66     72 while ( $child && $child->get_id != $self_id ) {
1508 166         210 $nodes++;
1509 166         256 $child = $child->get_parent;
1510             }
1511 34 100 66     88 if ( !$minnodes || $nodes < $minnodes ) {
1512 2         4 $minnodes = $nodes;
1513             }
1514             }
1515 2         10 return $minnodes;
1516             }
1517              
1518             =item calc_max_path_to_tips()
1519              
1520             Calculates longest path to tips.
1521              
1522             Type : Calculation
1523             Title : calc_max_path_to_tips
1524             Usage : my $max_path_to_tips =
1525             $node->calc_max_path_to_tips;
1526             Function: Returns the path length from
1527             $node to the tallest tip.
1528             Returns : FLOAT
1529             Args : NONE
1530              
1531             =cut
1532              
1533             sub calc_max_path_to_tips {
1534 2     2 1 3 my $self = shift;
1535 2         7 my $id = $self->get_id;
1536 2         6 my ( $length, $maxlength ) = ( 0, 0 );
1537 2         4 foreach my $child ( @{ $self->get_terminals } ) {
  2         5  
1538 16         19 $length = 0;
1539 16   66     36 while ( $child && $child->get_id != $id ) {
1540 68         111 my $branch_length = $child->get_branch_length;
1541 68 100       95 if ( defined $branch_length ) {
1542 35         44 $length += $branch_length;
1543             }
1544 68         110 $child = $child->get_parent;
1545             }
1546 16 100       31 if ( $length > $maxlength ) {
1547 7         10 $maxlength = $length;
1548             }
1549             }
1550 2         14 return $maxlength;
1551             }
1552              
1553             =item calc_min_path_to_tips()
1554              
1555             Calculates shortest path to tips.
1556              
1557             Type : Calculation
1558             Title : calc_min_path_to_tips
1559             Usage : my $min_path_to_tips =
1560             $node->calc_min_path_to_tips;
1561             Function: Returns the path length from
1562             $node to the shortest tip.
1563             Returns : FLOAT
1564             Args : NONE
1565              
1566             =cut
1567              
1568             sub calc_min_path_to_tips {
1569 2     2 1 5 my $self = shift;
1570 2         5 my $id = $self->get_id;
1571 2         4 my ( $length, $minlength );
1572 2         3 foreach my $child ( @{ $self->get_terminals } ) {
  2         5  
1573 16         18 $length = 0;
1574 16   66     37 while ( $child && $child->get_id != $id ) {
1575 68         118 my $branch_length = $child->get_branch_length;
1576 68 100       106 if ( defined $branch_length ) {
1577 35         48 $length += $branch_length;
1578             }
1579 68         102 $child = $child->get_parent;
1580             }
1581 16 100       28 if ( !$minlength ) {
1582 9         11 $minlength = $length;
1583             }
1584 16 50       28 if ( $length < $minlength ) {
1585 0         0 $minlength = $length;
1586             }
1587             }
1588 2         9 return $minlength;
1589             }
1590              
1591             =item calc_patristic_distance()
1592              
1593             Calculates patristic distance between invocant and argument.
1594              
1595             Type : Calculation
1596             Title : calc_patristic_distance
1597             Usage : my $patristic_distance =
1598             $node->calc_patristic_distance($other_node);
1599             Function: Returns the patristic distance
1600             between $node and $other_node.
1601             Returns : FLOAT
1602             Args : Bio::Phylo::Forest::Node
1603              
1604             =cut
1605              
1606             sub calc_patristic_distance {
1607 19     19 1 32 my ( $self, $other_node ) = @_;
1608 19         29 my $patristic_distance = 0;
1609 19         40 my $mrca = $self->get_mrca($other_node);
1610 19         43 my $mrca_id = $mrca->get_id;
1611 19         39 while ( $self->get_id != $mrca_id ) {
1612 38         74 my $branch_length = $self->get_branch_length;
1613 38 100       66 if ( defined $branch_length ) {
1614 37         58 $patristic_distance += $branch_length;
1615             }
1616 38         62 $self = $self->get_parent;
1617             }
1618 19   66     59 while ( $other_node and $other_node->get_id != $mrca_id ) {
1619 48         87 my $branch_length = $other_node->get_branch_length;
1620 48 100       76 if ( defined $branch_length ) {
1621 43         60 $patristic_distance += $branch_length;
1622             }
1623 48         85 $other_node = $other_node->get_parent;
1624             }
1625 19         37 return $patristic_distance;
1626             }
1627              
1628             =item calc_nodal_distance()
1629              
1630             Calculates node distance between invocant and argument.
1631              
1632             Type : Calculation
1633             Title : calc_nodal_distance
1634             Usage : my $nodal_distance =
1635             $node->calc_nodal_distance($other_node);
1636             Function: Returns the number of nodes
1637             between $node and $other_node.
1638             Returns : INT
1639             Args : Bio::Phylo::Forest::Node
1640              
1641             =cut
1642              
1643             sub calc_nodal_distance {
1644 9     9 1 16 my ( $self, $other_node ) = @_;
1645 9         12 my $nodal_distance = 0;
1646 9         21 my $mrca = $self->get_mrca($other_node);
1647 9         24 my $mrca_id = $mrca->get_id;
1648 9   66     39 while ( $self and $self->get_id != $mrca_id ) {
1649 18         31 $nodal_distance++;
1650 18         66 $self = $self->get_parent;
1651             }
1652 9   66     30 while ( $other_node and $other_node->get_id != $mrca_id ) {
1653 21         29 $nodal_distance++;
1654 21         45 $other_node = $other_node->get_parent;
1655             }
1656 9         19 return $nodal_distance;
1657             }
1658              
1659             =item calc_terminals()
1660              
1661             Calculates number of terminals subtended by the invocant
1662              
1663             Type : Calculation
1664             Title : calc_terminals
1665             Usage : my $ntips = $node->calc_terminals;
1666             Function: Returns the number of terminals subtended by the invocant
1667             Returns : INT
1668             Args : None
1669              
1670             =cut
1671            
1672             sub calc_terminals {
1673 236     236 1 307 my $self = shift;
1674 236         344 my $tips = 0;
1675 236 100   1172   921 $self->visit_level_order( sub { $tips++ if shift->is_terminal } );
  1172         1851  
1676 236         788 return $tips;
1677             }
1678              
1679             =item calc_rankprob_tipcounts()
1680              
1681             Recurses from the root to the tips, returns an array reference at every step whose
1682             first element is a boolean set to true once the query node has been seen. The second
1683             element is an array that contains the number of subtended leaves - 1 for the query
1684             node and for all sisters of the nodes on the path from the query to the root. This
1685             method is used by the RANKPROB calculations (see below)
1686              
1687             Type : Calculation
1688             Title : calc_rankprob_tipcounts
1689             Usage : my @rp = @{ $root->calc_rankprob_tipcounts($node) };
1690             Function: Returns tip counts for RANKPROB
1691             Returns : ARRAY
1692             Args : NONE
1693              
1694             =cut
1695              
1696             sub calc_rankprob_tipcounts {
1697 358     358 1 497 my ($node,$u) = @_;
1698            
1699             # focal node (subtree) is empty, i.e. a leaf
1700 358         404 my @child = @{ $node->get_children };
  358         583  
1701 358 100       735 return [undef,undef] if not @child;
1702 250 100       495 return [ 1, [ $node->calc_terminals - 1 ] ] if $node->is_equal($u);
1703            
1704             # recurse left
1705 166         317 my $x = $child[0]->calc_rankprob_tipcounts( $u );
1706 166 100       303 if ( $x->[0] ) {
1707 58         69 my $n;
1708            
1709             # focal node has no sibling
1710 58 50       105 if ( not $child[1] ) {
1711 0         0 $n = 0;
1712             }
1713             else {
1714 58         111 $n = $child[1]->calc_terminals - 1;
1715             }
1716 58         87 return [ 1, [ @{ $x->[1] }, $n ] ];
  58         168  
1717             }
1718              
1719             # recurse right
1720 108         173 my $y = $child[1]->calc_rankprob_tipcounts( $u );
1721 108 100       209 if ( $y->[0] ) {
1722 34         57 my $n;
1723            
1724             # focal node has no sibling
1725 34 50       76 if ( not $child[0] ) {
1726 0         0 $n = 0;
1727             }
1728             else {
1729 34         64 $n = $child[0]->calc_terminals - 1;
1730             }
1731 34         58 return [ 1, [ @{ $y->[1] }, $n ] ];
  34         115  
1732             }
1733            
1734             # $u is neither left or right from here
1735             else {
1736 74         168 return [undef,undef];
1737             }
1738             }
1739              
1740             =item calc_rankprob()
1741              
1742             Calculates the probabilities for all rank orderings that the invocant node can
1743             occupy among all possible labeled histories. Uses Stadler's RANKPROB algorithm as
1744             described in:
1745              
1746             B<Gernhard, T.> et al., 2006. Estimating the relative order of speciation
1747             or coalescence events on a given phylogeny. I<Evolutionary Bioinformatics Online>.
1748             B<2>:285. L<http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2674681/>.
1749              
1750             Type : Calculation
1751             Title : calc_rankprob
1752             Usage : my @rp = @{ $root->calc_rankprob($node) };
1753             Function: Returns the rank probabilities of the invocant node
1754             Returns : ARRAY, indices are ranks, values are probabilities
1755             Args : NONE
1756              
1757             =cut
1758              
1759             sub calc_rankprob {
1760 76     76 1 131 my ($t,$u) = @_;
1761 76         149 my $x = $t->calc_rankprob_tipcounts($u);
1762 76         134 $x = $x->[1];
1763 76         111 my $lhsm = $x->[0];
1764 76         109 my $k = scalar(@$x);
1765 76         98 my $start = 1;
1766 76         101 my $end = 1;
1767 76         129 my $rp = [0,1];
1768 76         103 my $step = 1;
1769 76         157 while ( $step < $k ) {
1770 68         89 my $rhsm = $x->[$step];
1771 68         102 my $newstart = $start+1;
1772 68         92 my $newend = $end + $rhsm + 1;
1773 68         99 my $rp2 = [];
1774 68         134 for my $i ( 0 .. $newend ) {
1775 336         469 push @$rp2, 0;
1776             }
1777 68         105 for my $i ( $newstart .. $newend ) {
1778 180         362 my $q = max( 0, $i - 1 - $end );
1779 180         349 for my $j ( $q .. min( $rhsm, $i - 2 ) ) {
1780 266         604 my $a = $rp->[$i-$j-1] * nchoose($lhsm + $rhsm - ($i-1),$rhsm-$j) * nchoose($i-2,$j);
1781 266         466 $rp2->[$i]+=$a;
1782             }
1783             }
1784 68         117 $rp = $rp2;
1785 68         101 $start = $newstart;
1786 68         76 $end = $newend;
1787 68         76 $lhsm = $lhsm+$rhsm+1;
1788 68         135 $step += 1;
1789             }
1790 76         103 my $tot = sum( @{ $rp } );
  76         194  
1791 76         111 for my $i ( 0..$#{ $rp } ) {
  76         160  
1792 320         467 $rp->[$i] = $rp->[$i] / $tot;
1793             }
1794 76         159 return $rp;
1795             }
1796              
1797             =item calc_expected_rank()
1798              
1799             Calculates the expected rank and variance that the invocant node occupies among all
1800             possible labeled histories. Uses Stadler's RANKPROB algorithm as described in:
1801              
1802             B<Gernhard, T.> et al., 2006. Estimating the relative order of speciation
1803             or coalescence events on a given phylogeny. I<Evolutionary Bioinformatics Online>.
1804             B<2>:285. L<http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2674681/>.
1805              
1806             Type : Calculation
1807             Title : calc_expected_rank
1808             Usage : my ( $rank, $variance ) = $root->calc_expected_rank($node);
1809             Function: Calculates expected rank and variance
1810             Returns : Two numbers: rank and variance
1811             Args : NONE
1812              
1813             =cut
1814              
1815             sub calc_expected_rank {
1816 8     8 1 17 my ( $t, $u ) = @_;
1817 8         15 my $rp = $t->calc_rankprob( $u );
1818 8         14 my $mu = 0;
1819 8         14 my $sigma = 0;
1820 8         15 for my $i ( 0 .. $#{ $rp } ) {
  8         16  
1821 59         79 $mu += $i * $rp->[$i];
1822 59         79 $sigma += $i * $i * $rp->[$i];
1823             }
1824 8         32 return $mu, $sigma - $mu * $mu;
1825             }
1826              
1827             =item calc_rankprob_compare()
1828              
1829             Calculates the probability that the argument node is below the invocant node over all
1830             possible labeled histories. Uses Stadler's COMPARE algorithm as described in:
1831              
1832             B<Gernhard, T.> et al., 2006. Estimating the relative order of speciation
1833             or coalescence events on a given phylogeny. I<Evolutionary Bioinformatics Online>.
1834             B<2>:285. L<http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2674681/>.
1835              
1836             Type : Calculation
1837             Title : calc_rankprob_compare
1838             Usage : my $prob = $root->calc_rankprob_compare($u,$v);
1839             Function: Compares rankings of nodes
1840             Returns : A number (probability)
1841             Args : Bio::Phylo::Forest::Node
1842              
1843             =cut
1844              
1845             sub calc_rankprob_compare {
1846 56     56 1 112 my ($t,$u,$v) = @_;
1847 56         130 my ($found_u,$found_v,$root,$root_u,$root_v) = $t->get_subtrees($u,$v);
1848            
1849             # both vertices need to occur in the same tree, of course
1850 56 50 33     189 if ( not ($found_u and $found_v) ) {
1851 0         0 print "This tree does not have those vertices!";
1852 0         0 return 0;
1853             }
1854            
1855             # If either one is the root node of the
1856             # subtree that connects them then their
1857             # relative rankings are certain.
1858 56 100       115 return 1.0 if $root->is_equal($u);
1859 43 100       89 return 0.0 if $root->is_equal($v);
1860              
1861             # calculate rank probabilities in
1862             # respective subtrees
1863 30         80 my $x = $root_u->calc_rankprob($u);
1864 30         66 my $y = $root_v->calc_rankprob($v);
1865 30         65 my $usize = $root_u->calc_terminals - 1;
1866 30         63 my $vsize = $root_v->calc_terminals - 1;
1867            
1868 30         92 for my $i ( scalar(@$x) .. $usize + 1 ) {
1869 51         93 push @$x, 0;
1870             }
1871 30         53 my $xcumulative = [0];
1872 30         42 for my $i ( 1 .. $#{ $x } ) {
  30         53  
1873 122         238 push @$xcumulative, $xcumulative->[$i-1] + $x->[$i];
1874             }
1875 30         63 my $rp = [0];
1876 30         49 for my $i ( 1 .. $#{ $y } ) {
  30         56  
1877 71         110 push @$rp, 0;
1878 71         132 for my $j ( 1 .. $usize) {
1879 229         425 my $a = $y->[$i] * nchoose($i-1+$j,$j) * nchoose($vsize-$i+$usize-$j, $usize-$j) * $xcumulative->[$j];
1880 229         394 $rp->[$i] += $a;
1881             }
1882             }
1883 30         70 my $tot = nchoose($usize+$vsize,$vsize);
1884 30         169 return sum(@$rp)/$tot;
1885             }
1886              
1887             =back
1888              
1889             =head2 VISITOR METHODS
1890              
1891             The methods below are similar in spirit to those by the same name in L<Bio::Phylo::Forest::Tree>,
1892             except those in the tree class operate from the tree root, and those in this node class operate
1893             on an invocant node, and so these process a subtree.
1894              
1895             =over
1896              
1897             =item visit_depth_first()
1898              
1899             Visits nodes depth first
1900              
1901             Type : Visitor method
1902             Title : visit_depth_first
1903             Usage : $tree->visit_depth_first( -pre => sub{ ... }, -post => sub { ... } );
1904             Function: Visits nodes in a depth first traversal, executes subs
1905             Returns : $tree
1906             Args : Optional:
1907             # first event handler, is executed when node is reached in recursion
1908             -pre => sub { print "pre: ", shift->get_name, "\n" },
1909            
1910             # is executed if node has a daughter, but before that daughter is processed
1911             -pre_daughter => sub { print "pre_daughter: ", shift->get_name, "\n" },
1912            
1913             # is executed if node has a daughter, after daughter has been processed
1914             -post_daughter => sub { print "post_daughter: ", shift->get_name, "\n" },
1915            
1916             # is executed if node has no daughter
1917             -no_daughter => sub { print "no_daughter: ", shift->get_name, "\n" },
1918              
1919             # is executed whether or not node has sisters, if it does have sisters
1920             # they're processed first
1921             -in => sub { print "in: ", shift->get_name, "\n" },
1922              
1923             # is executed if node has a sister, before sister is processed
1924             -pre_sister => sub { print "pre_sister: ", shift->get_name, "\n" },
1925            
1926             # is executed if node has a sister, after sister is processed
1927             -post_sister => sub { print "post_sister: ", shift->get_name, "\n" },
1928            
1929             # is executed if node has no sister
1930             -no_sister => sub { print "no_sister: ", shift->get_name, "\n" },
1931            
1932             # is executed last
1933             -post => sub { print "post: ", shift->get_name, "\n" },
1934            
1935             # specifies traversal order, default 'ltr' means first_daugher -> next_sister
1936             # traversal, alternate value 'rtl' means last_daughter -> previous_sister traversal
1937             -order => 'ltr', # ltr = left-to-right, 'rtl' = right-to-left
1938            
1939             # passes sister node as second argument to pre_sister and post_sister subs,
1940             # and daughter node as second argument to pre_daughter and post_daughter subs
1941             -with_relatives => 1 # or any other true value
1942             Comments:
1943              
1944             =cut
1945              
1946             #$tree->visit_depth_first(
1947             # '-pre' => sub { print "pre: ", shift->get_name, "\n" },
1948             # '-pre_daughter' => sub { print "pre_daughter: ", shift->get_name, "\n" },
1949             # '-post_daughter' => sub { print "post_daughter: ", shift->get_name, "\n" },
1950             # '-in' => sub { print "in: ", shift->get_name, "\n" },
1951             # '-pre_sister' => sub { print "pre_sister: ", shift->get_name, "\n" },
1952             # '-post_sister' => sub { print "post_sister: ", shift->get_name, "\n" },
1953             # '-post' => sub { print "post: ", shift->get_name, "\n" },
1954             # '-order' => 'ltr',
1955             #);
1956             sub visit_depth_first {
1957 141     141 1 289 my $self = shift;
1958 141         362 my %args = looks_like_hash @_;
1959              
1960             # my @keys = qw(pre pre_daughter post_daughter in pre_sister post_sister post order with_relatives);
1961             # my %permitted_keys = map { "-${_}" => 1 } @keys;
1962             # for my $key ( keys %args ) {
1963             # if ( not exists $permitted_keys{$key} ) {
1964             # throw 'BadArgs' => "Can't use argument $key";
1965             # }
1966             # if ( $key ne "-with_relatives" or $key ne "-order" ) {
1967             # if ( not looks_like_instance $args{$key}, 'CODE' ) {
1968             # throw 'BadArgs' => "Argument $key must be a code reference";
1969             # }
1970             # }
1971             # }
1972 141 50 33     536 if ( $args{'-order'} and $args{'-order'} =~ /^rtl$/i ) {
1973 0         0 $args{'-sister_method'} = 'get_previous_sister';
1974 0         0 $args{'-daughter_method'} = 'get_last_daughter';
1975             }
1976             else {
1977 141         441 $args{'-sister_method'} = 'get_next_sister';
1978 141         303 $args{'-daughter_method'} = 'get_first_daughter';
1979             }
1980 141         688 $self->_visit_depth_first(%args);
1981 140         453 return $self;
1982             }
1983              
1984             sub _visit_depth_first {
1985 4466     4466   10972 my ( $node, %args ) = @_;
1986             my ( $daughter_method, $sister_method ) =
1987 4466         8738 @args{qw(-daughter_method -sister_method)};
1988 4466 100       8943 $args{'-pre'}->($node) if $args{'-pre'};
1989 4466 100       10592 if ( my $daughter = $node->$daughter_method ) {
1990 2112         3455 my @args = ($node);
1991 2112 50       4349 push @args, $daughter if $args{'-with_relatives'};
1992 2112 50       4006 $args{'-pre_daughter'}->(@args) if $args{'-pre_daughter'};
1993 2112         6563 $daughter->_visit_depth_first(%args);
1994 2107 100       5833 $args{'-post_daughter'}->(@args) if $args{'-post_daughter'};
1995             }
1996             else {
1997 2354 100       4794 $args{'-no_daughter'}->($node) if $args{'-no_daughter'};
1998             }
1999 4461 50       7939 $args{'-in'}->($node) if $args{'-in'};
2000 4461 100       9131 if ( my $sister = $node->$sister_method ) {
2001 2213         3683 my @args = ($node);
2002 2213 50       3908 push @args, $sister if $args{'-with_relatives'};
2003 2213 50       3756 $args{'-pre_sister'}->(@args) if $args{'-pre_sister'};
2004 2213         7160 $sister->_visit_depth_first(%args);
2005 2209 50       6045 $args{'-post_sister'}->(@args) if $args{'-post_sister'};
2006             }
2007             else {
2008 2248 50       4777 $args{'-no_sister'}->($node) if $args{'-no_sister'};
2009             }
2010 4457 100       12177 $args{'-post'}->($node) if $args{'-post'};
2011             }
2012              
2013             =item visit_breadth_first()
2014              
2015             Visits nodes breadth first
2016              
2017             Type : Visitor method
2018             Title : visit_breadth_first
2019             Usage : $tree->visit_breadth_first( -pre => sub{ ... }, -post => sub { ... } );
2020             Function: Visits nodes in a breadth first traversal, executes handlers
2021             Returns : $tree
2022             Args : Optional handlers in the order in which they would be executed on an internal node:
2023            
2024             # first event handler, is executed when node is reached in recursion
2025             -pre => sub { print "pre: ", shift->get_name, "\n" },
2026            
2027             # is executed if node has a sister, before sister is processed
2028             -pre_sister => sub { print "pre_sister: ", shift->get_name, "\n" },
2029            
2030             # is executed if node has a sister, after sister is processed
2031             -post_sister => sub { print "post_sister: ", shift->get_name, "\n" },
2032            
2033             # is executed if node has no sister
2034             -no_sister => sub { print "no_sister: ", shift->get_name, "\n" },
2035            
2036             # is executed whether or not node has sisters, if it does have sisters
2037             # they're processed first
2038             -in => sub { print "in: ", shift->get_name, "\n" },
2039            
2040             # is executed if node has a daughter, but before that daughter is processed
2041             -pre_daughter => sub { print "pre_daughter: ", shift->get_name, "\n" },
2042            
2043             # is executed if node has a daughter, after daughter has been processed
2044             -post_daughter => sub { print "post_daughter: ", shift->get_name, "\n" },
2045            
2046             # is executed if node has no daughter
2047             -no_daughter => sub { print "no_daughter: ", shift->get_name, "\n" },
2048            
2049             # is executed last
2050             -post => sub { print "post: ", shift->get_name, "\n" },
2051            
2052             # specifies traversal order, default 'ltr' means first_daugher -> next_sister
2053             # traversal, alternate value 'rtl' means last_daughter -> previous_sister traversal
2054             -order => 'ltr', # ltr = left-to-right, 'rtl' = right-to-left
2055             Comments:
2056              
2057             =cut
2058              
2059             sub visit_breadth_first {
2060 0     0 1 0 my $self = shift;
2061 0         0 my %args = looks_like_hash @_;
2062 0 0 0     0 if ( $args{'-order'} and $args{'-order'} =~ /rtl/i ) {
2063 0         0 $args{'-sister_method'} = 'get_previous_sister';
2064 0         0 $args{'-daughter_method'} = 'get_last_daughter';
2065             }
2066             else {
2067 0         0 $args{'-sister_method'} = 'get_next_sister';
2068 0         0 $args{'-daughter_method'} = 'get_first_daughter';
2069             }
2070 0         0 $self->_visit_breadth_first(%args);
2071 0         0 return $self;
2072             }
2073              
2074             sub _visit_breadth_first {
2075 0     0   0 my ( $node, %args ) = @_;
2076             my ( $daughter_method, $sister_method ) =
2077 0         0 @args{qw(-daughter_method -sister_method)};
2078 0 0       0 $args{'-pre'}->($node) if $args{'-pre'};
2079 0 0       0 if ( my $sister = $node->$sister_method ) {
2080 0 0       0 $args{'-pre_sister'}->($node) if $args{'-pre_sister'};
2081 0         0 $sister->_visit_breadth_first(%args);
2082 0 0       0 $args{'-post_sister'}->($node) if $args{'-post_sister'};
2083             }
2084             else {
2085 0 0       0 $args{'-no_sister'}->($node) if $args{'-no_sister'};
2086             }
2087 0 0       0 $args{'-in'}->($node) if $args{'-in'};
2088 0 0       0 if ( my $daughter = $node->$daughter_method ) {
2089 0 0       0 $args{'-pre_daughter'}->($node) if $args{'-pre_daughter'};
2090 0         0 $daughter->_visit_breadth_first(%args);
2091 0 0       0 $args{'-post_daughter'}->($node) if $args{'-post_daughter'};
2092             }
2093             else {
2094 0 0       0 $args{'-no_daughter'}->($node) if $args{'-no_daughter'};
2095             }
2096 0 0       0 $args{'-post'}->($node) if $args{'-post'};
2097             }
2098              
2099             =item visit_level_order()
2100              
2101             Visits nodes in a level order traversal.
2102              
2103             Type : Visitor method
2104             Title : visit_level_order
2105             Usage : $tree->visit_level_order( sub{...} );
2106             Function: Visits nodes in a level order traversal, executes sub
2107             Returns : $tree
2108             Args : A subroutine reference that operates on visited nodes.
2109             Comments:
2110              
2111             =cut
2112              
2113             sub visit_level_order {
2114 360     360 1 697 my ( $self, $sub ) = @_;
2115 360 50       969 if ( looks_like_instance $sub, 'CODE' ) {
2116 360         649 my @queue = ($self);
2117 360         1055 while (@queue) {
2118 5672         7934 my $node = shift @queue;
2119 5672         11897 $sub->($node);
2120 5672 50       11450 if ( my $children = $node->get_children ) {
2121 5672         7554 push @queue, @{$children};
  5672         12803  
2122             }
2123             }
2124             }
2125             else {
2126 0         0 throw 'BadArgs' => "'$sub' not a CODE reference";
2127             }
2128 360         728 return $self;
2129             }
2130              
2131             =back
2132              
2133             =head2 SERIALIZERS
2134              
2135             =over
2136              
2137             =item to_xml()
2138              
2139             Serializes invocant to xml.
2140              
2141             Type : Serializer
2142             Title : to_xml
2143             Usage : my $xml = $obj->to_xml;
2144             Function: Turns the invocant object (and its descendants )into an XML string.
2145             Returns : SCALAR
2146             Args : NONE
2147              
2148             =cut
2149              
2150             sub to_xml {
2151 0     0 1 0 my $self = shift;
2152 0         0 my @nodes = ( $self, @{ $self->get_descendants } );
  0         0  
2153 0         0 my $xml = '';
2154              
2155             # first write out the node elements
2156 0         0 for my $node (@nodes) {
2157 0 0       0 if ( my $taxon = $node->get_taxon ) {
2158 0         0 $node->set_attributes( 'otu' => $taxon->get_xml_id );
2159             }
2160 0 0       0 if ( $node->is_root ) {
2161 0         0 $node->set_attributes( 'root' => 'true' );
2162             }
2163 0         0 $xml .= "\n" . $node->get_xml_tag(1);
2164             }
2165              
2166             # then the rootedge?
2167 0 0       0 if ( my $length = shift(@nodes)->get_branch_length ) {
2168 0         0 my $edge = $fac->create_xmlwritable(
2169             '-tag' => 'rootedge',
2170             '-attributes' => {
2171             'target' => $self->get_xml_id,
2172             'id' => "edge" . $self->get_id,
2173             'length' => $length
2174             }
2175             );
2176 0         0 $xml .= "\n" . $edge->get_xml_tag(1);
2177             }
2178              
2179             # then the subtended edges
2180 0         0 for my $node (@nodes) {
2181 0         0 my $length = $node->get_branch_length;
2182 0         0 my $edge = $fac->create_xmlwritable(
2183             '-tag' => 'edge',
2184             '-attributes' => {
2185             'source' => $node->get_parent->get_xml_id,
2186             'target' => $node->get_xml_id,
2187             'id' => "edge" . $node->get_id
2188             }
2189             );
2190 0 0       0 $edge->set_attributes( 'length' => $length ) if defined $length;
2191 0         0 $xml .= "\n" . $edge->get_xml_tag(1);
2192             }
2193 0         0 return $xml;
2194             }
2195              
2196             =item to_newick()
2197              
2198             Serializes subtree subtended by invocant to newick string.
2199              
2200             Type : Serializer
2201             Title : to_newick
2202             Usage : my $newick = $obj->to_newick;
2203             Function: Turns the invocant object into a newick string.
2204             Returns : SCALAR
2205             Args : takes same arguments as Bio::Phylo::Unparsers::Newick
2206             Comments: takes same arguments as Bio::Phylo::Unparsers::Newick
2207              
2208             =cut
2209              
2210             {
2211             my ( $root_id, $string );
2212              
2213             #no warnings 'uninitialized';
2214             sub to_newick {
2215 3364     3364 1 4480 my $node = shift;
2216 3364         6774 my %args = @_;
2217 3364 100       5864 $root_id = $node->get_id if not $root_id;
2218 3364         4586 my $blformat = '%f';
2219              
2220             # first create the name
2221 3364         3764 my $name;
2222 3364 100 100     5607 if ( $node->is_terminal or $args{'-nodelabels'} ) {
2223 3153 100 66     8860 if ( ref $args{'-nodelabels'} and ref($args{'-nodelabels'}) eq 'CODE' ) {
    50 0        
    0          
    0          
2224 35         71 my $id;
2225 35 100       77 if ( $node->is_terminal ) {
2226 18         138 $id = $args{'-translate'}->{$node->get_nexus_name};
2227             }
2228             else {
2229 17         61 $id = $node->get_name;
2230             }
2231 35         124 $name = $args{'-nodelabels'}->($node,$id);
2232             }
2233             elsif ( not $args{'-tipnames'} ) {
2234 3118         6967 $name = $node->get_nexus_name(1);
2235             }
2236             elsif ( $args{'-tipnames'} =~ /^internal$/i ) {
2237 0         0 $name = $node->get_nexus_name(1);
2238             }
2239             elsif ( $args{'-tipnames'} =~ /^taxon/i and $node->get_taxon ) {
2240 0 0       0 if ( $args{'-tipnames'} =~ /^taxon_internal$/i ) {
    0          
2241 0         0 $name = $node->get_taxon->get_nexus_name(1);
2242             }
2243             elsif ( $args{'-tipnames'} =~ /^taxon$/i ) {
2244 0         0 $name = $node->get_taxon->get_nexus_name(1);
2245             }
2246             }
2247             else {
2248 0         0 $name = $node->get_generic( $args{'-tipnames'} );
2249             }
2250 3153 50 66     6378 if ( $args{'-translate'}
2251             and exists $args{'-translate'}->{$name} )
2252             {
2253 0         0 $name = $args{'-translate'}->{$name};
2254             }
2255             }
2256              
2257             # now format branch length
2258 3364         4967 my $branch_length;
2259 3364 100       7544 if ( defined( $branch_length = $node->get_branch_length ) ) {
2260 3132 50       5644 if ( $args{'-blformat'} ) {
2261 0         0 $blformat = $args{'-blformat'};
2262             }
2263 3132         15042 $branch_length = sprintf $blformat, $branch_length;
2264             }
2265              
2266             # now format nhx
2267 3364         5021 my $nhx;
2268 3364 100       5906 if ( $args{'-nhxkeys'} ) {
2269 215         283 my ( $sep, $sp );
2270 215 50       398 if ( $args{'-nhxstyle'} =~ /^mesquite$/i ) {
2271 0         0 $sep = ',';
2272 0         0 $nhx = '[%';
2273 0         0 $sp = ' ';
2274             }
2275             else {
2276 215         282 $sep = ':';
2277 215         263 $nhx = '[&&NHX:';
2278 215         288 $sp = '';
2279             }
2280 215         284 my @nhx;
2281 215         247 for my $i ( 0 .. $#{ $args{'-nhxkeys'} } ) {
  215         550  
2282 860         1375 my $key = $args{'-nhxkeys'}->[$i];
2283 860         1632 my $value = $node->get_generic($key);
2284 860 100       2505 push @nhx, "$sp$key$sp=$sp$value$sp" if $value;
2285             }
2286 215 50       433 if (@nhx) {
2287 215         468 $nhx .= join $sep, @nhx;
2288 215         405 $nhx .= ']';
2289             }
2290             else {
2291 0         0 $nhx = '';
2292             }
2293             }
2294              
2295             # recurse further
2296 3364 100       6938 if ( my $first_daughter = $node->get_first_daughter ) {
2297 1652         2937 $string .= '(';
2298 1652         5266 $first_daughter->to_newick(%args);
2299             }
2300              
2301             # append to growing newick string
2302 3364 100       8083 $string .= ')' if $node->get_first_daughter;
2303 3364 100       7289 $string .= $name if defined $name;
2304 3364 100       7090 $string .= ':' . $branch_length if defined $branch_length;
2305 3364 100       5295 $string .= $nhx if $nhx;
2306 3364 100       6497 if ( $root_id == $node->get_id ) {
    100          
2307 29         69 undef $root_id;
2308 29         630 my $result = $string . ';';
2309 29         67 undef $string;
2310 29         193 return $result;
2311             }
2312              
2313             # recurse further
2314             elsif ( my $next_sister = $node->get_next_sister ) {
2315 1683         2555 $string .= ',';
2316 1683         4763 $next_sister->to_newick(%args);
2317             }
2318             else {
2319             #$string .= ')';
2320             }
2321             }
2322             }
2323              
2324             =item to_dom()
2325              
2326             Type : Serializer
2327             Title : to_dom
2328             Usage : $node->to_dom($dom)
2329             Function: Generates an array of DOM elements from the invocant's
2330             descendants
2331             Returns : an array of Element objects
2332             Args : DOM factory object
2333              
2334             =cut
2335              
2336             sub to_dom {
2337 0     0 1 0 my ( $self, $dom ) = shift;
2338 0   0     0 $dom ||= $Bio::Phylo::NeXML::DOM::DOM;
2339 0 0       0 unless ( looks_like_object $dom, _DOMCREATOR_ ) {
2340 0         0 throw 'BadArgs' => 'DOM factory object not provided';
2341             }
2342 0         0 my @nodes = ( $self, @{ $self->get_descendants } );
  0         0  
2343 0         0 my @elts;
2344              
2345             # first write out the node elements
2346 0         0 for my $node (@nodes) {
2347 0 0       0 if ( my $taxon = $node->get_taxon ) {
2348 0         0 $node->set_attributes( 'otu' => $taxon->get_xml_id );
2349             }
2350 0 0       0 if ( $node->is_root ) {
2351 0         0 $node->set_attributes( 'root' => 'true' );
2352             }
2353 0         0 push @elts, $node->get_dom_elt($dom);
2354             }
2355              
2356             # then the rootedge?
2357 0 0       0 if ( my $length = shift(@nodes)->get_branch_length ) {
2358 0         0 my $target = $self->get_xml_id;
2359 0         0 my $id = "edge" . $self->get_id;
2360 0         0 my $elt = $dom->create_element(
2361             '-tag' => 'rootedge',
2362             '-attributes' => {
2363             'target' => $target,
2364             'id' => $id,
2365             'length' => $length,
2366             }
2367             );
2368 0         0 push @elts, $elt;
2369             }
2370              
2371             # then the subtended edges
2372 0         0 for my $node (@nodes) {
2373 0         0 my $source = $node->get_parent->get_xml_id;
2374 0         0 my $target = $node->get_xml_id;
2375 0         0 my $id = "edge" . $node->get_id;
2376 0         0 my $length = $node->get_branch_length;
2377 0         0 my $elt = $dom->create_element(
2378             '-tag' => 'edge',
2379             '-attributes' => {
2380             'source' => $source,
2381             'target' => $target,
2382             'id' => $id,
2383             }
2384             );
2385 0 0       0 $elt->set_attributes( 'length' => $length ) if ( defined $length );
2386 0         0 push @elts, $elt;
2387             }
2388 0         0 return @elts;
2389             }
2390              
2391             =begin comment
2392              
2393             Type : Internal method
2394             Title : _type
2395             Usage : $node->_type;
2396             Function:
2397             Returns : CONSTANT
2398             Args :
2399              
2400             =end comment
2401              
2402             =cut
2403              
2404 60086     60086   100023 sub _type { $TYPE_CONSTANT }
2405 2     2   7 sub _tag { 'node' }
2406              
2407             =begin comment
2408              
2409             Type : Internal method
2410             Title : _container
2411             Usage : $node->_container;
2412             Function:
2413             Returns : CONSTANT
2414             Args :
2415              
2416             =end comment
2417              
2418             =cut
2419              
2420 19487     19487   29956 sub _container { $CONTAINER_CONSTANT }
2421              
2422             =back
2423              
2424             =cut
2425              
2426             # podinherit_insert_token
2427              
2428             =head1 SEE ALSO
2429              
2430             There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo>
2431             for any user or developer questions and discussions.
2432              
2433             =over
2434              
2435             =item L<Bio::Phylo::Taxa::TaxonLinker>
2436              
2437             This object inherits from L<Bio::Phylo::Taxa::TaxonLinker>, so methods
2438             defined there are also applicable here.
2439              
2440             =item L<Bio::Phylo::Listable>
2441              
2442             This object inherits from L<Bio::Phylo::Listable>, so methods
2443             defined there are also applicable here.
2444              
2445             =item L<Bio::Phylo::Manual>
2446              
2447             Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
2448              
2449             =back
2450              
2451             =head1 CITATION
2452              
2453             If you use Bio::Phylo in published research, please cite it:
2454              
2455             B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
2456             and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
2457             I<BMC Bioinformatics> B<12>:63.
2458             L<http://dx.doi.org/10.1186/1471-2105-12-63>
2459              
2460             =cut
2461              
2462             1;
2463             __DATA__
2464              
2465             sub add_Descendent{
2466             my ( $self,$child ) = @_;
2467             $self->set_child( $child );
2468             return scalar @{ $self->get_children };
2469             }
2470              
2471             sub each_Descendent{
2472             my $self = shift;
2473             if ( my $children = $self->get_children ) {
2474             return @{ $children };
2475             }
2476             return;
2477             }
2478              
2479             sub get_all_Descendents{
2480             my $self = shift;
2481             if ( my $desc = $self->get_descendants ) {
2482             return @{ $desc };
2483             }
2484             return;
2485             }
2486              
2487             *get_Descendents = \&get_all_Descendents;
2488              
2489             *is_Leaf = \&is_terminal;
2490             *is_otu = \&is_terminal;
2491              
2492             sub descendent_count{
2493             my $self = shift;
2494             my $count = 0;
2495             if ( my $desc = get_descendants ) {
2496             $count = scalar @{ $desc };
2497             }
2498             return $count;
2499             }
2500              
2501             sub height{ shift->calc_max_path_to_tips }
2502              
2503             sub depth{ shift->calc_path_to_root }
2504              
2505             sub branch_length{
2506             my $self = shift;
2507             if ( @_ ) {
2508             $self->set_branch_length(shift);
2509             }
2510             return $self->get_branch_length;
2511             }
2512              
2513             sub id {
2514             my $self = shift;
2515             if ( @_ ) {
2516             $self->set_name(shift);
2517             }
2518             return $self->get_name;
2519             }
2520              
2521             sub internal_id { shift->get_id }
2522              
2523             sub description {
2524             my $self = shift;
2525             if ( @_ ) {
2526             $self->set_desc(shift);
2527             }
2528             return $self->get_desc;
2529             }
2530              
2531             sub bootstrap {
2532             my ( $self, $bs ) = @_;
2533             if ( defined $bs && looks_like_number $bs ) {
2534             $self->set_score($bs);
2535             }
2536             return $self->get_score;
2537             }
2538              
2539             sub ancestor {
2540             my $self = shift;
2541             if ( @_ ) {
2542             $self->set_parent(shift);
2543             }
2544             return $self->get_parent;
2545             }
2546              
2547             sub invalidate_height { }
2548              
2549             sub add_tag_value{
2550             my $self = shift;
2551             if ( @_ ) {
2552             my ( $key, $value ) = @_;
2553             $self->set_generic( $key, $value );
2554             }
2555             return 1;
2556             }
2557              
2558             sub remove_tag {
2559             my ( $self, $tag ) = @_;
2560             my %hash = %{ $self->get_generic };
2561             my $exists = exists $hash{$tag};
2562             delete $hash{$tag};
2563             $self->set_generic();
2564             $self->set_generic(%hash);
2565             return !!$exists;
2566             }
2567              
2568             sub remove_all_tags{ shift->set_generic() }
2569              
2570             sub get_all_tags {
2571             my $self = shift;
2572             my %hash = %{ $self->get_generic };
2573             return keys %hash;
2574             }
2575              
2576             sub get_tag_values{
2577             my ( $self, $tag ) = @_;
2578             my $values = $self->get_generic($tag);
2579             return ref $values ? @{ $values } : $values;
2580             }
2581              
2582             sub has_tag{
2583             my ( $self, $tag ) = @_;
2584             my %hash = %{ $self->get_generic };
2585             return exists $hash{$tag};
2586             }
2587              
2588             sub id_output { shift->get_internal_name }