Hmmer2: Fixed a subtle bug where values set by a first HSP, that
[bioperl-live.git] / Bio / PhyloNetwork / Factory.pm
blob9c68a198fd62e1982b4b73af11e33e5961e4b116
2 # Module for Bio::PhyloNetwork::Factory
4 # Please direct questions and support issues to <bioperl-l@bioperl.org>
6 # Cared for by Gabriel Cardona <gabriel(dot)cardona(at)uib(dot)es>
8 # Copyright Gabriel Cardona
10 # You may distribute this module under the same terms as perl itself
12 # POD documentation - main docs before the code
14 =head1 NAME
16 Bio::PhyloNetwork::Factory - Module to sequentially generate
17 Phylogenetic Networks
19 =head1 SYNOPSIS
21 use strict;
22 use warnings;
24 use Bio::PhyloNetwork;
25 use Bio::PhyloNetwork::Factory;
27 # Will generate sequentially all the 4059 binary tree-child phylogenetic
28 # networks with 4 leaves
30 my $factory=Bio::PhyloNetwork::Factory->new(-numleaves=>4);
32 my @nets;
34 while (my $net=$factory->next_network()) {
35 push @nets,$net;
36 print "".(scalar @nets).": ".$net->eNewick()."\n";
39 =head1 DESCRIPTION
41 Sequentially builds a (binary tree-child) phylogenetic network each time
42 next_network is called.
44 =head1 AUTHOR
46 Gabriel Cardona, gabriel(dot)cardona(at)uib(dot)es
48 =head1 SEE ALSO
50 L<Bio::PhyloNetwork>
52 =head1 APPENDIX
54 The rest of the documentation details each of the object methods.
56 =cut
58 package Bio::PhyloNetwork::Factory;
60 use strict;
61 use warnings;
63 use base qw(Bio::Root::Root);
65 use Bio::PhyloNetwork;
66 use Bio::PhyloNetwork::TreeFactory;
68 =head2 new
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
76 -leaves => reference to an array (of leaves names)
77 -numhybrids => integer [default = numleaves -1]
78 -recurse => boolean [optional]
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.
84 If the parameter -leaves=E<gt>\@leaves is given, then the set of leaves of
85 these networks will be @leaves. If it is given the parameter
86 -numleaves=E<gt>$numleaves, then the set of leaves will be "l1"..."l$numleaves".
88 If the parameter -numhybrids=E<gt>$numhybrids is given, then the generated
89 networks will have at most $numhybrids hybrid nodes. Note that, necessarily,
90 $numhybrids E<lt> $numleaves.
92 If the parameter -recurse=E<gt>1 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.
96 =cut
98 sub new {
99 my ($pkg,@args)=@_;
101 my $self=$pkg->SUPER::new(@args);
103 my ($leavesR,$numleaves,$numhybrids,$recurse)=
104 $self->_rearrange([qw(LEAVES
105 NUMLEAVES
106 NUMHYBRIDS
107 RECURSE)],@args);
108 my @leaves;
109 if ((! defined $leavesR) && (defined $numleaves)) {
110 @leaves=map {"l$_"} (1..$numleaves);
111 $leavesR=\@leaves;
113 if (! defined $leavesR) {
114 $self->throw("No leaves set neither numleaves given");
116 @leaves=@$leavesR;
117 $self->{leaves}=$leavesR;
118 $numleaves=@leaves;
119 $self->{numleaves}=$numleaves;
121 $recurse ||= 0;
122 if (! defined $numhybrids) {
123 $numhybrids=$numleaves-1;
124 $recurse=1;
126 $self->{recurse}=$recurse;
127 $self->{numhybrids}=$numhybrids;
128 if ($numhybrids ==0) {
129 return Bio::PhyloNetwork::TreeFactory->new(-leaves=>\@leaves);
131 my $parent;
132 if ($numhybrids > 1) {
133 $parent=new($pkg,'-leaves'=>\@leaves,
134 '-numhybrids'=>($numhybrids-1),
135 '-recurse'=>($recurse));
137 else {
138 $parent=Bio::PhyloNetwork::TreeFactory->new(-leaves=>\@leaves);
140 $self->{parent}=$parent;
141 my $oldnet=$parent->next_network();
142 $self->{oldnet}=$oldnet;
143 $self->update();
144 $self->{found}=[];
145 bless($self,$pkg);
148 sub update {
149 my ($self)=@_;
151 my @candidates=$self->{oldnet}->edges();
152 $self->{candidates}=\@candidates;
153 $self->{numcandidates}=(scalar @candidates);
154 $self->{index1}=-$self->{recurse};
155 $self->{index2}=0;
158 =head2 next_network
160 Title : next_network
161 Usage : my $net=$factory->next_network()
162 Function: returns a network
163 Returns : Bio::PhyloNetwork
164 Args : none
166 =cut
168 sub next_network {
169 my ($self)=@_;
170 my $numleaves=$self->{numleaves};
171 my $numhybrids=$self->{numhybrids};
172 START:
173 if ($self->{index1}==-1) {
174 $self->{index1}++;
175 return $self->{oldnet};
177 if ($self->{index1} >= $self->{numcandidates}) {
178 $self->{index2}++;
179 $self->{index1}=0;
181 if ($self->{index2} >= $self->{numcandidates}) {
182 my $oldnet=$self->{parent}->next_network();
183 if (! $oldnet) {
184 return 0;
186 $self->{oldnet}=$oldnet;
187 $self->update();
188 goto START;
190 if ((scalar $self->{oldnet}->hybrid_nodes())< $self->{numhybrids}-1) {
191 $self->{candidates}=[];
192 $self->{numcandidates}=0;
193 goto START;
195 my $u1=$self->{candidates}->[$self->{index1}]->[0];
196 my $v1=$self->{candidates}->[$self->{index1}]->[1];
197 my $u2=$self->{candidates}->[$self->{index2}]->[0];
198 my $v2=$self->{candidates}->[$self->{index2}]->[1];
199 my $lbl=$self->{numhybrids};
200 if ($self->{oldnet}->is_attackable($u1,$v1,$u2,$v2)) {
201 my $net=Bio::PhyloNetwork->new(-graph=>$self->{oldnet}->graph);
202 $net->do_attack($u1,$v1,$u2,$v2,$lbl);
203 $self->{index1}++;
204 my @found=@{$self->{found}};
205 foreach my $netant (@found) {
206 if ($net->is_mu_isomorphic($netant) ) {
207 goto START;
210 push @found,$net;
211 $self->{found}=\@found;
212 return $net;
214 else {
215 $self->{index1}++;
216 goto START;