Algorithm-Genetic-Diploid

 view release on metacpan or  search on metacpan

lib/Algorithm/Genetic/Diploid/Base.pm  view on Meta::CPAN

=over

=item new

Base constructor for everyone, takes named arguments

=cut

sub new {
	my $package = shift;
	$logger->debug("instantiating new $package object");
	my %self = @_;
	$self{'id'} = $id++;
	
	# experiment is provided as an argument
	if ( $self{'experiment'} ) {
		$experiment = $self{'experiment'};
		delete $self{'experiment'};
	}
	
	# create the object

lib/Algorithm/Genetic/Diploid/Chromosome.pm  view on Meta::CPAN


=item genes

Sets and gets list of genes on the chromosome

=cut

sub genes {
	my $self = shift;
	if ( @_ ) {
		$log->debug("assigning new genes: @_");
		$self->{'genes'} = \@_;
	}
	return @{ $self->{'genes'} };
}

=item number

Sets and gets chromosome number, i.e. in humans that would be 1..22, X, Y

=cut

lib/Algorithm/Genetic/Diploid/Experiment.pm  view on Meta::CPAN


=item population

Getter and setter for the L<Algorithm::Genetic::Diploid::Population> object

=cut

sub population {
	my $self = shift;
	if ( @_ ) {
		$log->debug("assigning new population: @_");
		$self->{'population'} = shift;
	}
	return $self->{'population'};
}

=item run

Runs the experiment!

=cut

lib/Algorithm/Genetic/Diploid/Individual.pm  view on Meta::CPAN


=item chromosomes

Getter and setter for the list of chromosomes

=cut

sub chromosomes {
	my $self = shift;
	if ( @_ ) {
		$log->debug("assigning new chromosomes: @_");
		$self->{'chromosomes'} = \@_;
	}
	return @{ $self->{'chromosomes'} }
}

=item meiosis

Meiosis produces a gamete, i.e. n chromosomes that have mutated and recombined

=cut

sub meiosis {
	my $self = shift;
	
	# this is basically mitosis: cloning of chromosomes
	my @chro = map { $_->clone } $self->chromosomes;
	$log->debug("have cloned ".scalar(@chro)." chromosomes (meiosis II)");
	
	# create pairs of homologous chromosomes, i.e. metafase
	my @pairs;
	for my $i ( 0 .. $#chro - 1 ) {
		for my $j ( ( $i + 1 ) .. $#chro ) {
			if ( $chro[$i]->number == $chro[$j]->number ) {
				push @pairs, [ $chro[$i], $chro[$j] ];
			}	
		}
	}

lib/Algorithm/Genetic/Diploid/Individual.pm  view on Meta::CPAN

}

=item breed

Produces a new individual by mating the invocant with the argument

=cut

sub breed {
	my ( $self, $mate ) = @_;
	$log->debug("going to breed $self with $mate");
	$self->_increment_cc;
	$mate->_increment_cc;
	__PACKAGE__->new( 
		'chromosomes' => [ $self->meiosis, $mate->meiosis ] 
	);
}

=item phenotype

Expresses all the genes and weights them to produce a phenotype

=cut

sub phenotype {
	my ( $self, $env ) = @_;
	$log->debug("computing phenotype in environment $env");
	if ( not defined $self->{'phenotype'} ) {
		my @genes = map { $_->genes } $self->chromosomes;
		my $total_weight = sum map { $_->weight } @genes;
		my $products = sum map { $_->weight * $_->express($env) } @genes;
		$self->{'phenotype'} = $products / $total_weight;
	}
	return $self->{'phenotype'};
}

=item fitness

The fitness is the difference between the optimum and the phenotype

=cut

sub fitness {
	my ( $self, $optimum, $env ) = @_;
	my $id = $self->id;
	my $phenotype = $self->phenotype( $env );
	my $diff = abs( $optimum - $phenotype );
	$log->debug("fitness of $id against optimum $optimum is $diff");
	return $diff;
}

=back

=cut

1;

lib/Algorithm/Genetic/Diploid/Logger.pm  view on Meta::CPAN

=item INFO

Informational messages are transmitted.

=cut

sub INFO ()  { 3 }

=item DEBUG

Everything is transmitted, including debugging messages.

=cut

sub DEBUG () { 4 }

# constants mapped to string for AUTOLOAD
my %levels = (
	'fatal' => FATAL,
	'error' => ERROR,
	'warn'  => WARN,
	'info'  => INFO,
	'debug' => DEBUG,
);

sub _simple_formatter {
	my %args = @_;
	my ( $level, $sub, $file, $line, $msg ) = @args{('level','sub','file','line','msg')};
	return sprintf "%s %s\n", $level, $msg;
}

sub _verbose_formatter {
	my %args = @_;

lib/Algorithm/Genetic/Diploid/Logger.pm  view on Meta::CPAN

	my ( $level, $sub, $file, $line, $msg ) = @args{('level','sub','file','line','msg')};
	return sprintf "%s %s [%s] - %s\n", $level, $sub, $line, $msg;
}

# this is where methods such as $log->info ultimately are routed to
sub AUTOLOAD {
	my ( $self, $msg ) = @_;
	my $method = $AUTOLOAD;
	$method =~ s/.+://;
	
	# only proceed if method was one of fatal..debug
	if ( exists $levels{$method} ) {
		my ( $package, $file1up, $line1up, $subroutine ) = caller( 1 );
		my ( $pack0up, $filename, $line, $sub0up )       = caller( 0 );
		
		# calculate what the verbosity is for the current context
		# (either at sub, package or global level)
		my $verbosity;
		if ( exists $VERBOSE{$subroutine} ) {
			$verbosity = $VERBOSE{$subroutine};
		}

lib/Algorithm/Genetic/Diploid/Population.pm  view on Meta::CPAN

=item individuals

Getter and setter for the list of individuals

=cut

sub individuals {
	my $self = shift;
	if ( @_ ) {
		$self->{'individuals'} = \@_;
		$log->debug("assigning ".scalar(@_)." individuals to population");
	}
	return @{ $self->{'individuals'} };
}

=item turnover

Moves the population on to the next generation, i.e.
1. compute fitness of all individuals
2. mate up to reproduction rate in proportion to fitness

=cut

sub turnover {
	my ( $self, $gen, $env, $optimum ) = @_;
	my $log = $self->logger;
	$log->debug("going to breed generation $gen against optimum $optimum");
	
	# sort all individuals by fitness, creates array refs 
	# where 0 element is Individual, 1 element is its fitness
	my @fittest = sort { $a->[1] <=> $b->[1] } 
	               map { [ $_, $_->fitness($optimum,$env) ] } 
	               $self->individuals;
	$log->debug("sorted current generation by fitness");
	$log->info("*** fittest at generation $gen: ".$fittest[0]->[0]->phenotype($env));
	               
	# get the highest index of Individual 
	# that still gets to reproduce
	my $maxidx = int( $self->experiment->reproduction_rate * $#fittest );
	$log->debug("individuals up to index $maxidx will breed");
	
	# take the slice of Individuals that get to reproduce
	my @breeders = @fittest[ 0 .. $maxidx ];
	$log->debug("number of breeders: ".scalar(@breeders));
	
	# compute the total fitness, to know how much each breeder gets to
	# contribute to the next generation
	my $total_fitness = sum map { $_->[1] } @breeders;
	$log->debug("total fitness is $total_fitness");
	
	# compute the population size, which we need to divide up over the
	# breeders in proportion of their fitness relative to total fitness
	my $popsize = scalar $self->individuals;
	$log->debug("population size will be $popsize");
	
	# here we make breeding pairs
	my @children;
	ORGY: while( @children < $popsize ) {
		for my $i ( 0 .. $#breeders ) {
			my $quotum_i = $breeders[$i]->[1] / $total_fitness * $popsize * 2;
			for my $j ( 0 .. $#breeders ) {
				my $quotum_j = $breeders[$j]->[1] / $total_fitness * $popsize * 2;
				my $count_i  = $breeders[$i]->[0]->child_count;
				my $count_j  = $breeders[$j]->[0]->child_count;
				if ( $count_i < $quotum_i && $count_j < $quotum_j ) {
					push @children, $breeders[$i]->[0]->breed($breeders[$j]->[0]);
					$log->debug("bred child ".scalar(@children)." by pairing $i and $j");
					last ORGY if @children == $popsize;
				}				
			}
		}
	}
	
	my %genes = map { $_->id => 1 } map { $_->genes } map { $_->chromosomes } @children;
	$log->debug("generation $gen has ".scalar(keys(%genes))." distinct genes");
	
	# now the population consists of the children
	$self->individuals(@children);
	return @{ $fittest[0] };
}

=back

=cut



( run in 1.301 second using v1.01-cache-2.11-cpan-49f99fa48dc )