Skip to content

Instantly share code, notes, and snippets.

@jaldhar
Created July 27, 2017 07:10
Show Gist options
  • Save jaldhar/bae299ee03df93fcdd3633d751581e0b to your computer and use it in GitHub Desktop.
Save jaldhar/bae299ee03df93fcdd3633d751581e0b to your computer and use it in GitHub Desktop.

Revisions

  1. jaldhar created this gist Jul 27, 2017.
    75 changes: 75 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,75 @@
    =begin pod

    Algorithm::DawkinsWeasel is a simple model illustrating the idea of cumulative
    selection in evolution.

    The original form of it looked like this:

    1. Start with a random string of 28 characters.
    2. Make 100 copies of this string, with a 5% chance per character of that
    character being replaced with a random character.
    3. Compare each new string with "METHINKS IT IS LIKE A WEASEL", and give
    each a score (the number of letters in the string that are correct and
    in the correct position).
    4. If any of the new strings has a perfect score (== 28), halt.
    5. Otherwise, take the highest scoring string, and go to step 2

    This module parametrizes the target string, mutation threshold, and number of
    copies per round.

    The goal is to be able to use it something like this:

    my $weasel = Algorithm::DawkinsWeasel.new;
    say $weasel.current-phrase while $weasel;

    =end pod
    unit class Algorithm::DawkinsWeasel:ver<0.0.2> does Iterator;

    has Str @.target-phrase;
    has Rat $.mutation-threshold;
    has Int $.copies;

    has Str @!charset;
    has Int $!count;
    has Str @!current-phrase;
    has Int $!hi-score;
    submethod BUILD(Str :$target-phrase = 'METHINKS IT IS LIKE A WEASEL',
    Rat :$mutation-threshold = 0.05, Int :$copies = 100) {
    @!target-phrase = $target-phrase.comb;
    $!mutation-threshold = $mutation-threshold;
    $!copies = $copies;
    }

    submethod TWEAK {
    @!charset = | ['A' .. 'Z'] , ' ';
    @!current-phrase = map { @!charset.pick }, 0 .. @!target-phrase.end;
    $!hi-score = 0;
    $!count = 0;
    }

    method evolve {
    for (1 .. $!copies) {
    my @trial = map {
    1.rand < $!mutation-threshold ?? @!charset.pick !! $_;
    }, @!current-phrase;

    my Int $score = 0;
    for 0 .. @!target-phrase.end -> $i {
    if @trial[$i] eq @!target-phrase[$i] {
    $score++;
    }
    }

    if $score > $!hi-score {
    $!hi-score = $score;
    @!current-phrase = @trial;
    }
    }
    }

    method pull-one {
    $!count++;

    self.evolve;
    return $!hi-score == @!target-phrase.elems ?? IterationEnd !! self;
    }