AI-Genetic-Pro
view release on metacpan or search on metacpan
lib/AI/Genetic/Pro/MCE.pm view on Meta::CPAN
package AI::Genetic::Pro::MCE;
$AI::Genetic::Pro::MCE::VERSION = '1.009';
use warnings;
use strict;
use base qw( AI::Genetic::Pro );
#-----------------------------------------------------------------------
use Clone qw( clone );
use List::Util qw( shuffle );
use MCE( Sereal => 0 );
#use MCE::Loop;
use MCE::Map;
use MCE::Util;
#-----------------------------------------------------------------------
$Storable::Deparse = 1;
$Storable::Eval = 1;
#-----------------------------------------------------------------------
__PACKAGE__->mk_accessors( qw(
_pop
_tpl
));
#=======================================================================
sub new {
my ( $cls, $obj, $tpl ) = @_;
my $self = bless $obj, $cls;
#-------------------------------------------------------------------
$self->_init_mce;
$self->_init_pop;
#-------------------------------------------------------------------
$AI::Genetic::Pro::Array::Type::Native = 1 if $self->native;
#-------------------------------------------------------------------
delete $tpl->{ $_ } for qw( -history -mce -population -workers );
$self->_tpl( $tpl );
#-------------------------------------------------------------------
return $self;
}
#=======================================================================
sub _init_pop {
my ( $self ) = @_;
my $pop = int( $self->population / $self->workers );
my $rst = $self->population % $self->workers;
my @pop = ( $pop ) x $self->workers;
$pop[ 0 ] += $rst;
$self->_pop( \@pop );
}
#=======================================================================
sub _calculate_fitness_all {
my ($self) = @_;
# Faster version. Thanks to Mario Roy :-)
my %fit = mce_map_s {
$_ => $self->fitness()->( $self, $self->chromosomes->[ $_ ] )
} 0, $#{ $self->chromosomes };
# The old one
#my %fit = mce_map {
# $_ => $self->fitness()->( $self, $self->chromosomes->[ $_ ] )
# } 0 .. $#{ $self->chromosomes };
$self->_fitness( \%fit );
return;
}
#=======================================================================
sub _init_mce {
my ( $self ) = @_;
#-------------------------------------------------------------------
$self->workers( MCE::Util::get_ncpu() ) unless $self->workers;
#-------------------------------------------------------------------
MCE::Map->init(
chunk_size => 1, # Thanks Roy :-)
#chunk_size => q[auto], # The old one
max_workers => $self->workers,
posix_exit => 1, # Thanks Roy :-)
);
#-------------------------------------------------------------------
return;
}
#=======================================================================
sub init {
my ( $self, $val ) = @_;
#-------------------------------------------------------------------
my $pop = $self->population;
$self->population( 1 );
$self->SUPER::init( $val );
$self->population( $pop );
#-------------------------------------------------------------------
my $one = shift @{ $self->chromosomes };
my $tpl = $self->_tpl;
my @lst = mce_map {
my $arg = clone( $tpl );
$arg->{ -population } = $_;
my $gal = AI::Genetic::Pro->new( %$arg );
$gal->init( $val );
@{ $gal->_state };
} @{ $self->_pop };
#-------------------------------------------------------------------
return $self->_adopt( \@lst );
}
#=======================================================================
sub _adopt {
my ( $self, $lst ) = @_;
if( my $typ = $self->_package ){
for my $idx ( 0 .. $#$lst ){
$lst->[ $idx ]->[ 0 ] = $typ->make_with_packed( $lst->[ $idx ]->[ 0 ] );
bless $lst->[ $idx ]->[ 0 ], q[AI::Genetic::Pro::Chromosome];
}
}
my ( @chr, %fit, @rhc, %tif );
for my $sth ( @$lst ){
push @chr, $sth->[ 0 ];
$fit{ $#chr } = $sth->[ 1 ];
}
#@$lst = ( );
my @idx = shuffle 0 .. $#chr;
for my $i ( @idx ){
push @rhc, $chr[ $i ];
$tif{ $#rhc } = $fit{ $i };
}
$self->_fitness ( \%tif );
$self->chromosomes( \@rhc );
return;
}
#=======================================================================
sub _chunks {
my ( $self ) = @_;
my $cnt = 0;
my @chk;
for my $idx ( 0 .. $#{ $self->_pop } ){
my $pos = 0;
my %tmp = map { $pos++ => $self->_fitness->{ $_ } } $cnt .. $cnt + $self->_pop->[ $idx ] -1 ;
my @tmp = splice @{ $self->chromosomes }, 0, $self->_pop->[ $idx ];
$cnt += @tmp;
if( $self->_package ){
push @chk, [
[ map { ${ tied( @$_ ) } } @tmp ],
\%tmp,
];
}else{
push @chk, [
\@tmp,
\%tmp,
];
}
}
return \@chk;
}
#=======================================================================
sub evolve {
my ( $self, $generations ) = @_;
$generations ||= -1;
for(my $i = 0; $i != $generations; $i++){
# terminate ----------------------------------------------------
last if $self->terminate and $self->terminate->( $self );
# update generation --------------------------------------------
$self->generation($self->generation + 1);
# update history -----------------------------------------------
$self->_save_history;
my $tpl = $self->_tpl;
my @lst = mce_map {
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
my $ary = $_;
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
my $arg = clone( $tpl );
$arg->{ -population } = 1;
my $gal = AI::Genetic::Pro->new( %$arg );
$gal->init( 1 );
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
if( my $typ = $self->_package ){
for my $idx ( 0 .. $#{ $ary->[ 0 ] } ){
$ary->[ 0 ][ $idx ] = $typ->make_with_packed( $ary->[ 0 ][ $idx ] );
bless $ary->[ 0 ][ $idx ], q[AI::Genetic::Pro::Chromosome];
}
}
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
$gal->population ( scalar( @{ $ary->[ 0 ] } ) );
$gal->chromosomes( $ary->[ 0 ] );
$gal->_fitness ( $ary->[ 1 ] );
$gal->strict ( 0 );
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
$gal->evolve ( 1 );
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@{ $gal->_state };
} $self->_chunks;
$self->_adopt( \@lst );
}
return;
}
#=======================================================================
1;
( run in 0.608 second using v1.01-cache-2.11-cpan-4d50c553e7e )