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   375 use strict;
  1         1  
  1         24  
61 1     1   4 use warnings;
  1         1  
  1         22  
62              
63 1     1   4 use base qw(Bio::Root::Root);
  1         1  
  1         57  
64              
65 1     1   5 use Bio::PhyloNetwork;
  1         1  
  1         19  
66 1     1   3 use Bio::PhyloNetwork::TreeFactory;
  1         2  
  1         555  
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 139 my ($pkg,@args)=@_;
100              
101 2         13 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         3 my @leaves;
109 2 100 66     7 if ((! defined $leavesR) && (defined $numleaves)) {
110 1         3 @leaves=map {"l$_"} (1..$numleaves);
  3         6  
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         2 $numleaves=@leaves;
119 2         3 $self->{numleaves}=$numleaves;
120              
121 2   100     6 $recurse ||= 0;
122 2 100       3 if (! defined $numhybrids) {
123 1         2 $numhybrids=$numleaves-1;
124 1         2 $recurse=1;
125             }
126 2         3 $self->{recurse}=$recurse;
127 2         2 $self->{numhybrids}=$numhybrids;
128 2 50       37 if ($numhybrids ==0) {
129 0         0 return Bio::PhyloNetwork::TreeFactory->new(-leaves=>\@leaves);
130             }
131 2         2 my $parent;
132 2 100       5 if ($numhybrids > 1) {
133 1         6 $parent=new($pkg,'-leaves'=>\@leaves,
134             '-numhybrids'=>($numhybrids-1),
135             '-recurse'=>($recurse));
136             }
137             else {
138 1         25 $parent=Bio::PhyloNetwork::TreeFactory->new(-leaves=>\@leaves);
139             }
140 2         3 $self->{parent}=$parent;
141 2         4 my $oldnet=$parent->next_network();
142 2         4 $self->{oldnet}=$oldnet;
143 2         4 $self->update();
144 2         3 $self->{found}=[];
145 2         6 bless($self,$pkg);
146             }
147              
148             sub update {
149 27     27 0 46 my ($self)=@_;
150              
151 27         92 my @candidates=$self->{oldnet}->edges();
152 27         3829 $self->{candidates}=\@candidates;
153 27         52 $self->{numcandidates}=(scalar @candidates);
154 27         56 $self->{index1}=-$self->{recurse};
155 27         53 $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 1020 my ($self)=@_;
170 92         133 my $numleaves=$self->{numleaves};
171 92         127 my $numhybrids=$self->{numhybrids};
172             START:
173 1134 100       2148 if ($self->{index1}==-1) {
174 27         46 $self->{index1}++;
175 27         117 return $self->{oldnet};
176             }
177 1107 100       1936 if ($self->{index1} >= $self->{numcandidates}) {
178 162         209 $self->{index2}++;
179 162         228 $self->{index1}=0;
180             }
181 1107 100       1724 if ($self->{index2} >= $self->{numcandidates}) {
182 27         78 my $oldnet=$self->{parent}->next_network();
183 27 100       101 if (! $oldnet) {
184 2         8 return 0;
185             }
186 25         101 $self->{oldnet}=$oldnet;
187 25         85 $self->update();
188 25         119 goto START;
189             }
190 1080 100       1897 if ((scalar $self->{oldnet}->hybrid_nodes())< $self->{numhybrids}-1) {
191 3         10 $self->{candidates}=[];
192 3         5 $self->{numcandidates}=0;
193 3         11 goto START;
194             }
195 1077         2365 my $u1=$self->{candidates}->[$self->{index1}]->[0];
196 1077         1419 my $v1=$self->{candidates}->[$self->{index1}]->[1];
197 1077         1376 my $u2=$self->{candidates}->[$self->{index2}]->[0];
198 1077         1462 my $v2=$self->{candidates}->[$self->{index2}]->[1];
199 1077         1171 my $lbl=$self->{numhybrids};
200 1077 100       2008 if ($self->{oldnet}->is_attackable($u1,$v1,$u2,$v2)) {
201 156         357 my $net=Bio::PhyloNetwork->new(-graph=>$self->{oldnet}->graph);
202 156         429 $net->do_attack($u1,$v1,$u2,$v2,$lbl);
203 156         308 $self->{index1}++;
204 156         197 my @found=@{$self->{found}};
  156         715  
205 156         266 foreach my $netant (@found) {
206 2968 100       3970 if ($net->is_mu_isomorphic($netant) ) {
207 93         852 goto START;
208             }
209             }
210 63         126 push @found,$net;
211 63         155 $self->{found}=\@found;
212 63         228 return $net;
213             }
214             else {
215 921         1290 $self->{index1}++;
216 921         4038 goto START;
217             }
218             }
219              
220             1;