File Coverage

blib/lib/Algorithm/Evolutionary/Simple.pm
Criterion Covered Total %
statement 89 90 98.8
branch 8 8 100.0
condition 20 33 60.6
subroutine 15 16 93.7
pod 10 10 100.0
total 142 157 90.4


line stmt bran cond sub pod time code
1             package Algorithm::Evolutionary::Simple;
2              
3 2     2   38457 use warnings;
  2         5  
  2         61  
4 2     2   9 use strict;
  2         2  
  2         47  
5 2     2   8 use Carp qw(croak);
  2         8  
  2         168  
6              
7             our $VERSION = '0.2'; # Probably such an increase is not guaranteed, but...
8              
9 2     2   10 use base 'Exporter';
  2         2  
  2         178  
10 2     2   692 use Sort::Key::Top qw(rnkeytop) ;
  2         1780  
  2         1770  
11              
12             our @EXPORT_OK= qw( random_chromosome max_ones max_ones_fast spin
13             get_pool_roulette_wheel get_pool_binary_tournament
14             produce_offspring mutate crossover single_generation );
15              
16             # Module implementation here
17             sub random_chromosome {
18 32     32 1 9007 my $length = shift;
19 32         36 my $string = '';
20 32         62 for (1..$length) {
21 1024 100       1146 $string .= (rand >0.5)?1:0;
22             }
23 32         65 $string;
24             }
25              
26             sub max_ones {
27 125     125 1 18169 my $str=shift;
28 125         101 my $count = 0;
29 125         170 while ($str) {
30 3957         4757 $count += chop($str);
31             }
32 125         334 $count;
33             }
34              
35              
36             sub max_ones_fast {
37 0     0 1 0 ($_[0] =~ tr/1/1/);
38             }
39              
40             sub get_pool_roulette_wheel {
41 7   66 7 1 2942 my $population = shift || croak "No population here";
42 6   66     25 my $fitness_of = shift || croak "need stuff evaluated";
43 5   66     20 my $need = shift || croak "I need to know the new population size";
44 4   66     18 my $total_fitness = shift || croak "I need the total fitness";
45              
46 3         124 my @wheel = map( $fitness_of->{$_}/$total_fitness, @$population);
47 3         17 my @slots = spin( \@wheel, scalar(@$population));
48             # my $slots = scalar(@$population);
49             # my @slots = map( $_*$slots, @wheel );;
50 3         6 my @pool;
51 3         3 my $index = 0;
52 3         4 do {
53 221         168 my $p = $index++ % @slots;
54 221         158 my $copies = $slots[$p];
55 221         324 for (1..$copies) {
56 96         296 push @pool, $population->[$p];
57             }
58             } while ( @pool < $need );
59            
60 3         30 @pool;
61             }
62              
63             sub get_pool_binary_tournament {
64 4   66 4 1 2311 my $population = shift || croak "No population here";
65 3   66     17 my $fitness_of = shift || croak "need stuff evaluated";
66 2   66     18 my $need = shift || croak "I need to know the new population size";
67              
68 1         2 my $total_fitness = 0;
69 1         2 my @pool;
70 1         2 my $population_size = @$population;
71 1         2 do {
72 32         36 my $one = $population->[rand( $population_size )];
73 32         26 my $another = $population->[rand( $population_size )];
74 32 100       64 if ( $fitness_of->{$one} > $fitness_of->{$another} ) {
75 10         23 push @pool, $one;
76             } else {
77 22         44 push @pool, $another;
78             }
79             } while ( @pool < $need );
80            
81 1         21 @pool;
82             }
83              
84             sub spin {
85 3     3 1 6 my ( $wheel, $slots ) = @_;
86 3         49 return map( $_*$slots, @$wheel );
87             }
88              
89             sub produce_offspring {
90 4   33 4 1 1055 my $pool = shift || croak "Pool missing";
91 4   33     8 my $offspring_size = shift || croak "Population size needed";
92 4         4 my @population = ();
93 4         4 my $population_size = scalar( @$pool );
94 4         14 for ( my $i = 0; $i < $offspring_size/2; $i++ ) {
95 62         60 my $first = $pool->[rand($population_size)];
96 62         49 my $second = $pool->[rand($population_size)];
97            
98 62         66 push @population, crossover( $first, $second );
99             }
100 4         12 map( $_ = mutate($_), @population );
101 4         36 return @population;
102             }
103              
104             sub mutate {
105 124     124 1 86 my $chromosome = shift;
106 124         104 my $mutation_point = int(rand( length( $chromosome )));
107 124 100       187 substr($chromosome, $mutation_point, 1,
108             ( substr($chromosome, $mutation_point, 1) eq 1 )?0:1 );
109 124         183 return $chromosome;
110             }
111              
112             sub crossover {
113 62     62 1 41 my ($chromosome_1, $chromosome_2) = @_;
114 62         49 my $length = length( $chromosome_1 );
115 62         60 my $xover_point_1 = int rand( $length - 2 );
116 62         50 my $range = 1 + int rand ( $length - $xover_point_1 );
117 62         47 my $swap_chrom = $chromosome_1;
118 62         77 substr($chromosome_1, $xover_point_1, $range,
119             substr($chromosome_2, $xover_point_1, $range) );
120 62         76 substr($chromosome_2, $xover_point_1, $range,
121             substr($swap_chrom, $xover_point_1, $range) );
122 62         152 return ( $chromosome_1, $chromosome_2 );
123             }
124              
125             sub single_generation {
126 4   66 4 1 1994 my $population = shift || croak "No population";
127 3   66     19 my $fitness_of = shift || croak "No fitness cache";
128 2         4 my $total_fitness = shift;
129 2 100       6 if ( !$total_fitness ) {
130 1         11 map( $total_fitness += $fitness_of->{$_}, @$population);
131             }
132 2         4 my $population_size = @{$population};
  2         4  
133 2     64   29 my @best = rnkeytop { $fitness_of->{$_} } 2 => @$population; # Extract elite
  64         126  
134 2         13 my @reproductive_pool = get_pool_roulette_wheel( $population, $fitness_of,
135             $population_size, $total_fitness ); # Reproduce
136 2         8 my @offspring = produce_offspring( \@reproductive_pool, $population_size - 2 ); #Obtain offspring
137 2         8 unshift( @offspring, @best ); #Insert elite at the beginning
138 2         20 @offspring; # return
139             }
140              
141             "010101"; # Magic true value required at end of module
142             __END__