README

NAME

Algorithm::Evolutionary::Simple - A simple evolutionary algorithm

SYNOPSIS

use Algorithm::Evolutionary::Simple;

# From resources/examples/max-ones.p6
my UInt :$length = 64;
my UInt :$population-size = 256;


my @initial-population = initialize( size => $population-size,
				     genome-length => $length );
my %fitness-of;

my $population = evaluate( population => @initial-population,
			   fitness-of => %fitness-of,
			   evaluator => &max-ones );

my $result = 0;
while $population.sort(*.value).reverse.[0].value < $length {
    $population = generation( population => $population,
			      fitness-of => %fitness-of,
			      evaluator => &max-ones,
			      population-size => $population-size) ;
    $result += $population-size;
    info(to-json( { best => best-fitness($population) } ));
}

say $result

DESCRIPTION

Algorithm::Evolutionary::Simple is a module for writing simple and quasi -canonical evolutionary algorithms in Raku. It uses binary representation, integer fitness (which is needed for the kind of data structure we are using) and a single fitness function.

It is intended mainly for demo purposes, although it's been actually used in research. In the future, more versions will be available.

It uses a fitness cache for storing and not reevaluating already seen chromosomes, so be mindful of memory bloat.

EXAMPLES

Go to resources/examples for examples. For instance , run max-ones.p6 or p-peaks.p6 there. You'll need to run

 zef  install --deps-only .

To install needed modules in that directory.

METHODS

initialize( UInt :genome-length --> Array ) is export

Creates the initial population of binary chromosomes with the indicated length; returns an array.

random-chromosome( UInt $length --> List )

Generates a random chromosome of indicated length. Returns a Seq of Bools

max-ones( @chromosome --> Int )

Returns the number of trues (or ones) in the chromosome.

leading-ones( @chromosome --> Int )

Returns the number of ones from the beginning of the chromosome.

royal-road( @chromosome )

That's a bumpy road, returns 1 for each block of 4 which has the same true or false value.

multi evaluate( :@population, :%fitness-of, :auto-t = False --> Mix ) is export

Evaluates the chromosomes, storing values in the fitness cache. If auto-t is set to 'True', uses autothreading for faster operation (if needed). In absence of that parameter, defaults to sequential.

sub evaluate-nocache( :@population, :$evaluator --> Mix )

Evaluates the population, returning a Mix, but does not use a cache. Intended mainly for concurrent operation.

get-pool-roulette-wheel( Mix need = $population.elems ) is export

Returns $need elements with probability proportional to its weight, which is fitness in this case.

mutation( @chromosome is copy --> Array )

Returns the chromosome with a random bit flipped.

crossover ( @chromosome1 is copy, @chromosome2 is copy ) returns List

Returns two chromosomes, with parts of it crossed over. Generally you will want to do crossover first, then mutation.

produce-offspring( @pool, $size = @pool.elems --> Seq ) is export

Produces offspring from an array that contains the reproductive pool; it returns a Seq.

produce-offspring-no-mutation( @pool, $size = @pool.elems --> Seq ) is export

Produces offspring from an array that contains the reproductive pool without using mutation; it returns a Seq.

best-fitness( $population )

Returns the fitness of the first element. Mainly useful to check if the algorithm is finished.

multi sub generation( :@population, :%fitness-of, :population-size = auto-t --> Mix )

Single generation of an evolutionary algorithm. The initial Mix has to be evaluated before entering here using the evaluate function. Will use auto-threading if $auto-t is True.

multi sub generation( :@population, :%fitness-of, :population-size = no-mutation --> Mix )

Single generation of an evolutionary algorithm. The initial Mix has to be evaluated before entering here using the evaluate function. Will not use mutation if that variable is set to True

sub generations-without-change( population )

Returns False if the number of generations in $generations has not been reached without changing; it returns True otherwise.

mix( population2, $size --> Mix ) is export

Mixes the two populations, returning a single one of the indicated size and with type Mix.

sub pack-individual( @individual --> Int )

Packs the individual in a single Int. The invidual must be binary, and the maximum length is 64.

sub unpack-individual( Int bits --> Array(Seq))

Unpacks the individual that has been packed previously using pack-individual

sub pack-population( @population --> Buf)

Packs a population, producing a buffer which can be sent to a channel or stored in a compact form.

sub unpack-population( Buf bits --> Array )

Unpacks the population that has been packed using pack-population

multi sub frequencies( $population)

$population can be an array or a Mix, in which case the keys are extracted. This returns the per-bit (or gene) frequency of one (or True) for the population.

multi sub frequencies-best( proportion = 2)

$population is a Mix, in which case the keys are extracted. This returns the per-bit (or gene) frequency of one (or True) for the population of the best part of the population; the size of the population will be divided by the $proportion variable.

sub generate-by-frequencies( $population-size, @frequencies )

Generates a population of that size with every gene according to the indicated frequency.

sub crossover-frequencies( @frequencies, @frequencies-prime --> Array )

Generates a new array with random elements of the two arrays that are used as arguments.

SEE ALSO

There is a very interesting implementation of an evolutionary algorithm in Algorithm::Genetic. Check it out.

This is also kind of a port of [Algorithm::Evolutionary::Simple to Perl6](https ://metacpan.org/release/Algorithm-Evolutionary-Simple), which has a few more goodies, but it's not simply a port, since most of the code is completely different.

AUTHOR

JJ Merelo [email protected]

COPYRIGHT AND LICENSE

Copyright 2018, 2019, 2022 JJ Merelo

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.

Algorithm::Evolutionary::Simple v0.0.8

A simple evolutionary algorithm

Authors

  • JJ Merelo

License

Artistic-2.0

Dependencies

Test Dependencies

Provides

  • Algorithm::Evolutionary::Fitness::P-Peaks
  • Algorithm::Evolutionary::Simple

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.