File Coverage

lib/Algorithm/Evolutionary/Op/Easy.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1 2     2   12 use strict; #-*-cperl-*-
  2         3  
  2         79  
2 2     2   11 use warnings;
  2         4  
  2         75  
3              
4 2     2   9 use lib qw( ../../.. );
  2         5  
  2         16  
5              
6             =head1 NAME
7              
8             Algorithm::Evolutionary::Op::Easy - evolutionary algorithm, single generation, with
9             variable operators.
10            
11              
12             =head1 SYNOPSIS
13              
14             my $easyEA = Algorithm::Evolutionary::Op::Base->fromXML( $ref->{initial}{section}{pop}{op} );
15             # Parsed XML fragment, see samples
16              
17             for ( my $i = 0; $i < $ref->{initial}{section}{pop}{op}{param}{maxgen}{value}; $i++ ) {
18             print "<", "="x 20, "Generation $i", "="x 20, ">\n";
19             $easyEA->apply(\@pop );
20             for ( @pop ) {
21             print $_->asString, "\n";
22             }
23             }
24              
25             #Define a default algorithm with predefined evaluation function,
26             #Mutation and crossover. Default selection rate is 0.4
27             my $algo = new Algorithm::Evolutionary::Op::Easy( $eval );
28              
29             #Define an easy single-generation algorithm with predefined mutation and crossover
30             my $m = new Algorithm::Evolutionary::Op::Bitflip; #Changes a single bit
31             my $c = new Algorithm::Evolutionary::Op::Crossover; #Classical 2-point crossover
32             my $generation = new Algorithm::Evolutionary::Op::Easy( $rr, 0.2, [$m, $c] );
33              
34             =head1 Base Class
35              
36             L
37              
38             =cut
39              
40             =head1 DESCRIPTION
41              
42             "Easy" to use, single generation of an evolutionary algorithm. Takes
43             an arrayref of operators as input, or defines bitflip-mutation and
44             2-point crossover as default. The C method applies a single
45             iteration of the algorithm to the population it takes as input
46              
47             =head1 METHODS
48              
49             =cut
50              
51             package Algorithm::Evolutionary::Op::Easy;
52              
53             our ($VERSION) = ( '$Revision: 3.4 $ ' =~ / (\d+\.\d+)/ ) ;
54              
55 2     2   413 use Carp;
  2         5  
  2         156  
56              
57 2     2   950 use Algorithm::Evolutionary::Wheel;
  2         6  
  2         68  
58 2     2   1220 use Algorithm::Evolutionary::Op::Bitflip;
  0            
  0            
59             use Algorithm::Evolutionary::Op::Crossover;
60              
61             use base 'Algorithm::Evolutionary::Op::Base';
62              
63             # Class-wide constants
64             our $APPLIESTO = 'ARRAY';
65              
66             =head2 new( $eval_func, [$operators_arrayref] )
67              
68             Creates an algorithm that optimizes the handled fitness function and
69             reference to an array of operators. If this reference is null, an
70             array consisting of bitflip mutation and 2 point crossover is
71             generated. Which, of course, might not what you need in case you
72             don't have a binary chromosome.
73              
74             =cut
75              
76             sub new {
77             my $class = shift;
78             my $self = {};
79             $self->{_eval} = shift || croak "No eval function found";
80             $self->{_selrate} = shift || 0.4;
81             if ( @_ ) {
82             $self->{_ops} = shift;
83             } else {
84             #Create mutation and crossover
85             my $mutation = new Algorithm::Evolutionary::Op::Bitflip;
86             push( @{$self->{_ops}}, $mutation );
87             my $xover = new Algorithm::Evolutionary::Op::Crossover;
88             push( @{$self->{_ops}}, $xover );
89             }
90             bless $self, $class;
91             return $self;
92              
93             }
94              
95             =head2 set( $hashref, codehash, opshash )
96              
97             Sets the instance variables. Takes a ref-to-hash (for options), codehash (for fitness) and opshash (for operators)
98              
99             =cut
100              
101             sub set {
102             my $self = shift;
103             my $hashref = shift || croak "No params here";
104             my $codehash = shift || croak "No code here";
105             my $opshash = shift || croak "No ops here";
106             $self->{_selrate} = $hashref->{selrate};
107              
108             for ( keys %$codehash ) {
109             $self->{"_$_"} = eval "sub { $codehash->{$_} } " || carp "Error compiling fitness function: $! => $@";
110             }
111              
112             $self->{_ops} =();
113             for ( keys %$opshash ) {
114             #First element of the array contains the content, second the rate.
115             push @{$self->{_ops}},
116             Algorithm::Evolutionary::Op::Base::fromXML( $_, $opshash->{$_}->[1], $opshash->{$_}->[0] );
117             }
118             }
119              
120             =head2 apply( $population )
121              
122             Applies the algorithm to the population; checks that it receives a
123             ref-to-array as input, croaks if it does not. Returns a sorted,
124             culled, evaluated population for next generation.
125              
126             =cut
127              
128             sub apply ($) {
129             my $self = shift;
130             my $pop = shift || croak "No population here";
131              
132             #Evaluate
133             my $eval = $self->{_eval};
134             my @ops = @{$self->{_ops}};
135             my @popEval;
136             for ( @$pop ) {
137             my $fitness; #Evaluates only those that have no fitness
138             if ( !defined ($_->Fitness() ) ) {
139             $_->evaluate( $eval );
140             }
141             push @popEval, $_;
142             }
143              
144             #Sort
145             my @popsort = sort { $b->{_fitness} <=> $a->{_fitness}; }
146             @popEval ;
147              
148             #Cull
149             my $pringaos = int(($#popsort+1)*$self->{_selrate}); #+1 gives you size
150             splice @popsort, -$pringaos;
151            
152             #Reproduce
153             my @rates = map( $_->{'rate'}, @ops );
154             my $opWheel = new Algorithm::Evolutionary::Wheel @rates;
155              
156             #Generate offpring;
157             my $originalSize = $#popsort; # Just for random choice
158             for ( my $i = 0; $i < $pringaos; $i ++ ) {
159             my @offspring;
160             my $selectedOp = $ops[ $opWheel->spin()];
161             croak "Problems with selected operator" if !$selectedOp;
162             for ( my $j = 0; $j < $selectedOp->arity(); $j ++ ) {
163             my $chosen = $popsort[ int ( rand( $originalSize ) )];
164             push( @offspring, $chosen ); #No need to clone, it's not changed in ops
165             }
166             # p rint "Op ", ref $selectedOp, "\n";
167             # if ( (ref $selectedOp ) =~ /ssover/ ) {
168             # print map( $_->{'_str'}."\n", @offspring );
169             # }
170             my $mutante = $selectedOp->apply( @offspring );
171             croak "Error aplying operator" if !$mutante;
172             # print "Mutante ", $mutante->{'_str'}, "\n";
173             push( @popsort, $mutante );
174             }
175              
176             #Return
177             @$pop = @popsort;
178            
179             }
180              
181             =head1 SEE ALSO
182              
183             L.
184             L.
185              
186              
187             =head1 Copyright
188            
189             This file is released under the GPL. See the LICENSE file included in this distribution,
190             or go to http://www.fsf.org/licenses/gpl.txt
191              
192             CVS Info: $Date: 2011/02/14 06:55:36 $
193             $Header: /cvsroot/opeal/Algorithm-Evolutionary/lib/Algorithm/Evolutionary/Op/Easy.pm,v 3.4 2011/02/14 06:55:36 jmerelo Exp $
194             $Author: jmerelo $
195             $Revision: 3.4 $
196             $Name $
197              
198             =cut
199              
200             "The truth is out there";