1 | #!/usr/bin/env perl
|
---|
2 |
|
---|
3 | use strict;
|
---|
4 |
|
---|
5 | our $debug = 0;
|
---|
6 | our %taken;
|
---|
7 |
|
---|
8 | our $length = 0;
|
---|
9 | our $round_size = 100;
|
---|
10 | our $maxstack = 150;
|
---|
11 | our $working_mfactor = 0;
|
---|
12 | our $best_mfactor = 0;
|
---|
13 | our $best_vector;
|
---|
14 | our $refill = 0;
|
---|
15 | our $maxrounds = 20;
|
---|
16 | our @winners;
|
---|
17 | our $winnercompare = 10;
|
---|
18 |
|
---|
19 | our $total = 0;
|
---|
20 |
|
---|
21 | sub message {
|
---|
22 | our $debug;
|
---|
23 | my $level = shift;
|
---|
24 | my $message = shift;
|
---|
25 | if ( $level => $debug ) {
|
---|
26 | print "DEBUG [$level]: $message\n";
|
---|
27 | }
|
---|
28 | }
|
---|
29 |
|
---|
30 | sub merit {
|
---|
31 | my $y = shift;
|
---|
32 | our $length;
|
---|
33 | my $e = 0;
|
---|
34 | my $f;
|
---|
35 | my $t;
|
---|
36 |
|
---|
37 | foreach my $k (1 .. ($length - 1)) {
|
---|
38 | $t = 0;
|
---|
39 | for my $i (0 .. ($length - 1 - $k)) {
|
---|
40 | $t += $$y[$i] * $$y[$i+$k];
|
---|
41 | }
|
---|
42 | $e += $t ** 2;
|
---|
43 | }
|
---|
44 |
|
---|
45 | $f = ($length ** 2) / ( 2 * $e);
|
---|
46 | printer('DEBUG merit', $f, $y) if $debug > 5;
|
---|
47 | return($f);
|
---|
48 | }
|
---|
49 |
|
---|
50 | sub randarray {
|
---|
51 | our $debug;
|
---|
52 | my @output = ();
|
---|
53 | my ($i,$v);
|
---|
54 | message(1,"New randarray of length $length");
|
---|
55 | foreach $i ( 0 .. ($length - 1)) {
|
---|
56 | $v = int(rand() + 0.5);
|
---|
57 | $output[$i] = ( $v ) ? 1 : -1;
|
---|
58 | }
|
---|
59 | return(\@output);
|
---|
60 | }
|
---|
61 |
|
---|
62 | sub flip {
|
---|
63 | my $rref = shift;
|
---|
64 | my $number = shift;
|
---|
65 | my $v = $$rref[$number];
|
---|
66 | $v = ($v == 1) ? -1 : 1;
|
---|
67 | $$rref[$number] = $v;
|
---|
68 | }
|
---|
69 |
|
---|
70 | sub try_merit {
|
---|
71 | our @stack;
|
---|
72 | our %taken;
|
---|
73 | our $best_mfactor;
|
---|
74 | our $best_vector;
|
---|
75 | our $working_mfactor;
|
---|
76 |
|
---|
77 | my $try_array = shift;
|
---|
78 | my $new_mfactor;
|
---|
79 | my $result = 0;
|
---|
80 | my $array2string = join('',@{$try_array});
|
---|
81 |
|
---|
82 | if ( not exists ($taken{$array2string}) ) {
|
---|
83 | $new_mfactor = merit($try_array);
|
---|
84 | $taken{$array2string} = $new_mfactor;
|
---|
85 |
|
---|
86 | if ($new_mfactor > $best_mfactor) {
|
---|
87 | $best_mfactor = $new_mfactor;
|
---|
88 | $best_vector = $try_array;
|
---|
89 | $result = 1;
|
---|
90 | unshift(@stack,$try_array);
|
---|
91 | }
|
---|
92 | }
|
---|
93 | if ( $debug == 5 ) {
|
---|
94 | print "==== " . scalar(@stack) . "====\n";
|
---|
95 | print join("\n",@stack) . "\n";
|
---|
96 | }
|
---|
97 | return($result);
|
---|
98 | }
|
---|
99 |
|
---|
100 | sub combine {
|
---|
101 | our $length;
|
---|
102 | our $debug;
|
---|
103 | message(1,"Working on combine");
|
---|
104 |
|
---|
105 | my $result = 0;
|
---|
106 | my $loop;
|
---|
107 | my $input = shift;
|
---|
108 | my $input2 = shift;
|
---|
109 | my @result_l;
|
---|
110 | my @result_r;
|
---|
111 |
|
---|
112 |
|
---|
113 | my $middle = int($length / 2);
|
---|
114 | @result_l = (@{$input}[0 .. $middle],
|
---|
115 | @{$input2}[ $middle + 1 .. ($length-1) ]);
|
---|
116 | @result_r = (@{$input2}[0 .. $middle],
|
---|
117 | @{$input}[ $middle + 1 .. ($length-1) ]);
|
---|
118 |
|
---|
119 | if ($debug > 3) {
|
---|
120 | print "Orig l: ";
|
---|
121 | print @{$input};
|
---|
122 | print "\n";
|
---|
123 | print "Orig 2: ";
|
---|
124 | print @{$input2};
|
---|
125 | print "\n";
|
---|
126 | print "Combine l: ";
|
---|
127 | print @result_l;
|
---|
128 | print "\n";
|
---|
129 | print "Combine r: ";
|
---|
130 | print @result_r;
|
---|
131 | print "\n";
|
---|
132 | }
|
---|
133 | message(1,"DEBUG: Done on combine");
|
---|
134 | return(\@result_l,\@result_r);
|
---|
135 | }
|
---|
136 |
|
---|
137 | sub crossover {
|
---|
138 | my $input = shift;
|
---|
139 | my $rev_array = shift;
|
---|
140 | my $result = 0;
|
---|
141 | my ($try_array_l,$try_array_r) = combine($input,$rev_array);
|
---|
142 |
|
---|
143 | if ( try_merit($try_array_l) ) {
|
---|
144 | $result = 1;
|
---|
145 | }
|
---|
146 |
|
---|
147 | if ( try_merit($try_array_r) ) {
|
---|
148 | $result = 1;
|
---|
149 | }
|
---|
150 | return($result);
|
---|
151 | }
|
---|
152 |
|
---|
153 |
|
---|
154 | sub mutations {
|
---|
155 | our $length;
|
---|
156 |
|
---|
157 | my @try_array;
|
---|
158 | my $result = 0;
|
---|
159 | my @test_array = @_;
|
---|
160 |
|
---|
161 | message(1,"Working on mutations");
|
---|
162 |
|
---|
163 | foreach my $i ( 0 .. ($length - 1) ) {
|
---|
164 | my @try_array = ();
|
---|
165 | @try_array = @test_array;
|
---|
166 | flip(\@try_array, $i);
|
---|
167 |
|
---|
168 | if ( try_merit(\@try_array) ) {
|
---|
169 | $result = 1;
|
---|
170 | }
|
---|
171 | }
|
---|
172 | message(1,"Done on mutations");
|
---|
173 | return($result) ;
|
---|
174 | }
|
---|
175 |
|
---|
176 |
|
---|
177 | sub crossovers {
|
---|
178 | our $length;
|
---|
179 |
|
---|
180 | my @try_array;
|
---|
181 | my $result = 0;
|
---|
182 | my @test_array = @_;
|
---|
183 |
|
---|
184 | my $i;
|
---|
185 | my $j;
|
---|
186 |
|
---|
187 | message(1,"Working on crossovers");
|
---|
188 | foreach $i ( 0 .. ($length - 1) ) {
|
---|
189 | my @try_array = ();
|
---|
190 | @try_array = @test_array;
|
---|
191 | foreach $j ( $i .. ($length - 1) ) {
|
---|
192 | flip(\@try_array, $j);
|
---|
193 | }
|
---|
194 |
|
---|
195 | if ( try_merit(\@try_array) ) {
|
---|
196 | $result = 1;
|
---|
197 | }
|
---|
198 | }
|
---|
199 | message(1,"Done on crossovers");
|
---|
200 | return($result);
|
---|
201 | }
|
---|
202 |
|
---|
203 |
|
---|
204 |
|
---|
205 |
|
---|
206 | sub randmutate {
|
---|
207 | our $length;
|
---|
208 | my $switchtimes = shift;
|
---|
209 | my $switchnumbers = shift;
|
---|
210 | my @test_array = @_;
|
---|
211 | my $result = 0;
|
---|
212 | my @try_array;
|
---|
213 | my $i;
|
---|
214 | my $j;
|
---|
215 | my $n;
|
---|
216 | my @flipped;
|
---|
217 |
|
---|
218 | message(1,"Working on randmutate");
|
---|
219 |
|
---|
220 | foreach $i ( 0 .. $switchtimes ) {
|
---|
221 | my @try_array = ();
|
---|
222 | @try_array = @test_array;
|
---|
223 | @flipped = ();
|
---|
224 | foreach $j ( 0 .. $switchnumbers ) {
|
---|
225 | $n = int(rand($length - 1));
|
---|
226 | if ( not exists $flipped[$n] ) {
|
---|
227 | flip(\@try_array,$n);
|
---|
228 | $flipped[$n] = 1;
|
---|
229 | }
|
---|
230 | }
|
---|
231 |
|
---|
232 | if ( try_merit(\@try_array) ) {
|
---|
233 | $result = 1;
|
---|
234 | }
|
---|
235 | }
|
---|
236 | return($result);
|
---|
237 | }
|
---|
238 |
|
---|
239 | sub printer {
|
---|
240 | my $message = shift;
|
---|
241 | my $mfactor = shift;
|
---|
242 | my $input = shift;
|
---|
243 | return("Message : $message \n" .
|
---|
244 | "Vector : " . join(',',array2string($input) . "\n" .
|
---|
245 | "mfactor : $mfactor \n" .
|
---|
246 | "--\n");
|
---|
247 | }
|
---|
248 |
|
---|
249 |
|
---|
250 |
|
---|
251 | our @stack = ();
|
---|
252 | our $best_mfactor = 0;
|
---|
253 | our $best_vector;
|
---|
254 |
|
---|
255 | sub array2string {
|
---|
256 | my $input = shift;
|
---|
257 | my @result = ();
|
---|
258 | my $n = 1;
|
---|
259 | foreach my $i (1 .. $#$input) {
|
---|
260 | if ($$input[$i] != $$input[$i - 1]) {
|
---|
261 | push(@result,$n);
|
---|
262 | $n = 1;
|
---|
263 | }
|
---|
264 | else {
|
---|
265 | $n++;
|
---|
266 | }
|
---|
267 | }
|
---|
268 | push(@result,$n);
|
---|
269 | return(@result);
|
---|
270 | }
|
---|
271 |
|
---|
272 | sub string2array {
|
---|
273 | my @output = ();
|
---|
274 | my $input = shift;
|
---|
275 | $input = split(//,$input);
|
---|
276 | my $c = 0;
|
---|
277 | my $v = 1;
|
---|
278 |
|
---|
279 | my ($n,$i);
|
---|
280 |
|
---|
281 | for $n ( 0 .. length($input) - 1) {
|
---|
282 | for $i ( 1 .. @{$input}[$n] ) {
|
---|
283 | $output[$c] = $v;
|
---|
284 | $c++;
|
---|
285 | }
|
---|
286 | $v = ( $v == 1) ? -1 : 1;
|
---|
287 | }
|
---|
288 |
|
---|
289 | return(@output);
|
---|
290 | }
|
---|
291 |
|
---|
292 |
|
---|
293 | #
|
---|
294 | # Vul de stack met een random arrays
|
---|
295 | sub init {
|
---|
296 | our $length = shift;
|
---|
297 | our @stack;
|
---|
298 | our $best_mfactor;
|
---|
299 |
|
---|
300 | my ($n,$y);
|
---|
301 |
|
---|
302 | @stack = ();
|
---|
303 | $best_mfactor = 0;
|
---|
304 |
|
---|
305 | foreach $n ( 1 .. 75 ) {
|
---|
306 | $y = randarray();
|
---|
307 | push(@stack,$y);
|
---|
308 | }
|
---|
309 |
|
---|
310 | }
|
---|
311 |
|
---|
312 | sub reinit {
|
---|
313 | our $refill;
|
---|
314 | our $winnercompare;
|
---|
315 | our $length;
|
---|
316 | our @winners;
|
---|
317 | our %taken;
|
---|
318 | our @stack;
|
---|
319 | our $best_vector;
|
---|
320 | our $best_mfactor;
|
---|
321 |
|
---|
322 | my $maxwinners = 5;
|
---|
323 |
|
---|
324 | my ($result_l,$result_r);
|
---|
325 | my ($i,$j);
|
---|
326 | my ($n,$y);
|
---|
327 | my ($r);
|
---|
328 |
|
---|
329 | %taken = ();
|
---|
330 | @stack = ();
|
---|
331 |
|
---|
332 | $refill++;
|
---|
333 | #push best array on good place
|
---|
334 | $i = merit($best_vector);
|
---|
335 | print printer("Round best vector",$i,$best_vector);
|
---|
336 | my $ws = $#winners - 1;
|
---|
337 | my $done = 0;
|
---|
338 | foreach $n ( 0 .. $ws ) {
|
---|
339 | $j = merit($winners[$n]);
|
---|
340 | if ( $i > $j ) {
|
---|
341 | foreach $r ($ws .. ($n + 1)) {
|
---|
342 | $winners[$r] = $winners[$r-1];
|
---|
343 | }
|
---|
344 | $winners[$n] = $best_vector;
|
---|
345 | $done = 1;
|
---|
346 | last;
|
---|
347 | }
|
---|
348 | }
|
---|
349 | if ( ($done == 0) && ($ws < $maxwinners) ) {
|
---|
350 | push(@winners,$best_vector);
|
---|
351 | }
|
---|
352 | print printer("Current best vector",merit($winners[0]),$winners[0]);
|
---|
353 |
|
---|
354 | if ( $refill == $winnercompare ) {
|
---|
355 | push(@stack,@winners);
|
---|
356 | $refill = 0;
|
---|
357 | $r = scalar(@stack) - 1;
|
---|
358 | foreach $i ( 0 .. ($r - 1)) {
|
---|
359 | foreach $j ( ($i) .. $r ) {
|
---|
360 | ($result_l,$result_r) = combine($stack[$i],$stack[$j]);
|
---|
361 | push(@stack,$result_l);
|
---|
362 | push(@stack,$result_r);
|
---|
363 | }
|
---|
364 | }
|
---|
365 | $best_mfactor = merit($winners[0]);
|
---|
366 | }
|
---|
367 | else {
|
---|
368 | foreach $n ( 1 .. 75 ) {
|
---|
369 | $y = randarray();
|
---|
370 | push(@stack,$y);
|
---|
371 | }
|
---|
372 | $best_mfactor = 0;
|
---|
373 | }
|
---|
374 | }
|
---|
375 |
|
---|
376 | sub main {
|
---|
377 | our $working_mfactor;
|
---|
378 | our $round_number;
|
---|
379 | our $maxstack;
|
---|
380 | our $maxrounds;
|
---|
381 |
|
---|
382 | my $rounds = 0;
|
---|
383 | my $number = 0;
|
---|
384 | my $improvement = 0;
|
---|
385 | my $result;
|
---|
386 | my $stacksize;
|
---|
387 | my ($i,$j,$r,$y);
|
---|
388 |
|
---|
389 | while ( 'true' )
|
---|
390 | {
|
---|
391 | $total++;
|
---|
392 |
|
---|
393 | $number = ($improvement) ? 0 : $number + 1;
|
---|
394 | print "Number: $number\n" if $debug;
|
---|
395 |
|
---|
396 | $working_mfactor = merit(@stack[$number]);
|
---|
397 | if ( $debug > 1 ) {
|
---|
398 | message(1,
|
---|
399 | printer("Working vector",$working_mfactor,@stack[$number]));
|
---|
400 | }
|
---|
401 |
|
---|
402 | message(1,"\n" . $number . " of " . $stacksize );
|
---|
403 | $improvement = 0;
|
---|
404 |
|
---|
405 | $result = try_merit(@stack[$number]);
|
---|
406 | if ($result > 0 ) {
|
---|
407 | message(1,
|
---|
408 | printer("better array", $best_mfactor,@stack[$number]));
|
---|
409 | $improvement = 1;
|
---|
410 | }
|
---|
411 |
|
---|
412 | my @rev = reverse(@{$stack[$number]});
|
---|
413 | $result = crossover($stack[$number],\@rev);
|
---|
414 | if ($result > 0 ) {
|
---|
415 | message(1,
|
---|
416 | printer("better combine", $best_mfactor,@stack[$number]));
|
---|
417 | $improvement = 1;
|
---|
418 | }
|
---|
419 |
|
---|
420 | $result = mutations(@{$stack[$number]});
|
---|
421 | if ($result > 0 ) {
|
---|
422 | message(1,
|
---|
423 | printer("better mutation", $best_mfactor,@stack[$number]));
|
---|
424 | $improvement = 1;
|
---|
425 | }
|
---|
426 |
|
---|
427 | # Experimental 'crossover make'
|
---|
428 | $result = crossovers(@{$stack[$number]});
|
---|
429 | if ($result > 0 ) {
|
---|
430 | message(1,
|
---|
431 | printer("better crossovers", $best_mfactor,@stack[$number]));
|
---|
432 | $improvement = 1;
|
---|
433 | }
|
---|
434 |
|
---|
435 | # Not very usefull, not value added
|
---|
436 | # $result = randmutate($length, $length / 3,@{$stack[0]});
|
---|
437 | # if ($result > 0 ) {
|
---|
438 | # printer("better randmutate", $best_mfactor,@stack[0]);
|
---|
439 | # next;
|
---|
440 | # }
|
---|
441 |
|
---|
442 | if ( $improvement ) {
|
---|
443 | print "Stack size: " . scalar(@stack) . "\n";
|
---|
444 | print "best max mfactor " . $best_mfactor . "\n";
|
---|
445 | print "total done " . $total . "\n";
|
---|
446 | print "round " . $rounds;
|
---|
447 | print "\n---\n";
|
---|
448 | }
|
---|
449 |
|
---|
450 | if ( ($total % $round_size) == 0 ) {
|
---|
451 | print "===============================\n";
|
---|
452 | print "=== Completed Round $rounds ===\n";
|
---|
453 | print "===============================\n";
|
---|
454 | $rounds++;
|
---|
455 | reinit();
|
---|
456 | if ( $rounds == $maxrounds ) {
|
---|
457 | last;
|
---|
458 | }
|
---|
459 | $r = <> if $debug > 3;
|
---|
460 | $improvement = 1;
|
---|
461 | print "===============================\n";
|
---|
462 | print "=== New Round $rounds ===\n";
|
---|
463 | print "===============================\n";
|
---|
464 | next;
|
---|
465 | }
|
---|
466 |
|
---|
467 | $stacksize = scalar(@stack);
|
---|
468 | if ( $stacksize > $maxstack ) {
|
---|
469 | while ( scalar(@stack) >= 5 ) {
|
---|
470 | pop(@stack);
|
---|
471 | }
|
---|
472 | }
|
---|
473 | message(1,"$number of " . scalar(@stack) . "\n");;
|
---|
474 | $stacksize = scalar(@stack);
|
---|
475 | if ( (($number +2) > $stacksize) ) {
|
---|
476 | message(1,"Start EVOLVING");
|
---|
477 | $number = 0;
|
---|
478 | while ( scalar(@stack) > 5 ) {
|
---|
479 | pop(@stack);
|
---|
480 | }
|
---|
481 |
|
---|
482 | foreach ( 5 .. 9 ) {
|
---|
483 | $y = randarray();
|
---|
484 | push(@stack,$y);
|
---|
485 | }
|
---|
486 |
|
---|
487 | foreach $i ( 0 .. 4) {
|
---|
488 | foreach $j ( 5 .. 9 ) {
|
---|
489 | my ($result_l,$result_r) = combine($stack[$i],$stack[$j]);
|
---|
490 | push(@stack,$result_l);
|
---|
491 | push(@stack,$result_r);
|
---|
492 | }
|
---|
493 | }
|
---|
494 | message(1,"Done EVOLVING");
|
---|
495 | }
|
---|
496 |
|
---|
497 | #pause during debugging
|
---|
498 | $r = <> if $debug > 4;
|
---|
499 | }
|
---|
500 | }
|
---|
501 |
|
---|
502 | $debug = 0;
|
---|
503 | $round_size = 100;
|
---|
504 | $maxstack = 150;
|
---|
505 | $maxrounds = 20;
|
---|
506 | $winnercompare = 5;
|
---|
507 | init($ARGV[0]);
|
---|
508 | main();
|
---|
509 |
|
---|
510 | print "\n\n\n";
|
---|
511 |
|
---|
512 | print "===============================\n";
|
---|
513 | print "=== Results ===\n";
|
---|
514 | print "===============================\n";
|
---|
515 |
|
---|
516 | $best_vector = $winners[0];
|
---|
517 | $best_mfactor = merit($best_vector);
|
---|
518 | print printer("Final", $best_mfactor,$best_vector);
|
---|
519 | print "Total parents : $total\n";
|
---|
520 | print "Total rounds : $maxrounds\n";
|
---|
521 | print "Round parents : $round_size\n";
|
---|
522 | print "Winner compare: $winnercompare\n";
|
---|
523 | print "Max stack : $winnercompare\n";
|
---|
524 | print "Vector size : $length\n";
|
---|