File Coverage

blib/lib/Bio/Phylo/Forest/NodeRole.pm
Criterion Covered Total %
statement 603 821 73.4
branch 189 320 59.0
condition 73 109 66.9
subroutine 69 100 69.0
pod 58 77 75.3
total 992 1427 69.5


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