use strict;
use warnings;
=head1 NAME
Algorithm::Evolutionary::Op::GeneralGeneration - Customizable single generation for an evolutionary algorithm.
=head1 SYNOPSIS
#Taken from the t/general.t file, verbatim
my $m = new Algorithm::Evolutionary::Op::Bitflip; #Changes a single bit
my $c = new Algorithm::Evolutionary::Op::Crossover; #Classical 2-point crossover
my $replacementRate = 0.3; #Replacement rate
use Algorithm::Evolutionary::Op::RouletteWheel;
my $popSize = 20;
my $selector = new Algorithm::Evolutionary::Op::RouletteWheel $popSize; #One of the possible selectors
use Algorithm::Evolutionary::Op::GeneralGeneration;
my $onemax = sub {
my $indi = shift;
my $total = 0;
for ( my $i = 0; $i < $indi->length(); $i ++ ) {
$total += substr( $indi->{_str}, $i, 1 );
}
return $total;
};
my @pop;
my $numBits = 10;
for ( 0..$popSize ) {
my $indi = new Algorithm::Evolutionary::Individual::BitString $numBits ; #Creates random individual
my $fitness = $onemax->( $indi );
$indi->Fitness( $fitness );
push( @pop, $indi );
}
my $generation =
new Algorithm::Evolutionary::Op::GeneralGeneration( $onemax, $selector, [$m, $c], $replacementRate );
my @sortPop = sort { $a->Fitness() <=> $b->Fitness() } @pop;
my $bestIndi = $sortPop[0];
$generation->apply( \@sortPop );
=head1 Base Class
L<Algorithm::Evolutionary::Op::Base|Algorithm::Evolutionary::Op::Base>
=head1 DESCRIPTION
Genetic algorithm that uses the other component. Must take as input the operators thar are going to be
used, along with its priorities
=head1 METHODS
=cut
package Algorithm::Evolutionary::Op::GeneralGeneration;
use lib qw(../../..);
our $VERSION = '3.2';
use Carp;
use base 'Algorithm::Evolutionary::Op::Base';
use Algorithm::Evolutionary::Wheel;
# Class-wide constants
our $APPLIESTO = 'ARRAY';
our $ARITY = 1;
=head2 new( $evaluation_function, $selector, $ref_to_operator_array, $replacement_rate )
Creates an algorithm, with the usual operators. Includes a default mutation
and crossover, in case they are not passed as parameters
=cut
sub new {
my $class = shift;
my $self = {};
$self->{'_eval'} = shift || croak "No eval function found";
$self->{'_selector'} = shift || croak "No selector found";
$self->{'_ops'} = shift || croak "No operator found";
$self->{'_replacementRate'} = shift || 1; #Default to all replaced
bless $self, $class;
return $self;
}
=head2 set( $ref_to_params_hash, $ref_to_code_hash, $ref_to_operators_hash )
Sets the instance variables. Takes a ref-to-hash as
input
=cut
sub set {
my $self = shift;
my $hashref = shift || croak "No params here";
my $codehash = shift || croak "No code here";
my $opshash = shift || croak "No ops here";
$self->{_selrate} = $hashref->{selrate};
for ( keys %$codehash ) {
$self->{"_$_"} = eval "sub { $codehash->{$_} } ";
}
$self->{_ops} =();
for ( keys %$opshash ) {
push @{$self->{_ops}},
Algorithm::Evolutionary::Op::Base::fromXML( $_, $opshash->{$_}->[1], $opshash->{$_}->[0] ) ;
}
}
=head2 apply( $population )
Applies the algorithm to the population, which should have
been evaluated first; checks that it receives a
ref-to-array as input, croaks if it does not. Returns a sorted,
culled, evaluated population for next generation.
=cut
sub apply ($) {
my $self = shift;
my $pop = shift || croak "No population here";
croak "Incorrect type ".(ref $pop) if ref( $pop ) ne $APPLIESTO;
#Evaluate only the new ones
my $eval = $self->{_eval};
my @ops = @{$self->{_ops}};
#Breed
my $selector = $self->{_selector};
my @genitors = $selector->apply( @$pop );
#Reproduce
my $totRate = 0;
my @rates;
for ( @ops ) {
push( @rates, $_->{rate});
}
my $opWheel = new Algorithm::Evolutionary::Wheel @rates;
my @newpop;
my $pringaos = @$pop * $self->{'_replacementRate'} ;
for ( my $i = 0; $i < $pringaos; $i++ ) {
my @offspring;
my $selectedOp = $ops[ $opWheel->spin()];
# print $selectedOp->asXML;
for ( my $j = 0; $j < $selectedOp->arity(); $j ++ ) {
my $chosen = $genitors[ rand( @genitors )];
# print "Elegido ", $chosen->asString(), "\n";
push( @offspring, $chosen->clone() );
}
my $mutante = $selectedOp->apply( @offspring );
push( @newpop, $mutante );
}
#Eliminate and substitute
splice( @$pop, -$pringaos );
for ( @newpop ) {
$_->evaluate( $eval );
}
push @$pop, @newpop;
my @sortPop = sort { $b->{'_fitness'} <=> $a->{'_fitness'}; } @$pop;
@$pop = @sortPop;
}
=head1 SEE ALSO
=over 4
=item *
A more modern and flexible version: L<Algorithm::Evolutionary::Op::Generation_Skeleton>.
=item *
L<Algorithm::Evolutionary::Op::CanonicalGA>.
=item *
L<Algorithm::Evolutionary::Op::FullAlgorithm>.
=back
=head1 Copyright
This file is released under the GPL. See the LICENSE file included in this distribution,
or go to http://www.fsf.org/licenses/gpl.txt
=cut
"The truth is out there";