File Coverage

blib/lib/Algorithm/Evolutionary/Simple.pm
Criterion Covered Total %
statement 88 88 100.0
branch 6 6 100.0
condition 10 30 33.3
subroutine 15 15 100.0
pod 8 9 88.8
total 127 148 85.8


line stmt bran cond sub pod time code
1             package Algorithm::Evolutionary::Simple;
2              
3 2     2   61923 use warnings;
  2         5  
  2         84  
4 2     2   14 use strict;
  2         75  
  2         85  
5 2     2   11 use Carp qw(croak);
  2         8  
  2         295  
6              
7             our $VERSION = '0.1.1'; # SofEA edition
8              
9 2     2   12 use base 'Exporter';
  2         3  
  2         277  
10 2     2   2976 use Sort::Key::Top qw(rnkeytop) ;
  2         2669  
  2         2512  
11              
12             our @EXPORT_OK= qw( random_chromosome max_ones spin get_pool_roulette_wheel
13             get_pool_binary_tournament
14             produce_offspring mutate crossover single_generation );
15              
16              
17             # Module implementation here
18             sub random_chromosome {
19 32     32 1 26604 my $length = shift;
20 32         45 my $string = '';
21 32         75 for (1..$length) {
22 1024 100       1518 $string .= (rand >0.5)?1:0;
23             }
24 32         109 $string;
25             }
26              
27             sub max_ones {
28 93     93 1 29534 my $str=shift;
29 93         111 my $count = 0;
30 93         186 while ($str) {
31 2919         4952 $count += chop($str);
32             }
33 93         479 $count;
34             }
35              
36             sub get_pool_roulette_wheel {
37 2   33 2 1 526 my $population = shift || croak "No population here";
38 2   33     11 my $fitness_of = shift || croak "need stuff evaluated";
39 2   33     6 my $need = shift || croak "I need to know the new population size";
40              
41 2         4 my $total_fitness = 0;
42 2         39 map( $total_fitness += $fitness_of->{$_} , @$population );
43 2         51 my @wheel = map( $fitness_of->{$_}/$total_fitness, @$population);
44 2         12 my @slots = spin( \@wheel, scalar(@$population) );
45 2         7 my @pool;
46 2         3 my $index = 0;
47 2         12 do {
48 123         148 my $p = $index++ % @slots;
49 123         133 my $copies = $slots[$p];
50 123         226 for (1..$copies) {
51 64         213 push @pool, $population->[$p];
52             }
53             } while ( @pool < $need );
54            
55 2         35 @pool;
56             }
57              
58             sub get_pool_binary_tournament {
59 1   33 1 0 628 my $population = shift || croak "No population here";
60 1   33     6 my $fitness_of = shift || croak "need stuff evaluated";
61 1   33     4 my $need = shift || croak "I need to know the new population size";
62              
63 1         3 my $total_fitness = 0;
64 1         1 my @pool;
65 1         3 my $population_size = @$population;
66 1         2 do {
67 32         51 my $one = $population->[rand( $population_size )];
68 32         44 my $another = $population->[rand( $population_size )];
69 32 100       91 if ( $fitness_of->{$one} > $fitness_of->{$another} ) {
70 20         58 push @pool, $one;
71             } else {
72 12         36 push @pool, $another;
73             }
74             } while ( @pool < $need );
75            
76 1         18 @pool;
77             }
78              
79             sub spin {
80 2     2 1 5 my ( $wheel, $slots ) = @_;
81 2         38 my @slots = map( $_*$slots, @$wheel );
82 2         18 return @slots;
83             }
84              
85             sub produce_offspring {
86 3   33 3 1 818 my $pool = shift || croak "Pool missing";
87 3   33     11 my $offspring_size = shift || croak "Population size needed";
88 3         6 my @population = ();
89 3         4 my $population_size = scalar( @$pool );
90 3         14 for ( my $i = 0; $i < $offspring_size/2; $i++ ) {
91 47         72 my $first = $pool->[rand($population_size)];
92 47         57 my $second = $pool->[rand($population_size)];
93            
94 47         89 push @population, crossover( $first, $second );
95             }
96 3         9 map( $_ = mutate($_), @population );
97 3         44 return @population;
98             }
99              
100             sub mutate {
101 94     94 1 92 my $chromosome = shift;
102 94         125 my $mutation_point = int(rand( length( $chromosome )));
103 94 100       190 substr($chromosome, $mutation_point, 1,
104             ( substr($chromosome, $mutation_point, 1) eq 1 )?0:1 );
105 94         207 return $chromosome;
106             }
107              
108             sub crossover {
109 47     47 1 63 my ($chromosome_1, $chromosome_2) = @_;
110 47         54 my $length = length( $chromosome_1 );
111 47         68 my $xover_point_1 = int rand( $length - 2 );
112 47         62 my $range = 1 + int rand ( $length - $xover_point_1 );
113 47         76 my $swap_chrom = $chromosome_1;
114 47         91 substr($chromosome_1, $xover_point_1, $range,
115             substr($chromosome_2, $xover_point_1, $range) );
116 47         77 substr($chromosome_2, $xover_point_1, $range,
117             substr($swap_chrom, $xover_point_1, $range) );
118 47         207 return ( $chromosome_1, $chromosome_2 );
119             }
120              
121             sub single_generation {
122 1   33 1 1 9 my $population = shift || croak "No population";
123 1   33     5 my $fitness_of = shift || croak "No fitness";
124 1         1 my $population_size = @{$population};
  1         2  
125 1     32   22 my @best = rnkeytop { $fitness_of->{$_} } 2 => @$population; # Extract elite
  32         73  
126 1         6 my @reproductive_pool = get_pool_roulette_wheel( $population, $fitness_of, $population_size ); # Reproduce
127 1         7 my @offspring = produce_offspring( \@reproductive_pool, $population_size - 2 ); #Obtain offspring
128 1         5 unshift( @offspring, @best ); #Insert elite at the beginning
129 1         12 @offspring; # return
130             }
131              
132             "010101"; # Magic true value required at end of module
133             __END__