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   194 use strict;
  34         75  
  34         944  
3 34     34   616 use Bio::Phylo::Util::MOP;
  34         63  
  34         223  
4 34     34   151 use base qw'Bio::Phylo::Taxa::TaxonLinker Bio::Phylo::Listable';
  34         74  
  34         9677  
5 34     34   2803 use Bio::Phylo::Util::OptionalInterface 'Bio::Tree::NodeI';
  34         156  
  34         181  
6 34     34   401 use Bio::Phylo::Util::CONSTANT qw':objecttypes /looks_like/';
  34         68  
  34         8162  
7 34     34   219 use Bio::Phylo::Util::Exceptions 'throw';
  34         65  
  34         1278  
8 34     34   9761 use Bio::Phylo::Util::Math ':all';
  34         81  
  34         3550  
9 34     34   223 use Bio::Phylo::NeXML::Writable;
  34         73  
  34         327  
10 34     34   197 use Bio::Phylo::Factory;
  34         62  
  34         198  
11 34     34   157 use Scalar::Util 'weaken';
  34         61  
  34         1420  
12 34     34   253 use List::Util qw[sum min max];
  34         124  
  34         2846  
13 34     34   256 no warnings 'recursion';
  34         67  
  34         7657  
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 8251     8251 1 12875 my $class = shift;
113              
114             # process bioperl args
115 8251         20543 my %args = looks_like_hash @_;
116 8251 50       16054 if ( exists $args{'-leaf'} ) {
117 0         0 delete $args{'-leaf'};
118             }
119 8251 50       13566 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 8251 50       15372 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 8251         24645 my $self = $class->SUPER::new(%args);
135 8251 100       15667 if ( not $LOADED_WRAPPERS ) {
136 29 0 0 0 0 69 eval do { local $/; };
  29 0   0 0 139  
  29 0   0 0 22052  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0 0   0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  0     0   0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  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         87 $LOADED_WRAPPERS++;
138             }
139 8251         22388 return $self;
140 34     34   211 }
  34         68  
  34         182  
141              
142             =item new_from_bioperl()
143              
144             Node constructor from bioperl L 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 356     356 1 592 my ( $self, $child ) = @_;
213 356         1057 $self->delete($child);
214 356         553 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 114     114 1 168 my $self = shift;
236              
237             # can't collapse root
238 114 50       263 if ( my $parent = $self->get_parent ) {
239              
240             # can't collapse terminal nodes
241 114 50       153 if ( my @children = @{ $self->get_children } ) {
  114         219  
242              
243             # add node's branch length to that of children
244 114         247 my $length = $self->get_branch_length;
245 114         224 for my $child (@children) {
246 228 50       408 if ( defined $length ) {
247 228   50     507 my $child_length = $child->get_branch_length || 0;
248 228         925 $child->set_branch_length( $length + $child_length );
249             }
250              
251             # attach children to node's parent
252 228         609 $child->set_parent($parent);
253             }
254              
255             # prune node from parent
256 114         283 $parent->prune_child($self);
257              
258             # delete node from tree
259 114 50       273 if ( my $tree = $self->get_tree ) {
260 114         254 $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 508 my ( $self, $fd ) = @_;
289 336         813 $self->set_child( $fd, 0 );
290 335         585 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 502 my ( $self, $ld ) = @_;
311 336         447 $self->set_child( $ld, scalar @{ $self->get_children } );
  336         583  
312 335         629 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 342 my ( $self, $ps ) = @_;
333 237 100 100     479 if ( $ps and looks_like_object $ps, $TYPE_CONSTANT ) {
334 6 50       31 if ( my $parent = $self->get_parent ) {
335 6         29 my $children = $parent->get_children;
336 6         21 my $j = 0;
337 6         17 FINDSELF: for ( my $i = $#{$children} ; $i >= 0 ; $i-- ) {
  6         32  
338 13 100       63 if ( $children->[$i] == $self ) {
339 6         53 $j = $i - 1;
340 6         21 last FINDSELF;
341             }
342             }
343 6 50       28 $j = 0 if $j == -1;
344 6         31 $parent->set_child( $ps, $j );
345             }
346             }
347 236         359 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 385 my ( $self, $ns ) = @_;
369 237 100 100     468 if ( $ns and looks_like_object $ns, $TYPE_CONSTANT ) {
370 6 50       33 if ( my $parent = $self->get_parent ) {
371 6         28 my $children = $parent->get_children;
372 6         16 my $last = scalar @{$children};
  6         22  
373 6         17 my $j = $last;
374 6         16 FINDSELF: for my $i ( 0 .. $#{$children} ) {
  6         41  
375 16 100       61 if ( $children->[$i] == $self ) {
376 6         18 $j = $i + 1;
377 6         29 last FINDSELF;
378             }
379             }
380 6         35 $parent->set_child( $ns, $j );
381             }
382             }
383 236         365 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     39 my $dist = shift || 0;
443 9   50     31 my $force = shift || 0;
444 9         36 my $tree = $node->get_tree;
445 9         43 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       28 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         21 my ( $q, $s, $new_root );
458 7         20 my $p = $node->get_parent;
459 7         56 my $i = $p->get_index_of( $node );
460 7         20 my $r = $p->get_parent;
461 7         25 my $d = $p->get_branch_length;
462 7   100     19 my $tmp = $node->get_branch_length || 0;
463            
464             # adjust $dist to a useable value
465 7 50 33     84 $dist = $tmp / 2 if ($dist < 0.0 || $dist > $tmp);
466              
467             # instantiate new root, add $node as first child with new length
468 7         60 $q = $new_root = $fac->create_node( '-name' => 'root' );
469 7         32 $q->set_raw_child( $node => 0 );
470 7         27 $node->set_raw_parent( $q );
471 7         33 $node->set_branch_length( $dist );
472            
473             # add $node's parent as child with new length
474 7         23 $q->set_raw_child( $p => 1 );
475 7         26 $p->set_raw_parent( $q );
476 7         30 $p->set_branch_length( $tmp - $dist );
477            
478             # traverse along previous ancestors, swap them
479             # and update the branch lengths
480 7         25 while ( $r ) {
481 18         42 $s = $r->get_parent; # store r's parent
482 18         51 $p->set_raw_child( $r => $i ); # change r to p's child
483 18         47 $i = $r->get_index_of( $p ); # update $i
484 18         49 $r->set_raw_parent( $p ); # update r's parent
485            
486             # swap r->d and d, i.e. update r->d
487 18         42 $tmp = $r->get_branch_length;
488 18         49 $r->set_branch_length( $d );
489 18         23 $d = $tmp;
490            
491             # update p, q and r
492 18         26 $q = $p; $p = $r; $r = $s;
  18         28  
  18         33  
493             }
494            
495             # now $p is the root node
496 7         13 my @children = @{ $p->get_children };
  7         19  
497 7 50       25 if ( scalar(@children) == 2 ) { # remove p and link the other child of p to q
498 7         23 $r = $children[1 - $i]; # get the other child
499 7         17 $i = $q->get_index_of( $p ); # the position of p in q
500 7   100     20 my $bl = ( $r->get_branch_length || 0 ) + ( $p->get_branch_length || 0 );
      100        
501 7         28 $r->set_branch_length( $bl );
502            
503             # link r to q
504 7         22 $q->set_raw_child( $r => $i );
505 7         20 $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         29 $tree->insert($new_root);
520 7         24 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 59451     59451 1 101000 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 44 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 318 my $self = shift;
579 230         408 my $id = $self->get_id;
580 230 50       493 if ( my $parent = $self->get_parent ) {
581 230         441 my $children = $parent->get_children;
582 230         350 for ( my $i = $#{$children} ; $i >= 1 ; $i-- ) {
  230         545  
583 280 100       609 if ( $children->[$i]->get_id == $id ) {
584 119         355 return $children->[ $i - 1 ];
585             }
586             }
587             }
588 111         282 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 8429     8429 1 11303 my $self = shift;
606 8429         14040 my $id = $self->get_id;
607 8429 100       16735 if ( my $parent = $self->get_parent ) {
608 8214         14536 my $children = $parent->get_children;
609 8214         11441 for my $i ( 0 .. $#{$children} ) {
  8214         17380  
610 12688 100       23260 if ( $children->[$i]->get_id == $id ) {
611 8214         22765 return $children->[ $i + 1 ];
612             }
613             }
614             }
615 215         486 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 106 my $self = shift;
635 71         88 my @ancestors;
636 71         82 my $node = $self;
637 71 100       141 if ( $node = $node->get_parent ) {
638 69         128 while ($node) {
639 219         359 push @ancestors, $node;
640 219         359 $node = $node->get_parent;
641             }
642 69         203 return \@ancestors;
643             }
644             else {
645 2         12 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 8 my $self = shift;
664 3 50       11 if ( my $anc = $self->get_ancestors ) {
665 3         15 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 571 my ( $self, $patristic ) = @_;
689 3 100       15 my $criterion = $patristic ? 'patristic' : 'nodal';
690 3         24 my $method = sprintf 'calc_%s_distance', $criterion;
691 3         17 my $root = $self->get_root;
692 3 50       21 if ( my $terminals = $root->get_terminals ) {
693 3         12 my ( $furthest_distance, $furthest_node ) = (0);
694 3         7 for my $tip ( @{$terminals} ) {
  3         10  
695 24         78 my $distance = $self->$method($tip);
696 24 100       53 if ( $distance > $furthest_distance ) {
697 13         17 $furthest_distance = $distance;
698 13         18 $furthest_node = $tip;
699             }
700             }
701 3         20 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 4 my $self = shift;
725 2         4 my $sisters;
726 2 50       7 if ( my $parent = $self->get_parent ) {
727 2         7 $sisters = $parent->get_children;
728             }
729 2         10 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 59478     59478 1 83357 my ( $self, $i ) = @_;
749 59478 50       95173 $i = 0 if not defined $i;
750 59478         111802 my $children = $self->get_children;
751 59478         183153 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 759     759 1 1176 my $self = shift;
772 759         1311 my @current = ($self);
773 759         899 my @desc;
774 759         1382 while ( $self->_desc(@current) ) {
775 5365         8683 @current = $self->_desc(@current);
776 5365         13814 push @desc, @current;
777             }
778 759         1669 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 11489     11489   13568 my $self = shift;
805 11489         15930 my @current = @_;
806 11489         12358 my @return;
807 11489         14542 foreach (@current) {
808 61523         99435 my $children = $_->get_children;
809 61523 50       93262 if ($children) {
810 61523         64938 push @return, @{$children};
  61523         91272  
811             }
812             }
813 11489         23369 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 749     749 1 1013 my $self = shift;
833 749 50       1249 if ( $self->is_terminal ) {
834 0         0 return [$self];
835             }
836             else {
837 749         1017 return [ grep { $_->is_terminal } @{ $self->get_descendants } ];
  30993         52028  
  749         1374  
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 3 my $self = shift;
858 1         3 my @internals;
859 1         5 my $desc = $self->get_descendants;
860 1 50       5 if ( @{$desc} ) {
  1         7  
861 1         10 foreach ( @{$desc} ) {
  1         5  
862 14 100       30 if ( $_->is_internal ) {
863 6         11 push @internals, $_;
864             }
865             }
866             }
867 1         6 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 79 my ( $self, $other_node ) = @_;
887 40 100       103 if ( $self->get_id == $other_node->get_id ) {
888 7         21 return $self;
889             }
890 33   50     115 my $self_anc = $self->get_ancestors || [$self];
891 33   100     74 my $other_anc = $other_node->get_ancestors || [$other_node];
892 33         53 for my $i ( 0 .. $#{$self_anc} ) {
  33         87  
893 67         125 my $self_anc_id = $self_anc->[$i]->get_id;
894 67         94 for my $j ( 0 .. $#{$other_anc} ) {
  67         115  
895 200 100       329 if ( $self_anc_id == $other_anc->[$j]->get_id ) {
896 32         92 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 9 my $self = shift;
920 4         8 my $daughter = $self;
921 4         11 FIRST_DAUGHTER: while ($daughter) {
922 10 100       25 if ( my $grand_daughter = $daughter->get_first_daughter ) {
923 6         9 $daughter = $grand_daughter;
924 6         14 next FIRST_DAUGHTER;
925             }
926             else {
927 4         9 last FIRST_DAUGHTER;
928             }
929             }
930 4         18 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 10 my $self = shift;
950 4         8 my $daughter = $self;
951 4         13 LAST_DAUGHTER: while ($daughter) {
952 20 100       41 if ( my $grand_daughter = $daughter->get_last_daughter ) {
953 16         21 $daughter = $grand_daughter;
954 16         30 next LAST_DAUGHTER;
955             }
956             else {
957 4         8 last LAST_DAUGHTER;
958             }
959             }
960 4         16 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 2509 my ($node,$u,$v) = @_;
1028            
1029             # node is terminal
1030 1904         2060 my @child = @{ $node->get_children };
  1904         2923  
1031 1904 100       3521 if ( not @child ) {
    50          
1032 1008         1876 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         1382 my ( $found_ul, $found_vl, $subtree_l, $subtree_ul, $subtree_vl ) = $child[0]->get_subtrees( $u, $v );
1040 896         1498 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     1804 if ( $found_ul and $found_vl ) {
1044 16         46 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     1502 if ( $found_ur and $found_vr ) {
1049 24         66 return $found_ur, $found_vr, $subtree_r, $subtree_ur, $subtree_vr;
1050             }
1051            
1052             # have we found either?
1053 856   100     2594 my $found_u = ( $found_ul or $found_ur or $node->is_equal($u) );
1054 856   100     2504 my $found_v = ( $found_vl or $found_vr or $node->is_equal($v) );
1055            
1056             # initialize and assign subtrees
1057 856         1119 my ( $subtree_u, $subtree_v );
1058 856 100       1258 $subtree_u = $subtree_ul if $found_ul;
1059 856 100       1144 $subtree_v = $subtree_vl if $found_vl;
1060 856 100       1195 $subtree_u = $subtree_ur if $found_ur;
1061 856 100       1210 $subtree_v = $subtree_vr if $found_vr;
1062 856 100 100     2211 if ( $found_u and (not $found_v) ) {
    100 100        
1063 142         179 $subtree_u = $node;
1064             }
1065             elsif ( $found_v and (not $found_u) ) {
1066 142         168 $subtree_v = $node;
1067             }
1068 856 100       1401 $subtree_u = $node if $node->is_equal($u);
1069 856 100       1592 $subtree_v = $node if $node->is_equal($v);
1070            
1071             # return results
1072 856         2168 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 48198     48198 1 83155 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 147     147 1 300 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 33 my $self = shift;
1138 9         29 my $children = $self->get_children;
1139 9         18 for my $child ( @{$children} ) {
  9         25  
1140 11 100       39 return 0 if $child->is_internal;
1141             }
1142 8         16 return !!scalar @{$children};
  8         55  
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 717     717 1 1110 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 8310     8310 1 11479 my ( $self, $ancestor ) = @_;
1223 8310         13875 my $ancestor_id = $ancestor->get_id;
1224 8310         19303 while ($self) {
1225 105907 100       169589 if ( my $parent = $self->get_parent ) {
1226 97600         114200 $self = $parent;
1227             }
1228             else {
1229 8307         16889 return;
1230             }
1231 97600 100       156967 if ( $self->get_id == $ancestor_id ) {
1232 3         11 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 8309     8309 1 14367 my ( $self, $child ) = @_;
1256 8309 100       13863 if ( $child->is_descendant_of($self) ) {
1257 3         17 return 1;
1258             }
1259             else {
1260 8306         18237 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         10 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         5 return 1;
1290             }
1291             else {
1292 3         12 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 8615     8615 1 14594 my ( $self, $node ) = @_;
1315 8615 100       18280 if ( my $parent = $self->get_parent ) {
1316 553         1098 return $parent->get_id == $node->get_id;
1317             }
1318 8062         22309 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 6 my ( $outgroup, $nodes ) = @_;
1343 2         3 for my $i ( 0 .. $#{$nodes} ) {
  2         7  
1344 3         5 for my $j ( ( $i + 1 ) .. $#{$nodes} ) {
  3         5  
1345 2         9 my $mrca = $nodes->[$i]->get_mrca( $nodes->[$j] );
1346 2 100       6 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 17141     17141 1 23372 my $self = shift;
1375 17141         27249 my $type = $self->_type;
1376 17141         28598 for (@_) {
1377 17161 50       25722 return 0 if $type != $_->_type;
1378             }
1379 17141         37865 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 122 my $self = shift;
1405 81         103 my $node = $self;
1406 81         111 my $path = 0;
1407 81         147 while ($node) {
1408 379         640 my $branch_length = $node->get_branch_length;
1409 379 50       646 if ( defined $branch_length ) {
1410 379         614 $path += $branch_length;
1411             }
1412 379 100       691 if ( my $parent = $node->get_parent ) {
1413 298         556 $node = $parent;
1414             }
1415             else {
1416 81         127 last;
1417             }
1418             }
1419 81         206 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 3 my $self = shift;
1439 2         4 my ( $nodes, $parent ) = ( 0, $self );
1440 2         6 while ($parent) {
1441 2         3 $nodes++;
1442 2         5 $parent = $parent->get_parent;
1443 2 100       7 if ($parent) {
1444 1 50       4 if ( my $cntr = $parent->calc_nodes_to_root ) {
1445 1         8 $nodes += $cntr;
1446 1         2 last;
1447             }
1448             }
1449             }
1450 2         6 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         13 $nodes = 0;
1474 8   66     19 while ( $child && $child->get_id != $self_id ) {
1475 35         39 $nodes++;
1476 35         53 $child = $child->get_parent;
1477             }
1478 8 100       16 if ( $nodes > $maxnodes ) {
1479 7         8 $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         12 my $self_id = $self->get_id;
1503 2         5 my ( $nodes, $minnodes );
1504 2         5 foreach my $child ( @{ $self->get_terminals } ) {
  2         5  
1505 34         42 $nodes = 0;
1506 34   66     69 while ( $child && $child->get_id != $self_id ) {
1507 166         188 $nodes++;
1508 166         238 $child = $child->get_parent;
1509             }
1510 34 100 66     94 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 4 my $self = shift;
1534 2         5 my $id = $self->get_id;
1535 2         5 my ( $length, $maxlength ) = ( 0, 0 );
1536 2         3 foreach my $child ( @{ $self->get_terminals } ) {
  2         5  
1537 16         21 $length = 0;
1538 16   66     36 while ( $child && $child->get_id != $id ) {
1539 68         108 my $branch_length = $child->get_branch_length;
1540 68 100       112 if ( defined $branch_length ) {
1541 35         39 $length += $branch_length;
1542             }
1543 68         110 $child = $child->get_parent;
1544             }
1545 16 100       30 if ( $length > $maxlength ) {
1546 7         11 $maxlength = $length;
1547             }
1548             }
1549 2         12 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 5 my $self = shift;
1569 2         6 my $id = $self->get_id;
1570 2         5 my ( $length, $minlength );
1571 2         6 foreach my $child ( @{ $self->get_terminals } ) {
  2         6  
1572 16         18 $length = 0;
1573 16   66     39 while ( $child && $child->get_id != $id ) {
1574 68         109 my $branch_length = $child->get_branch_length;
1575 68 100       102 if ( defined $branch_length ) {
1576 35         44 $length += $branch_length;
1577             }
1578 68         136 $child = $child->get_parent;
1579             }
1580 16 100       27 if ( !$minlength ) {
1581 9         11 $minlength = $length;
1582             }
1583 16 50       31 if ( $length < $minlength ) {
1584 0         0 $minlength = $length;
1585             }
1586             }
1587 2         10 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 42 my ( $self, $other_node ) = @_;
1607 19         31 my $patristic_distance = 0;
1608 19         42 my $mrca = $self->get_mrca($other_node);
1609 19         40 my $mrca_id = $mrca->get_id;
1610 19         40 while ( $self->get_id != $mrca_id ) {
1611 38         87 my $branch_length = $self->get_branch_length;
1612 38 100       71 if ( defined $branch_length ) {
1613 37         57 $patristic_distance += $branch_length;
1614             }
1615 38         68 $self = $self->get_parent;
1616             }
1617 19   66     57 while ( $other_node and $other_node->get_id != $mrca_id ) {
1618 48         84 my $branch_length = $other_node->get_branch_length;
1619 48 100       86 if ( defined $branch_length ) {
1620 43         57 $patristic_distance += $branch_length;
1621             }
1622 48         102 $other_node = $other_node->get_parent;
1623             }
1624 19         38 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         19 my $mrca = $self->get_mrca($other_node);
1646 9         21 my $mrca_id = $mrca->get_id;
1647 9   66     48 while ( $self and $self->get_id != $mrca_id ) {
1648 18         24 $nodal_distance++;
1649 18         46 $self = $self->get_parent;
1650             }
1651 9   66     25 while ( $other_node and $other_node->get_id != $mrca_id ) {
1652 21         54 $nodal_distance++;
1653 21         35 $other_node = $other_node->get_parent;
1654             }
1655 9         16 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 310 my $self = shift;
1673 236         271 my $tips = 0;
1674 236 100   1172   871 $self->visit_level_order( sub { $tips++ if shift->is_terminal } );
  1172         1777  
1675 236         694 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 473 my ($node,$u) = @_;
1697            
1698             # focal node (subtree) is empty, i.e. a leaf
1699 358         368 my @child = @{ $node->get_children };
  358         594  
1700 358 100       675 return [undef,undef] if not @child;
1701 250 100       460 return [ 1, [ $node->calc_terminals - 1 ] ] if $node->is_equal($u);
1702            
1703             # recurse left
1704 166         305 my $x = $child[0]->calc_rankprob_tipcounts( $u );
1705 166 100       286 if ( $x->[0] ) {
1706 58         74 my $n;
1707            
1708             # focal node has no sibling
1709 58 50       86 if ( not $child[1] ) {
1710 0         0 $n = 0;
1711             }
1712             else {
1713 58         96 $n = $child[1]->calc_terminals - 1;
1714             }
1715 58         78 return [ 1, [ @{ $x->[1] }, $n ] ];
  58         154  
1716             }
1717              
1718             # recurse right
1719 108         162 my $y = $child[1]->calc_rankprob_tipcounts( $u );
1720 108 100       156 if ( $y->[0] ) {
1721 34         43 my $n;
1722            
1723             # focal node has no sibling
1724 34 50       63 if ( not $child[0] ) {
1725 0         0 $n = 0;
1726             }
1727             else {
1728 34         58 $n = $child[0]->calc_terminals - 1;
1729             }
1730 34         45 return [ 1, [ @{ $y->[1] }, $n ] ];
  34         104  
1731             }
1732            
1733             # $u is neither left or right from here
1734             else {
1735 74         139 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 et al., 2006. Estimating the relative order of speciation
1746             or coalescence events on a given phylogeny. I.
1747             B<2>:285. L.
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 116 my ($t,$u) = @_;
1760 76         118 my $x = $t->calc_rankprob_tipcounts($u);
1761 76         125 $x = $x->[1];
1762 76         95 my $lhsm = $x->[0];
1763 76         94 my $k = scalar(@$x);
1764 76         97 my $start = 1;
1765 76         90 my $end = 1;
1766 76         108 my $rp = [0,1];
1767 76         91 my $step = 1;
1768 76         134 while ( $step < $k ) {
1769 68         85 my $rhsm = $x->[$step];
1770 68         86 my $newstart = $start+1;
1771 68         83 my $newend = $end + $rhsm + 1;
1772 68         88 my $rp2 = [];
1773 68         115 for my $i ( 0 .. $newend ) {
1774 336         434 push @$rp2, 0;
1775             }
1776 68         95 for my $i ( $newstart .. $newend ) {
1777 180         322 my $q = max( 0, $i - 1 - $end );
1778 180         328 for my $j ( $q .. min( $rhsm, $i - 2 ) ) {
1779 266         567 my $a = $rp->[$i-$j-1] * nchoose($lhsm + $rhsm - ($i-1),$rhsm-$j) * nchoose($i-2,$j);
1780 266         446 $rp2->[$i]+=$a;
1781             }
1782             }
1783 68         87 $rp = $rp2;
1784 68         89 $start = $newstart;
1785 68         74 $end = $newend;
1786 68         74 $lhsm = $lhsm+$rhsm+1;
1787 68         123 $step += 1;
1788             }
1789 76         90 my $tot = sum( @{ $rp } );
  76         177  
1790 76         108 for my $i ( 0..$#{ $rp } ) {
  76         127  
1791 320         428 $rp->[$i] = $rp->[$i] / $tot;
1792             }
1793 76         153 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 et al., 2006. Estimating the relative order of speciation
1802             or coalescence events on a given phylogeny. I.
1803             B<2>:285. L.
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         15 my $rp = $t->calc_rankprob( $u );
1817 8         12 my $mu = 0;
1818 8         10 my $sigma = 0;
1819 8         11 for my $i ( 0 .. $#{ $rp } ) {
  8         12  
1820 59         76 $mu += $i * $rp->[$i];
1821 59         100 $sigma += $i * $i * $rp->[$i];
1822             }
1823 8         30 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 et al., 2006. Estimating the relative order of speciation
1832             or coalescence events on a given phylogeny. I.
1833             B<2>:285. L.
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 95 my ($t,$u,$v) = @_;
1846 56         120 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     177 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       104 return 1.0 if $root->is_equal($u);
1858 43 100       86 return 0.0 if $root->is_equal($v);
1859              
1860             # calculate rank probabilities in
1861             # respective subtrees
1862 30         59 my $x = $root_u->calc_rankprob($u);
1863 30         58 my $y = $root_v->calc_rankprob($v);
1864 30         52 my $usize = $root_u->calc_terminals - 1;
1865 30         56 my $vsize = $root_v->calc_terminals - 1;
1866            
1867 30         94 for my $i ( scalar(@$x) .. $usize + 1 ) {
1868 51         85 push @$x, 0;
1869             }
1870 30         49 my $xcumulative = [0];
1871 30         39 for my $i ( 1 .. $#{ $x } ) {
  30         51  
1872 122         231 push @$xcumulative, $xcumulative->[$i-1] + $x->[$i];
1873             }
1874 30         44 my $rp = [0];
1875 30         39 for my $i ( 1 .. $#{ $y } ) {
  30         55  
1876 71         102 push @$rp, 0;
1877 71         94 for my $j ( 1 .. $usize) {
1878 229         461 my $a = $y->[$i] * nchoose($i-1+$j,$j) * nchoose($vsize-$i+$usize-$j, $usize-$j) * $xcumulative->[$j];
1879 229         365 $rp->[$i] += $a;
1880             }
1881             }
1882 30         58 my $tot = nchoose($usize+$vsize,$vsize);
1883 30         138 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,
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 145     145 1 290 my $self = shift;
1957 145         372 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 145 50 33     551 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 145         347 $args{'-sister_method'} = 'get_next_sister';
1977 145         335 $args{'-daughter_method'} = 'get_first_daughter';
1978             }
1979 145         682 $self->_visit_depth_first(%args);
1980 144         499 return $self;
1981             }
1982              
1983             sub _visit_depth_first {
1984 5162     5162   12237 my ( $node, %args ) = @_;
1985             my ( $daughter_method, $sister_method ) =
1986 5162         9297 @args{qw(-daughter_method -sister_method)};
1987 5162 100       10096 $args{'-pre'}->($node) if $args{'-pre'};
1988 5162 100       11570 if ( my $daughter = $node->$daughter_method ) {
1989 2469         3952 my @args = ($node);
1990 2469 50       4395 push @args, $daughter if $args{'-with_relatives'};
1991 2469 50       3913 $args{'-pre_daughter'}->(@args) if $args{'-pre_daughter'};
1992 2469         7326 $daughter->_visit_depth_first(%args);
1993 2464 100       6173 $args{'-post_daughter'}->(@args) if $args{'-post_daughter'};
1994             }
1995             else {
1996 2693 100       5123 $args{'-no_daughter'}->($node) if $args{'-no_daughter'};
1997             }
1998 5157 50       8659 $args{'-in'}->($node) if $args{'-in'};
1999 5157 100       10477 if ( my $sister = $node->$sister_method ) {
2000 2548         4258 my @args = ($node);
2001 2548 50       4460 push @args, $sister if $args{'-with_relatives'};
2002 2548 50       4497 $args{'-pre_sister'}->(@args) if $args{'-pre_sister'};
2003 2548         8161 $sister->_visit_depth_first(%args);
2004 2544 50       6136 $args{'-post_sister'}->(@args) if $args{'-post_sister'};
2005             }
2006             else {
2007 2609 50       4723 $args{'-no_sister'}->($node) if $args{'-no_sister'};
2008             }
2009 5153 100       13481 $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 700 my ( $self, $sub ) = @_;
2114 360 50       1067 if ( looks_like_instance $sub, 'CODE' ) {
2115 360         674 my @queue = ($self);
2116 360         752 while (@queue) {
2117 6298         8692 my $node = shift @queue;
2118 6298         12851 $sub->($node);
2119 6298 50       12186 if ( my $children = $node->get_children ) {
2120 6298         8244 push @queue, @{$children};
  6298         14515  
2121             }
2122             }
2123             }
2124             else {
2125 0         0 throw 'BadArgs' => "'$sub' not a CODE reference";
2126             }
2127 360         694 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 2966     2966 1 4118 my $node = shift;
2215 2966         5824 my %args = @_;
2216 2966 100       5338 $root_id = $node->get_id if not $root_id;
2217 2966         3999 my $blformat = '%f';
2218              
2219             # first create the name
2220 2966         3645 my $name;
2221 2966 100 100     5218 if ( $node->is_terminal or $args{'-nodelabels'} ) {
2222 2755 100 66     7293 if ( ref $args{'-nodelabels'} and ref($args{'-nodelabels'}) eq 'CODE' ) {
    50 0        
    0          
    0          
2223 35         58 my $id;
2224 35 100       103 if ( $node->is_terminal ) {
2225 18         196 $id = $args{'-translate'}->{$node->get_nexus_name};
2226             }
2227             else {
2228 17         92 $id = $node->get_name;
2229             }
2230 35         187 $name = $args{'-nodelabels'}->($node,$id);
2231             }
2232             elsif ( not $args{'-tipnames'} ) {
2233 2720         6651 $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 2755 50 66     5506 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 2966         3970 my $branch_length;
2258 2966 100       6332 if ( defined( $branch_length = $node->get_branch_length ) ) {
2259 2734 50       4798 if ( $args{'-blformat'} ) {
2260 0         0 $blformat = $args{'-blformat'};
2261             }
2262 2734         13470 $branch_length = sprintf $blformat, $branch_length;
2263             }
2264              
2265             # now format nhx
2266 2966         4145 my $nhx;
2267 2966 100       4950 if ( $args{'-nhxkeys'} ) {
2268 215         511 my ( $sep, $sp );
2269 215 50       384 if ( $args{'-nhxstyle'} =~ /^mesquite$/i ) {
2270 0         0 $sep = ',';
2271 0         0 $nhx = '[%';
2272 0         0 $sp = ' ';
2273             }
2274             else {
2275 215         302 $sep = ':';
2276 215         365 $nhx = '[&&NHX:';
2277 215         270 $sp = '';
2278             }
2279 215         292 my @nhx;
2280 215         276 for my $i ( 0 .. $#{ $args{'-nhxkeys'} } ) {
  215         544  
2281 860         1346 my $key = $args{'-nhxkeys'}->[$i];
2282 860         1718 my $value = $node->get_generic($key);
2283 860 100       2427 push @nhx, "$sp$key$sp=$sp$value$sp" if $value;
2284             }
2285 215 50       484 if (@nhx) {
2286 215         524 $nhx .= join $sep, @nhx;
2287 215         418 $nhx .= ']';
2288             }
2289             else {
2290 0         0 $nhx = '';
2291             }
2292             }
2293              
2294             # recurse further
2295 2966 100       6394 if ( my $first_daughter = $node->get_first_daughter ) {
2296 1453         2234 $string .= '(';
2297 1453         4656 $first_daughter->to_newick(%args);
2298             }
2299              
2300             # append to growing newick string
2301 2966 100       6874 $string .= ')' if $node->get_first_daughter;
2302 2966 100       6308 $string .= $name if defined $name;
2303 2966 100       6156 $string .= ':' . $branch_length if defined $branch_length;
2304 2966 100       4896 $string .= $nhx if $nhx;
2305 2966 100       5780 if ( $root_id == $node->get_id ) {
    100          
2306 29         69 undef $root_id;
2307 29         431 my $result = $string . ';';
2308 29         72 undef $string;
2309 29         239 return $result;
2310             }
2311              
2312             # recurse further
2313             elsif ( my $next_sister = $node->get_next_sister ) {
2314 1484         2391 $string .= ',';
2315 1484         4718 $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 52258     52258   89096 sub _type { $TYPE_CONSTANT }
2404 2     2   7 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 16836     16836   25436 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
2430             for any user or developer questions and discussions.
2431              
2432             =over
2433              
2434             =item L
2435              
2436             This object inherits from L, so methods
2437             defined there are also applicable here.
2438              
2439             =item L
2440              
2441             This object inherits from L, so methods
2442             defined there are also applicable here.
2443              
2444             =item L
2445              
2446             Also see the manual: L and L.
2447              
2448             =back
2449              
2450             =head1 CITATION
2451              
2452             If you use Bio::Phylo in published research, please cite it:
2453              
2454             B, B, B, B
2455             and B, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
2456             I B<12>:63.
2457             L
2458              
2459             =cut
2460              
2461             1;
2462             __DATA__