use strict; use List::Util qw(shuffle); use Memoize; $|++; memoize('fitness'); my $pop_size = 100; my $string_size = @ARGV ? pop : 9; my $gen_size = (2 * int ($pop_size / 10)) || 2; my $generations = 1000; my $current_generation; my @parents; my @children; my @population = sort { fitness($b) <=> fitness($a) } map { randlist() } 1 .. $pop_size; while ( $current_generation++ < $generations and fitness($population[-1]) ) { @parents = @population[ select_parents() ]; push @children, crossover( splice(@parents, 0, 2) ) while @parents; @population[ select_children() ] = map { mutate($_) } @children; @population = sort { fitness($b) <=> fitness($a) } @population; cataclysm(\@population) if (rand() < .005); printf "\r%*s/%d : %3s" => length $generations, $current_generation, $generations, fitness($population[-1]); } print "\n$population[-1]"; print "\nEND\n"; ############ sub randlist { my $gene; for (0 .. $string_size) { $gene .= int rand ($string_size + 1); } return $gene; } sub fitness { local $_ = shift; my $diff; my $count; for my $n (0 .. $string_size) { $count = eval "tr/$n/$n/"; $diff += abs(substr($_,$n,1) - $count - 1); } return $diff; } sub select_children { my $total = $pop_size * ($pop_size + 1) / 2; my $rand; my @children; for (1 .. $gen_size) { $rand = int rand $total; for my $n (reverse(1 .. $pop_size)) { if ( ($rand -= $n) < 0 ) { push @children, -$n; last; } } } return @children; } sub select_parents { my @parents; my @children = select_children(); $parents[$_] = -$children[$_] - 1 for (0 .. $#children); return @parents; } sub crossover { my ($g1, $g2) = @_; my ($start, $end) = sort { $a <=> $b } map { int rand ($string_size + 1) } 1 .. 2; (substr( $g1, $start, $end - $start), substr( $g2, $start, $end - $start )) = (substr( $g2, $start, $end - $start), substr ( $g1, $start, $end - $start )); return ($g1, $g2); } sub mutate { my $gene = shift; for my $n ( 0 .. $string_size ) { substr( $gene, $n, 1 ) += (int rand 3) - 1 if (substr( $gene, $n, 1 ) < $string_size and rand() < .3); substr( $gene, $n, 1 ) = 1 if (substr( $gene, $n, 1) < 0); } return $gene; } sub cataclysm { my $population = shift; my @children; my @random; print "\rCATACLYSM!"; for (1 .. 3 * ($pop_size / $gen_size)) { push @random, randlist() for (1 .. $gen_size); @$population[ select_children() ] = @random; @$population = sort { fitness($b) <=> fitness($a) } @$population } }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Improving Evolutionary Algorithm (pangram)
by grinder (Bishop) on Feb 19, 2004 at 19:30 UTC | |
by jweed (Chaplain) on Feb 19, 2004 at 19:47 UTC | |
|
Re: Improving Evolutionary Algorithm
by delirium (Chaplain) on Feb 19, 2004 at 19:59 UTC | |
|
Re: Improving Evolutionary Algorithm
by blokhead (Monsignor) on Feb 19, 2004 at 20:09 UTC | |
by jmerelo (Sexton) on Nov 23, 2008 at 18:36 UTC | |
|
Re: Improving Evolutionary Algorithm
by tilly (Archbishop) on Feb 20, 2004 at 19:27 UTC | |
|
Re: Improving Evolutionary Algorithm (no code?(spoiler))
by BrowserUk (Patriarch) on Feb 20, 2004 at 21:55 UTC | |
by jweed (Chaplain) on Feb 21, 2004 at 04:08 UTC |