From: Ian Jackson Date: Mon, 1 Aug 2016 16:45:39 +0000 (+0100) Subject: stv: fix tiebreaks X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=appendix-a6.git;a=commitdiff_plain;h=8a14c3d1ae526accda2146e15fc99f98c1b94548 stv: fix tiebreaks --- diff --git a/stv b/stv index 3942b6b..03f16d8 100755 --- 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->();