File Coverage

blib/lib/Algorithm/Genetic/Diploid/Experiment.pm
Criterion Covered Total %
statement 65 76 85.5
branch 8 14 57.1
condition n/a
subroutine 13 15 86.6
pod 12 12 100.0
total 98 117 83.7


line stmt bran cond sub pod time code
1             package Algorithm::Genetic::Diploid::Experiment;
2 2     2   11 use strict;
  2         3  
  2         67  
3 2     2   11 use Algorithm::Genetic::Diploid;
  2         3  
  2         49  
4 2     2   10 use base 'Algorithm::Genetic::Diploid::Base';
  2         5  
  2         2127  
5              
6             my $log = __PACKAGE__->logger;
7              
8             =head1 NAME
9              
10             Algorithm::Genetic::Diploid::Experiment - manages an evolutionary experiment
11              
12             =head1 METHODS
13              
14             =over
15              
16             =item new
17              
18             Constructor takes named arguments. Provides defaults for C (0.05),
19             C (0.60), C (0.35) and C (50).
20              
21             =cut
22              
23             sub new {
24             shift->SUPER::new(
25 1     1 1 8 'mutation_rate' => 0.05,
26             'crossover_rate' => 0.60,
27             'reproduction_rate' => 0.35,
28             'ngens' => 50,
29             'factory' => Algorithm::Genetic::Diploid::Factory->new,
30             'population' => undef,
31             'env' => undef,
32             @_
33             );
34             }
35              
36             =item initialize
37              
38             Sets up the experiment based on the provided arguments:
39              
40             'individual_count' => number of individuals in the population, default is 50
41             'chromosome_count' => number of chromosome pairs per individual, default is 1
42             'gene_count' => number of genes per chromosome, default is 1
43              
44             =cut
45              
46             sub initialize {
47 1     1 1 16 my $self = shift;
48 1         5 my %args = (
49             'individual_count' => 50,
50             'chromosome_count' => 1,
51             'gene_count' => 1,
52             @_
53             );
54 1         10 my $fac = $self->factory;
55 1         11 my $pop = $fac->create_population;
56            
57             # create individuals
58 1         3 my @individuals;
59 1         3 for my $i ( 1 .. $args{'individual_count'} ) {
60 50         262 push @individuals, $fac->create_individual( 'experiment' => $self );
61            
62             # create chromosomes in homologous pairs
63 50         114 my @chromosomes;
64 50         107 for my $j ( 1 .. $args{'chromosome_count'} ) {
65 50         77 for ( 1 .. 2 ) {
66 100         547 push @chromosomes, $fac->create_chromosome(
67             'number' => $j,
68             'experiment' => $self,
69             );
70            
71             # create genes
72 100         143 my @genes;
73 100         211 for my $k ( 1 .. $args{'gene_count'} ) {
74 100         537 push @genes, $fac->create_gene(
75             'experiment' => $self,
76             );
77             }
78 100         356 $chromosomes[-1]->genes(@genes);
79             }
80             }
81 50         192 $individuals[-1]->chromosomes(@chromosomes);
82             }
83 1         10 $pop->individuals(@individuals);
84 1         13 $self->population($pop);
85             }
86              
87             =item optimum
88              
89             Should be overridden in order to define an optimum fitness value at the provided
90             generation.
91              
92             =cut
93              
94             sub optimum {
95 0     0 1 0 my ( $self, $gen ) = @_;
96             # do something with env and generation
97 0         0 return my $optimum;
98             }
99              
100             =item factory
101              
102             Getter and setter for a L object (or subclass
103             thereof), which instantiates other objects.
104              
105             =cut
106              
107             sub factory {
108 1     1 1 2 my $self = shift;
109 1 50       3 $self->{'factory'} = shift if @_;
110 1         10 return $self->{'factory'};
111             }
112              
113             =item env
114              
115             Getter and setter for a data object that gets passed to the gene functions
116              
117             =cut
118              
119             sub env {
120 50     50 1 93 my $self = shift;
121 50 50       127 $self->{'env'} = shift if @_;
122 50         225 return $self->{'env'};
123             }
124              
125             =item reproduction_rate
126              
127             Getter and setter for the fraction of individuals in the population that
128             gets to reproduce
129              
130             =cut
131              
132             sub reproduction_rate {
133 50     50 1 98 my $self = shift;
134 50 50       161 $self->{'reproduction_rate'} = shift if @_;
135 50         279 return $self->{'reproduction_rate'};
136             }
137              
138             =item mutation_rate
139              
140             Amount of change to apply to the weight and/or function of a gene.
141              
142             =cut
143              
144             sub mutation_rate {
145 6070     6070 1 10799 my $self = shift;
146 6070 50       16829 $self->{'mutation_rate'} = shift if @_;
147 6070         20478 return $self->{'mutation_rate'};
148             }
149              
150             =item crossover_rate
151              
152             Getter and setter for the proportion of genes that crossover
153              
154             =cut
155              
156             sub crossover_rate {
157 5000     5000 1 12115 my $self = shift;
158 5000 50       14055 $self->{'crossover_rate'} = shift if @_;
159 5000         40633 return $self->{'crossover_rate'};
160             }
161              
162             =item ngens
163              
164             Getter and setter for the number of generations in the experiment
165              
166             =cut
167              
168             sub ngens {
169 1     1 1 3 my $self = shift;
170 1 50       5 if ( @_ ) {
171 0         0 $log->info("number of generations set to: @_");
172 0         0 $self->{'ngens'} = shift;
173             }
174 1         5 return $self->{'ngens'};
175             }
176              
177             =item population
178              
179             Getter and setter for the L object
180              
181             =cut
182              
183             sub population {
184 51     51 1 98 my $self = shift;
185 51 100       186 if ( @_ ) {
186 1         8 $log->debug("assigning new population: @_");
187 1         3 $self->{'population'} = shift;
188             }
189 51         255 return $self->{'population'};
190             }
191              
192             =item run
193              
194             Runs the experiment!
195              
196             =cut
197              
198             sub run {
199 1     1 1 10 my $self = shift;
200 1         9 my $log = $self->logger;
201            
202 1         12 $log->info("going to run experiment");
203 1         1 my @results;
204 1         9 for my $i ( 1 .. $self->ngens ) {
205 50         315 my $optimum = $self->optimum($i);
206            
207 50         499 $log->info("optimum at generation $i is $optimum");
208 50         332 my ( $fittest, $fitness ) = $self->population->turnover($i,$self->env,$optimum);
209 50         290 push @results, [ $fittest, $fitness ];
210             }
211 1         12 my ( $fittest, $fitness ) = map { @{ $_ } } sort { $a->[1] <=> $b->[1] } @results;
  50         46  
  50         91  
  216         317  
212 1         320 return $fittest, $fitness;
213             }
214              
215             =item genecount
216              
217             Returns the number of distinct genes that remained after an experiment.
218              
219             =cut
220              
221             sub genecount {
222 0     0 1   my $self = shift;
223 0           my %genes = map { $_->id => $_ }
  0            
224 0           map { $_->genes }
225 0           map { $_->chromosomes }
226 0           map { $_->individuals } $self->population;
227 0           return values %genes;
228             }
229              
230             =back
231              
232             =cut
233              
234             1;