434412 -REPN=10 -LOCN=30 -S
#prog people loc'tns (srand(1) for testing)
####
[ 12 85] 127.723 [ [ 42: 80][ 74: 10] ]
[ 31 82] 156.39 [ [ 27: 27][ 57: 36][ 45: 94][ 58: 69] ]
[ 34 60] 158.432 [ [ 48: 20][ 86: 20][ 83: 72] ]
[ 47 47] 162.078 [ [ 78: 80][ 5: 60][ 53: 14][ 37: 9] ]
[ 36 30] 173.694 [ [ 67: 5][ 87: 72][ 77: 84] ]
[ 2 98] 173.723 [ [ 73: 60][ 95: 92] ]
[ 0 53] 178.987 [ [ 15: 22][ 99: 99][ 26: 29] ]
[ 5 0] 183.089 [ [ 45: 35][ 74: 46][ 46: 23] ]
[ 0 36] 183.654 [ [ 16: 66][ 59: 38][ 84: 2] ]
[ 0 19] 188.368 [ [ 61: 39][ 0: 91][ 51: 30] ]
000170 (000113) 1493.7 1686.14
#Cur'nt(Best ) Best Current
#Iters (iters) score score
##
##
#! perl -slw
use strict;
use Term::ReadKey;
use Clone qw[ clone ];
use List::Util qw[ min reduce sum ]; $a=$b;
$| = 1;
use constant { X => 0, Y => 1, };
use constant { REP => 0, LOCNS => 1, SCORE => 2 };
our $GRID ||= '100:100'; ## X:Y of grid
our @GRID = split ':', $GRID;
our $REPN ||= 10; ## Number of representatives
our $LOCN ||= $REPN * 3; ## Number of locations
our $EVO ||= 1000; ## Evolution backtrack count
our $S and srand( 1 ); ## allows comparison between runs.
print "Reps: $REPN Locations:$LOCN";
die "LOCN must be >= $REPN" unless $LOCN >= $REPN;
sub show { ## Format sets for display
system 'cls' if @_ > 1;
for( @{ $_[ 0 ] } ) {
printf "[%7s] %7g [ %s ]\n",
"@{ $_->[REP] }",
$_->[SCORE]||0.0,
join '', map{ sprintf "[%3d:%3d]", @$_ } @{ $_->[LOCNS] };
}
}
sub pythagoras { ## calc distance between to points.
my( $v1, $v2 ) = @_;
my $dx = abs( $v1->[X] ) - abs( $v2->[X] );
my $dy = abs( $v1->[Y] ) - abs( $v2->[Y] );
return sqrt( $dx**2 + $dy**2 );
}
## Simple scoring. of individual sets
## Sum of distances of locations from rep location.
sub score {
my( $set ) = @_;
return sum map {
pythagoras( $set->[ 0 ], $_ );
} @{ $set->[ 1 ] }
}
my @reps = map { [ int rand rand $GRID[X], int rand $GRID[Y] ] } 1 .. $REPN;
my @locations = map { [ int rand $GRID[X], int rand $GRID[Y] ] } 1 .. $LOCN;
my @sets = map { [ $_, [ pop @locations ] ] } @reps;
push @{ $sets[ rand @sets ][1] }, pop @locations while @locations;
show( \@sets, 1 ); ;
my( $tries, $c ) = ( 0, 's' );
my $best = [ 9e99, [], 9 ];
my $evolution = 0;
my( %scores, %best );
my( $delay, $display, $stop ) = ( -1, 1, 0 );
ReadMode 2;
while( 1 ) {
## Caclulate the total score for the current sets.
## Sum of individual totals.
my $totalScore = sum map {
$_->[SCORE] = score $_
} @sets;
## Records frequencies of (integerised) solutions found
$scores{ int $totalScore }++;
## Keep track of iterations
$tries++;
## Commands to monitor progress and quit.
$c = ReadKey( $delay )||'';
$stop = 1 if $c eq 'q'; ## Quit
$delay += 1 if $c eq 's'; ## speed (0=pause) (n>0 sleep n)
$delay = -1 if $c eq 'c'; ## Continue fullspeed
$display = !$display if $c eq 'd'; ## Toggle display
if( $best->[ 0 ] > $totalScore ) { ## If we found a better solution
$best = [ $totalScore, clone( \@sets ), $tries ]; ## save it
$evolution = $EVO; ## but allow bad solution to evolve for a while
## Keep a record of when we found improvements
## to allow estimates of "good enough" iterations;
$best{ $tries } = $totalScore;
}
elsif( $stop or not --$evolution ) {
## if no better evolution after $EVO attempts
@sets = @{ $best->[1] }; ## Restore the best yet and try again
print 'Best restored'; Win32::Sleep 1000;
}
last if $stop; ## stop here after ensuring the best is restored.
## Sort them by individual scores
@sets = sort{ $a->[SCORE] <=> $b->[SCORE] } @sets;
## Display them
show \@sets, 1 if $display;
printf "%06d (%06d) %g %g\n",
$tries, $best->[ 2 ], $best->[ 0 ], $totalScore;
## If the worst set has more than 1, given one to the best
push @{ $sets[ 0 ][LOCNS] }, shift @{ $sets[ -1 ][LOCNS] }
if @{ $sets[ -1 ][LOCNS] } > 1;
## pick two set/location pairs at random
my( $a, $b ) = map{ int rand @sets } 1 .. 2;
my( $sa, $sb ) = ( int rand $#{ $sets[ $a ][LOCNS] }, int rand $#{ $sets[ $b ][LOCNS] } );
## and swap them
my $temp = $sets[ $a ][LOCNS][ $sa ]||die "A:$a:$sa";
$sets[ $a ][LOCNS][ $sa ] = $sets[ $b ][LOCNS][ $sb ]||die "B:$b:$sb";
$sets[ $b ][LOCNS][ $sb ] = $temp;
}
show \@sets; ## display best solution
printf "Total: %d after %d tries\n", $best->[ 0 ], $best->[ 2 ];
printf 'Enter to see a frequendy plot of the solutions found'; ;
print "$_ => $scores{ $_ }" for sort{ $a <=> $b } keys %scores;
printf 'Enter to see record of best discovery points.'; ;
print "Best score: $best{ $_ } after $_ iterations." for sort{ $a <=> $b } keys %best;
##
##
[ 0 19] 41.3038 [ [ 5: 60] ]
[ 0 36] 45.0111 [ [ 45: 35] ]
[ 47 47] 47.1699 [ [ 87: 72] ]
[ 34 60] 49.7695 [ [ 53: 14] ]
[ 0 53] 54.9181 [ [ 46: 23] ]
[ 5 0] 66.9104 [ [ 16: 66] ]
[ 12 85] 67.424 [ [ 51: 30] ]
[ 2 98] 78.1025 [ [ 78: 80] ]
[ 31 82] 82.8794 [ [ 86: 20] ]
[ 36 30] 85.5862 [ [ 95: 92] ]
037234 (021726) 435.401 619.075
Best restored
[ 0 53] 54.9181 [ [ 46: 23] ]
[ 36 30] 15 [ [ 51: 30] ]
[ 12 85] 83.2947 [ [ 95: 92] ]
[ 0 36] 45.0111 [ [ 45: 35] ]
[ 47 47] 47.1699 [ [ 87: 72] ]
[ 0 19] 41.3038 [ [ 5: 60] ]
[ 34 60] 49.7695 [ [ 53: 14] ]
[ 31 82] 82.8794 [ [ 86: 20] ]
[ 2 98] 78.1025 [ [ 78: 80] ]
[ 5 0] 66.9104 [ [ 16: 66] ]
Total: 435 after 21726 tries
Enter to see a frequendy plot of the solutions found
435 => 3
441 => 3
442 => 2
443 => 1
447 => 1
448 => 1
450 => 3
453 => 4
454 => 3
455 => 1
456 => 1
457 => 3
459 => 3
461 => 2
462 => 1
463 => 3
464 => 4
465 => 3
466 => 4
467 => 9
468 => 6
469 => 8
470 => 6
471 => 6
472 => 7
473 => 12
474 => 4
475 => 8
476 => 12
477 => 10
478 => 10
479 => 15
480 => 13
481 => 12
482 => 13
483 => 9
484 => 20
485 => 8
486 => 17
487 => 22
488 => 21
489 => 22
490 => 21
491 => 29
492 => 30
493 => 23
494 => 27
495 => 40
496 => 34
497 => 39
498 => 34
499 => 42
500 => 31
501 => 43
502 => 64
503 => 49
504 => 53
505 => 44
506 => 55
507 => 72
508 => 63
509 => 72
510 => 58
511 => 59
512 => 60
513 => 84
514 => 63
515 => 59
516 => 78
517 => 83
518 => 77
519 => 105
520 => 94
521 => 83
522 => 91
523 => 110
524 => 107
525 => 101
526 => 134
527 => 125
528 => 119
529 => 110
530 => 134
531 => 122
532 => 113
533 => 125
534 => 152
535 => 157
536 => 170
537 => 153
538 => 173
539 => 153
540 => 194
541 => 181
542 => 149
543 => 179
544 => 188
545 => 172
546 => 192
547 => 210
548 => 207
549 => 213
550 => 204
551 => 212
552 => 235
553 => 254
554 => 248
555 => 185
556 => 268
557 => 242
558 => 256
559 => 247
560 => 258
561 => 258
562 => 241
563 => 290
564 => 281
565 => 288
566 => 318
567 => 306
568 => 268
569 => 306
570 => 275
571 => 281
572 => 268
573 => 307
574 => 307
575 => 299
576 => 254
577 => 293
578 => 324
579 => 284
580 => 299
581 => 304
582 => 303
583 => 322
584 => 333
585 => 342
586 => 323
587 => 329
588 => 333
589 => 312
590 => 331
591 => 274
592 => 314
593 => 349
594 => 318
595 => 303
596 => 290
597 => 318
598 => 323
599 => 288
600 => 272
601 => 329
602 => 331
603 => 335
604 => 304
605 => 312
606 => 328
607 => 311
608 => 315
609 => 290
610 => 280
611 => 320
612 => 272
613 => 267
614 => 298
615 => 307
616 => 260
617 => 280
618 => 283
619 => 346
620 => 299
621 => 253
622 => 262
623 => 264
624 => 251
625 => 230
626 => 226
627 => 254
628 => 239
629 => 260
630 => 231
631 => 245
632 => 226
633 => 217
634 => 244
635 => 206
636 => 221
637 => 226
638 => 180
639 => 176
640 => 206
641 => 175
642 => 180
643 => 161
644 => 166
645 => 203
646 => 167
647 => 179
648 => 163
649 => 155
650 => 125
651 => 146
652 => 128
653 => 130
654 => 121
655 => 137
656 => 127
657 => 121
658 => 122
659 => 120
660 => 100
661 => 115
662 => 93
663 => 119
664 => 102
665 => 109
666 => 107
667 => 90
668 => 87
669 => 88
670 => 90
671 => 63
672 => 69
673 => 74
674 => 69
675 => 45
676 => 57
677 => 61
678 => 53
679 => 49
680 => 62
681 => 54
682 => 53
683 => 41
684 => 50
685 => 49
686 => 50
687 => 41
688 => 31
689 => 44
690 => 30
691 => 37
692 => 36
693 => 36
694 => 42
695 => 39
696 => 29
697 => 19
698 => 26
699 => 28
700 => 28
701 => 30
702 => 24
703 => 22
704 => 22
705 => 16
706 => 20
707 => 15
708 => 13
709 => 13
710 => 13
711 => 14
712 => 9
713 => 8
714 => 3
715 => 8
716 => 4
717 => 1
718 => 2
719 => 9
720 => 3
721 => 5
722 => 3
723 => 3
724 => 9
725 => 3
727 => 4
728 => 1
729 => 2
730 => 3
732 => 4
733 => 4
734 => 2
735 => 1
736 => 1
739 => 2
740 => 2
741 => 1
742 => 3
743 => 1
744 => 1
746 => 1
Enter to see record of best discovery points.
Best score: 587.754090215359 after 1 iterations.
Best score: 585.739406140003 after 2 iterations.
Best score: 574.349845629305 after 7 iterations.
Best score: 539.378581196848 after 9 iterations.
Best score: 515.579334272599 after 25 iterations.
Best score: 503.180579975418 after 26 iterations.
Best score: 482.804864664163 after 98 iterations.
Best score: 481.914466880709 after 99 iterations.
Best score: 469.204365706502 after 623 iterations.
Best score: 468.414887089937 after 1607 iterations.
Best score: 454.855761343826 after 1846 iterations.
Best score: 442.160363943557 after 2281 iterations.
Best score: 442.160363943557 after 2282 iterations.
Best score: 441.218607935927 after 2283 iterations.
Best score: 435.401484875951 after 21726 iterations.