File Coverage

Bio/PhyloNetwork/Factory.pm
Criterion Covered Total %
statement 90 92 97.8
branch 22 24 91.6
condition 4 5 80.0
subroutine 8 8 100.0
pod 2 3 66.6
total 126 132 95.4


line stmt bran cond sub pod time code
1             #
2             # Module for Bio::PhyloNetwork::Factory
3             #
4             # Please direct questions and support issues to
5             #
6             # Cared for by Gabriel Cardona
7             #
8             # Copyright Gabriel Cardona
9             #
10             # You may distribute this module under the same terms as perl itself
11              
12             # POD documentation - main docs before the code
13              
14             =head1 NAME
15              
16             Bio::PhyloNetwork::Factory - Module to sequentially generate
17             Phylogenetic Networks
18              
19             =head1 SYNOPSIS
20              
21             use strict;
22             use warnings;
23              
24             use Bio::PhyloNetwork;
25             use Bio::PhyloNetwork::Factory;
26              
27             # Will generate sequentially all the 4059 binary tree-child phylogenetic
28             # networks with 4 leaves
29              
30             my $factory=Bio::PhyloNetwork::Factory->new(-numleaves=>4);
31              
32             my @nets;
33              
34             while (my $net=$factory->next_network()) {
35             push @nets,$net;
36             print "".(scalar @nets).": ".$net->eNewick()."\n";
37             }
38              
39             =head1 DESCRIPTION
40              
41             Sequentially builds a (binary tree-child) phylogenetic network each time
42             next_network is called.
43              
44             =head1 AUTHOR
45              
46             Gabriel Cardona, gabriel(dot)cardona(at)uib(dot)es
47              
48             =head1 SEE ALSO
49              
50             L
51              
52             =head1 APPENDIX
53              
54             The rest of the documentation details each of the object methods.
55              
56             =cut
57              
58             package Bio::PhyloNetwork::Factory;
59              
60 1     1   357 use strict;
  1         2  
  1         23  
61 1     1   3 use warnings;
  1         1  
  1         21  
62              
63 1     1   3 use base qw(Bio::Root::Root);
  1         2  
  1         56  
64              
65 1     1   3 use Bio::PhyloNetwork;
  1         2  
  1         17  
66 1     1   3 use Bio::PhyloNetwork::TreeFactory;
  1         1  
  1         514  
67              
68             =head2 new
69              
70             Title : new
71             Usage : my $factory = new Bio::PhyloNetwork::Factory();
72             Function: Creates a new Bio::PhyloNetwork::Factory
73             Returns : Bio::PhyloNetwork::RandomFactory
74             Args : -numleaves => integer
75             OR
76             -leaves => reference to an array (of leaves names)
77             -numhybrids => integer [default = numleaves -1]
78             -recurse => boolean [optional]
79              
80             Returns a Bio::PhyloNetwork::Factory object. Such an object will
81             sequentially create binary tree-child phylogenetic networks
82             each time next_network is called.
83              
84             If the parameter -leaves=E\@leaves is given, then the set of leaves of
85             these networks will be @leaves. If it is given the parameter
86             -numleaves=E$numleaves, then the set of leaves will be "l1"..."l$numleaves".
87              
88             If the parameter -numhybrids=E$numhybrids is given, then the generated
89             networks will have at most $numhybrids hybrid nodes. Note that, necessarily,
90             $numhybrids E $numleaves.
91              
92             If the parameter -recurse=E1 is given, then all networks with number of hybrid
93             nodes less or equal to $numhybrids will be given; otherwise only those with
94             exactly $numhybrids hybrid nodes.
95              
96             =cut
97              
98             sub new {
99 2     2 1 124 my ($pkg,@args)=@_;
100              
101 2         14 my $self=$pkg->SUPER::new(@args);
102              
103 2         10 my ($leavesR,$numleaves,$numhybrids,$recurse)=
104             $self->_rearrange([qw(LEAVES
105             NUMLEAVES
106             NUMHYBRIDS
107             RECURSE)],@args);
108 2         4 my @leaves;
109 2 100 66     8 if ((! defined $leavesR) && (defined $numleaves)) {
110 1         4 @leaves=map {"l$_"} (1..$numleaves);
  3         5  
111 1         3 $leavesR=\@leaves;
112             }
113 2 50       4 if (! defined $leavesR) {
114 0         0 $self->throw("No leaves set neither numleaves given");
115             }
116 2         5 @leaves=@$leavesR;
117 2         3 $self->{leaves}=$leavesR;
118 2         1 $numleaves=@leaves;
119 2         3 $self->{numleaves}=$numleaves;
120              
121 2   100     6 $recurse ||= 0;
122 2 100       5 if (! defined $numhybrids) {
123 1         3 $numhybrids=$numleaves-1;
124 1         2 $recurse=1;
125             }
126 2         1 $self->{recurse}=$recurse;
127 2         4 $self->{numhybrids}=$numhybrids;
128 2 50       8 if ($numhybrids ==0) {
129 0         0 return Bio::PhyloNetwork::TreeFactory->new(-leaves=>\@leaves);
130             }
131 2         50 my $parent;
132 2 100       5 if ($numhybrids > 1) {
133 1         5 $parent=new($pkg,'-leaves'=>\@leaves,
134             '-numhybrids'=>($numhybrids-1),
135             '-recurse'=>($recurse));
136             }
137             else {
138 1         9 $parent=Bio::PhyloNetwork::TreeFactory->new(-leaves=>\@leaves);
139             }
140 2         4 $self->{parent}=$parent;
141 2         5 my $oldnet=$parent->next_network();
142 2         3 $self->{oldnet}=$oldnet;
143 2         4 $self->update();
144 2         2 $self->{found}=[];
145 2         7 bless($self,$pkg);
146             }
147              
148             sub update {
149 27     27 0 37 my ($self)=@_;
150              
151 27         85 my @candidates=$self->{oldnet}->edges();
152 27         2349 $self->{candidates}=\@candidates;
153 27         154 $self->{numcandidates}=(scalar @candidates);
154 27         49 $self->{index1}=-$self->{recurse};
155 27         48 $self->{index2}=0;
156             }
157              
158             =head2 next_network
159              
160             Title : next_network
161             Usage : my $net=$factory->next_network()
162             Function: returns a network
163             Returns : Bio::PhyloNetwork
164             Args : none
165              
166             =cut
167              
168             sub next_network {
169 92     92 1 1182 my ($self)=@_;
170 92         139 my $numleaves=$self->{numleaves};
171 92         128 my $numhybrids=$self->{numhybrids};
172             START:
173 1134 100       1887 if ($self->{index1}==-1) {
174 27         34 $self->{index1}++;
175 27         136 return $self->{oldnet};
176             }
177 1107 100       1659 if ($self->{index1} >= $self->{numcandidates}) {
178 162         170 $self->{index2}++;
179 162         200 $self->{index1}=0;
180             }
181 1107 100       1655 if ($self->{index2} >= $self->{numcandidates}) {
182 27         98 my $oldnet=$self->{parent}->next_network();
183 27 100       94 if (! $oldnet) {
184 2         7 return 0;
185             }
186 25         106 $self->{oldnet}=$oldnet;
187 25         85 $self->update();
188 25         114 goto START;
189             }
190 1080 100       1891 if ((scalar $self->{oldnet}->hybrid_nodes())< $self->{numhybrids}-1) {
191 3         6 $self->{candidates}=[];
192 3         7 $self->{numcandidates}=0;
193 3         10 goto START;
194             }
195 1077         2108 my $u1=$self->{candidates}->[$self->{index1}]->[0];
196 1077         1069 my $v1=$self->{candidates}->[$self->{index1}]->[1];
197 1077         1096 my $u2=$self->{candidates}->[$self->{index2}]->[0];
198 1077         903 my $v2=$self->{candidates}->[$self->{index2}]->[1];
199 1077         883 my $lbl=$self->{numhybrids};
200 1077 100       1950 if ($self->{oldnet}->is_attackable($u1,$v1,$u2,$v2)) {
201 156         484 my $net=Bio::PhyloNetwork->new(-graph=>$self->{oldnet}->graph);
202 156         347 $net->do_attack($u1,$v1,$u2,$v2,$lbl);
203 156         382 $self->{index1}++;
204 156         146 my @found=@{$self->{found}};
  156         819  
205 156         230 foreach my $netant (@found) {
206 2977 100       3174 if ($net->is_mu_isomorphic($netant) ) {
207 93         783 goto START;
208             }
209             }
210 63         119 push @found,$net;
211 63         102 $self->{found}=\@found;
212 63         257 return $net;
213             }
214             else {
215 921         912 $self->{index1}++;
216 921         3289 goto START;
217             }
218             }
219              
220             1;