File Coverage

blib/lib/Algorithm/Genetic/Diploid/Individual.pm
Criterion Covered Total %
statement 59 59 100.0
branch 5 6 83.3
condition n/a
subroutine 12 12 100.0
pod 7 7 100.0
total 83 84 98.8


line stmt bran cond sub pod time code
1             package Algorithm::Genetic::Diploid::Individual;
2 2     2   17 use strict;
  2         6  
  2         264  
3 2     2   31 use List::Util qw'sum shuffle';
  2         4  
  2         427  
4 2     2   14 use Algorithm::Genetic::Diploid::Base;
  2         4  
  2         49  
5 2     2   10 use base 'Algorithm::Genetic::Diploid::Base';
  2         3  
  2         2338  
6              
7             my $log = __PACKAGE__->logger;
8              
9             =head1 NAME
10              
11             Algorithm::Genetic::Diploid::Individual - an individual that reproduces sexually
12              
13             =head1 METHODS
14              
15             =over
16              
17             =item new
18              
19             Constructor takes named arguments, sets a default, empty list of chromosomes and
20             a default child count of zero
21              
22             =cut
23              
24             sub new {
25             shift->SUPER::new(
26 2550     2550 1 20629 'chromosomes' => [],
27             'child_count' => 0,
28             @_,
29             );
30             }
31              
32             =item child_count
33              
34             Getter for the number of children
35              
36             =cut
37              
38             sub child_count {
39 30818     30818 1 109549 shift->{'child_count'};
40             }
41              
42             # private method to increment
43             # child count after breeding
44 5000     5000   8755 sub _increment_cc { shift->{'child_count'}++ }
45              
46             =item chromosomes
47              
48             Getter and setter for the list of chromosomes
49              
50             =cut
51              
52             sub chromosomes {
53 10051     10051 1 52719 my $self = shift;
54 10051 100       26488 if ( @_ ) {
55 50         357 $log->debug("assigning new chromosomes: @_");
56 50         136 $self->{'chromosomes'} = \@_;
57             }
58 10051         12405 return @{ $self->{'chromosomes'} }
  10051         40528  
59             }
60              
61             =item meiosis
62              
63             Meiosis produces a gamete, i.e. n chromosomes that have mutated and recombined
64              
65             =cut
66              
67             sub meiosis {
68 5000     5000 1 9831 my $self = shift;
69            
70             # this is basically mitosis: cloning of chromosomes
71 5000         22097 my @chro = map { $_->clone } $self->chromosomes;
  10000         27531401  
72 5000         27646729 $log->debug("have cloned ".scalar(@chro)." chromosomes (meiosis II)");
73            
74             # create pairs of homologous chromosomes, i.e. metafase
75 5000         13438 my @pairs;
76 5000         22642 for my $i ( 0 .. $#chro - 1 ) {
77 5000         24713 for my $j ( ( $i + 1 ) .. $#chro ) {
78 5000 50       36211 if ( $chro[$i]->number == $chro[$j]->number ) {
79 5000         31894 push @pairs, [ $chro[$i], $chro[$j] ];
80             }
81             }
82             }
83            
84             # recombination happens during metafase
85 5000         15763 for my $pair ( @pairs ) {
86 5000         31668 $pair->[0]->recombine( $pair->[1] );
87             }
88            
89             # telofase: homologues segregate
90 5000         16309 my @gamete = map { $_->[0] } map { [ shuffle @{ $_ } ] } @pairs;
  5000         16676  
  5000         7507  
  5000         33901  
91 5000         52543 return @gamete;
92             }
93              
94             =item breed
95              
96             Produces a new individual by mating the invocant with the argument
97              
98             =cut
99              
100             sub breed {
101 2500     2500 1 5545 my ( $self, $mate ) = @_;
102 2500         25754 $log->debug("going to breed $self with $mate");
103 2500         8589 $self->_increment_cc;
104 2500         5652 $mate->_increment_cc;
105 2500         5626 __PACKAGE__->new(
106             'chromosomes' => [ $self->meiosis, $mate->meiosis ]
107             );
108             }
109              
110             =item phenotype
111              
112             Expresses all the genes and weights them to produce a phenotype
113              
114             =cut
115              
116             sub phenotype {
117 2550     2550 1 3338 my ( $self, $env ) = @_;
118 2550         12770 $log->debug("computing phenotype in environment $env");
119 2550 100       6779 if ( not defined $self->{'phenotype'} ) {
120 2500         4985 my @genes = map { $_->genes } $self->chromosomes;
  5000         15501  
121 2500         4450 my $total_weight = sum map { $_->weight } @genes;
  5000         13514  
122 2500         4015 my $products = sum map { $_->weight * $_->express($env) } @genes;
  5000         13255  
123 2500         18488 $self->{'phenotype'} = $products / $total_weight;
124             }
125 2550         4795 return $self->{'phenotype'};
126             }
127              
128             =item fitness
129              
130             The fitness is the difference between the optimum and the phenotype
131              
132             =cut
133              
134             sub fitness {
135 2500     2500 1 4030 my ( $self, $optimum, $env ) = @_;
136 2500         8906 my $id = $self->id;
137 2500         4765 my $phenotype = $self->phenotype( $env );
138 2500         5622 my $diff = abs( $optimum - $phenotype );
139 2500         21923 $log->debug("fitness of $id against optimum $optimum is $diff");
140 2500         11549 return $diff;
141             }
142              
143             =back
144              
145             =cut
146              
147             1;