chiark / gitweb /
stv: fix tiebreaks
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 1 Aug 2016 16:45:39 +0000 (17:45 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 1 Aug 2016 16:45:39 +0000 (17:45 +0100)
stv

diff --git a/stv b/stv
index 3942b6b..03f16d8 100755 (executable)
--- a/stv
+++ b/stv
@@ -95,18 +95,36 @@ sub equalpiles ($@) {
 
 sub historically_prefer ($@) {
     my ($signum, @choices) = @_;
+    # $signum==+1 means choose candidates with more early preferences
 
     return $choices[0] if @choices < 2;
 
     my $compare = sub {
        foreach my $sr (@stagerecord) {
-           my $d = $sr->{ $a->{Cand} } <=> $sr->{ $b->{Cand} };
-           return $d * $signum if $d;
+           my $d = ($sr->{ $a->{Cand} }//0) <=> ($sr->{ $b->{Cand} }//0);
+           return -$d * $signum if $d;
        }
        return 0;
     };
 
     @choices = sort $compare @choices;
+
+    print DEBUG "historically_prefer\n",
+       Data::Dumper->Dump([\@choices, \@stagerecord],
+                          [qw(_@choices _@stagerecord)]);
+
+    foreach my $s (@choices) {
+       my $c = $s->{Cand};
+       printf " %6s %10s |", 'tiebrk', $c;
+       foreach my $sr (@stagerecord) {
+           my $p = pr($sr->{$c} // 0);
+           $p =~ s/\.0+\b//g;
+           $p =~ s/ //g;
+           print "$p|";
+       }
+       print "\n";
+    }
+
     $a = $choices[0];
     my $numequal = 1;
     for (;;) {
@@ -161,7 +179,7 @@ for (;;) {
     }
     my @sorted;
     my $things_update = sub {
-       foreach my $s (@surpluses, values %sorted) {
+       foreach my $s (values %sorted) {
            $s->{Total} = sum0 map { $_->{Weight} } @{ $s->{Votes } };
        }
        @sorted = nsort_by { -$_->{Total} } values %sorted;
@@ -205,6 +223,7 @@ for (;;) {
        my $topvoters = $s->{Total};
        my $surplus = $topvoters - $quota;
        last unless $surplus >= 0;
+       last unless $placesremain;
 
        my @elect = equalpiles 'elect?', @sorted;
 
@@ -226,6 +245,7 @@ for (;;) {
            push @newsurpluses, $s;
            delete $sorted{ $s->{Cand} };
            delete $continuing{ $s->{Cand} };
+           $placesremain--;
        }
 
        $things_update->();
@@ -245,15 +265,18 @@ for (;;) {
            grep { !!voteliveprefs $_ }
            @$votes;
 
+       my $derate = 1/1;
        printf "%7s %10s %s\n", 'xfrable', $s->{Cand}, pr $transferrable;
        if ($transferrable > $surplus) {
-           my $derate = $transferrable / $surplus;
+           $derate = $transferrable / $surplus;
            printf "%7s %10s %s\n", 'derate', $s->{Cand}, pr $derate;
            foreach my $vote (@{ $s->{Votes} }) {
                votelog $vote, "part of surplus, derated ". pr $derate;
                $vote->{Weight} /= $derate;
            }
        }
+       $s->{Total} = $transferrable / $derate;
+
        push @surpluses, $s;
 
        $things_update->();