#!/usr/bin/env perl use strict; our $debug = 0; our %taken; our $length = 0; our $round_size = 100; our $maxstack = 150; our $working_mfactor = 0; our $best_mfactor = 0; our $best_vector; our $refill = 0; our $maxrounds = 20; our @winners; our $winnercompare = 10; our $total = 0; sub message { our $debug; my $level = shift; my $message = shift; if ( $level => $debug ) { print "DEBUG [$level]: $message\n"; } } sub merit { my $y = shift; our $length; my $e = 0; my $f; my $t; foreach my $k (1 .. ($length - 1)) { $t = 0; for my $i (0 .. ($length - 1 - $k)) { $t += $$y[$i] * $$y[$i+$k]; } $e += $t ** 2; } $f = ($length ** 2) / ( 2 * $e); printer('DEBUG merit', $f, $y) if $debug > 5; return($f); } sub randarray { our $debug; my @output = (); my ($i,$v); message(1,"New randarray of length $length"); foreach $i ( 0 .. ($length - 1)) { $v = int(rand() + 0.5); $output[$i] = ( $v ) ? 1 : -1; } return(\@output); } sub flip { my $rref = shift; my $number = shift; my $v = $$rref[$number]; $v = ($v == 1) ? -1 : 1; $$rref[$number] = $v; } sub try_merit { our @stack; our %taken; our $best_mfactor; our $best_vector; our $working_mfactor; my $try_array = shift; my $new_mfactor; my $result = 0; my $array2string = join('',@{$try_array}); if ( not exists ($taken{$array2string}) ) { $new_mfactor = merit($try_array); $taken{$array2string} = $new_mfactor; if ($new_mfactor > $best_mfactor) { $best_mfactor = $new_mfactor; $best_vector = $try_array; $result = 1; unshift(@stack,$try_array); } } if ( $debug == 5 ) { print "==== " . scalar(@stack) . "====\n"; print join("\n",@stack) . "\n"; } return($result); } sub combine { our $length; our $debug; message(1,"Working on combine"); my $result = 0; my $loop; my $input = shift; my $input2 = shift; my @result_l; my @result_r; my $middle = int($length / 2); @result_l = (@{$input}[0 .. $middle], @{$input2}[ $middle + 1 .. ($length-1) ]); @result_r = (@{$input2}[0 .. $middle], @{$input}[ $middle + 1 .. ($length-1) ]); if ($debug > 3) { print "Orig l: "; print @{$input}; print "\n"; print "Orig 2: "; print @{$input2}; print "\n"; print "Combine l: "; print @result_l; print "\n"; print "Combine r: "; print @result_r; print "\n"; } message(1,"DEBUG: Done on combine"); return(\@result_l,\@result_r); } sub crossover { my $input = shift; my $rev_array = shift; my $result = 0; my ($try_array_l,$try_array_r) = combine($input,$rev_array); if ( try_merit($try_array_l) ) { $result = 1; } if ( try_merit($try_array_r) ) { $result = 1; } return($result); } sub mutations { our $length; my @try_array; my $result = 0; my @test_array = @_; message(1,"Working on mutations"); foreach my $i ( 0 .. ($length - 1) ) { my @try_array = (); @try_array = @test_array; flip(\@try_array, $i); if ( try_merit(\@try_array) ) { $result = 1; } } message(1,"Done on mutations"); return($result) ; } sub crossovers { our $length; my @try_array; my $result = 0; my @test_array = @_; my $i; my $j; message(1,"Working on crossovers"); foreach $i ( 0 .. ($length - 1) ) { my @try_array = (); @try_array = @test_array; foreach $j ( $i .. ($length - 1) ) { flip(\@try_array, $j); } if ( try_merit(\@try_array) ) { $result = 1; } } message(1,"Done on crossovers"); return($result); } sub randmutate { our $length; my $switchtimes = shift; my $switchnumbers = shift; my @test_array = @_; my $result = 0; my @try_array; my $i; my $j; my $n; my @flipped; message(1,"Working on randmutate"); foreach $i ( 0 .. $switchtimes ) { my @try_array = (); @try_array = @test_array; @flipped = (); foreach $j ( 0 .. $switchnumbers ) { $n = int(rand($length - 1)); if ( not exists $flipped[$n] ) { flip(\@try_array,$n); $flipped[$n] = 1; } } if ( try_merit(\@try_array) ) { $result = 1; } } return($result); } sub printer { my $message = shift; my $mfactor = shift; my $input = shift; return("Message : $message \n" . "Vector : " . join(',',array2string($input) . "\n" . "mfactor : $mfactor \n" . "--\n"); } our @stack = (); our $best_mfactor = 0; our $best_vector; sub array2string { my $input = shift; my @result = (); my $n = 1; foreach my $i (1 .. $#$input) { if ($$input[$i] != $$input[$i - 1]) { push(@result,$n); $n = 1; } else { $n++; } } push(@result,$n); return(@result); } sub string2array { my @output = (); my $input = shift; $input = split(//,$input); my $c = 0; my $v = 1; my ($n,$i); for $n ( 0 .. length($input) - 1) { for $i ( 1 .. @{$input}[$n] ) { $output[$c] = $v; $c++; } $v = ( $v == 1) ? -1 : 1; } return(@output); } # # Vul de stack met een random arrays sub init { our $length = shift; our @stack; our $best_mfactor; my ($n,$y); @stack = (); $best_mfactor = 0; foreach $n ( 1 .. 75 ) { $y = randarray(); push(@stack,$y); } } sub reinit { our $refill; our $winnercompare; our $length; our @winners; our %taken; our @stack; our $best_vector; our $best_mfactor; my $maxwinners = 5; my ($result_l,$result_r); my ($i,$j); my ($n,$y); my ($r); %taken = (); @stack = (); $refill++; #push best array on good place $i = merit($best_vector); print printer("Round best vector",$i,$best_vector); my $ws = $#winners - 1; my $done = 0; foreach $n ( 0 .. $ws ) { $j = merit($winners[$n]); if ( $i > $j ) { foreach $r ($ws .. ($n + 1)) { $winners[$r] = $winners[$r-1]; } $winners[$n] = $best_vector; $done = 1; last; } } if ( ($done == 0) && ($ws < $maxwinners) ) { push(@winners,$best_vector); } print printer("Current best vector",merit($winners[0]),$winners[0]); if ( $refill == $winnercompare ) { push(@stack,@winners); $refill = 0; $r = scalar(@stack) - 1; foreach $i ( 0 .. ($r - 1)) { foreach $j ( ($i) .. $r ) { ($result_l,$result_r) = combine($stack[$i],$stack[$j]); push(@stack,$result_l); push(@stack,$result_r); } } $best_mfactor = merit($winners[0]); } else { foreach $n ( 1 .. 75 ) { $y = randarray(); push(@stack,$y); } $best_mfactor = 0; } } sub main { our $working_mfactor; our $round_number; our $maxstack; our $maxrounds; my $rounds = 0; my $number = 0; my $improvement = 0; my $result; my $stacksize; my ($i,$j,$r,$y); while ( 'true' ) { $total++; $number = ($improvement) ? 0 : $number + 1; print "Number: $number\n" if $debug; $working_mfactor = merit(@stack[$number]); if ( $debug > 1 ) { message(1, printer("Working vector",$working_mfactor,@stack[$number])); } message(1,"\n" . $number . " of " . $stacksize ); $improvement = 0; $result = try_merit(@stack[$number]); if ($result > 0 ) { message(1, printer("better array", $best_mfactor,@stack[$number])); $improvement = 1; } my @rev = reverse(@{$stack[$number]}); $result = crossover($stack[$number],\@rev); if ($result > 0 ) { message(1, printer("better combine", $best_mfactor,@stack[$number])); $improvement = 1; } $result = mutations(@{$stack[$number]}); if ($result > 0 ) { message(1, printer("better mutation", $best_mfactor,@stack[$number])); $improvement = 1; } # Experimental 'crossover make' $result = crossovers(@{$stack[$number]}); if ($result > 0 ) { message(1, printer("better crossovers", $best_mfactor,@stack[$number])); $improvement = 1; } # Not very usefull, not value added # $result = randmutate($length, $length / 3,@{$stack[0]}); # if ($result > 0 ) { # printer("better randmutate", $best_mfactor,@stack[0]); # next; # } if ( $improvement ) { print "Stack size: " . scalar(@stack) . "\n"; print "best max mfactor " . $best_mfactor . "\n"; print "total done " . $total . "\n"; print "round " . $rounds; print "\n---\n"; } if ( ($total % $round_size) == 0 ) { print "===============================\n"; print "=== Completed Round $rounds ===\n"; print "===============================\n"; $rounds++; reinit(); if ( $rounds == $maxrounds ) { last; } $r = <> if $debug > 3; $improvement = 1; print "===============================\n"; print "=== New Round $rounds ===\n"; print "===============================\n"; next; } $stacksize = scalar(@stack); if ( $stacksize > $maxstack ) { while ( scalar(@stack) >= 5 ) { pop(@stack); } } message(1,"$number of " . scalar(@stack) . "\n");; $stacksize = scalar(@stack); if ( (($number +2) > $stacksize) ) { message(1,"Start EVOLVING"); $number = 0; while ( scalar(@stack) > 5 ) { pop(@stack); } foreach ( 5 .. 9 ) { $y = randarray(); push(@stack,$y); } foreach $i ( 0 .. 4) { foreach $j ( 5 .. 9 ) { my ($result_l,$result_r) = combine($stack[$i],$stack[$j]); push(@stack,$result_l); push(@stack,$result_r); } } message(1,"Done EVOLVING"); } #pause during debugging $r = <> if $debug > 4; } } $debug = 0; $round_size = 100; $maxstack = 150; $maxrounds = 20; $winnercompare = 5; init($ARGV[0]); main(); print "\n\n\n"; print "===============================\n"; print "=== Results ===\n"; print "===============================\n"; $best_vector = $winners[0]; $best_mfactor = merit($best_vector); print printer("Final", $best_mfactor,$best_vector); print "Total parents : $total\n"; print "Total rounds : $maxrounds\n"; print "Round parents : $round_size\n"; print "Winner compare: $winnercompare\n"; print "Max stack : $winnercompare\n"; print "Vector size : $length\n";