X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=appendix-a6.git;a=blobdiff_plain;f=compute-scottish-stv;h=d92db96382bddeac989202ad6e937ca8f52f6ce6;hp=6fde10308b409753d9f877e1df709300d2558fa3;hb=5fc4bc0993f2f2dc97c43217b3c0bfc51cdf9415;hpb=a4f2fc687bb9e16c33a59619acafe2cc21833ee1 diff --git a/compute-scottish-stv b/compute-scottish-stv index 6fde103..d92db96 100755 --- a/compute-scottish-stv +++ b/compute-scottish-stv @@ -35,15 +35,25 @@ our %tie; open DEBUG, ">.compute.log" or die $!; DEBUG->autoflush(1); -$SIG{__WARN__} = sub { +sub debug_dump () { print DEBUG Dumper(\%tie, \@non_transferable, \%cands, \@allvotes, $stage, $quota); +} + +$SIG{__WARN__} = sub { + $SIG{__DIE__} = undef; + debug_dump; confess $_[0]; }; +$SIG{__DIE__} = sub { + debug_dump; + die $_[0]; +}; + sub unkopt ($$) { my ($what,$opt) = @_; if ($opt =~ m/^[A-Z]/) { @@ -98,6 +108,7 @@ for (;;) { $cands{$_}{Cand} = $_ foreach keys %cands; $_->{Weight} //= 1/1 foreach @allvotes; $_->{TransferredSurplus} //= [ ] foreach @allvotes; +$_->{OrigPrefs} //= [ @{ $_->{Prefs} } ] foreach @allvotes; sub votelog ($$) { my ($vote,$m) = @_; @@ -111,6 +122,7 @@ sub sortballots (@) { # Strips that first preference from the ballot. # If the first preference has been eliminated, strips it # and looks for further preferences. + print DEBUG "sortballots ".(scalar @_)."...\n"; foreach my $v (@_) { my $firstprefs = shift @{ $v->{Prefs} }; my $w = $v->{Weight}; @@ -150,18 +162,22 @@ sub prf { } sub countballots () { - foreach my $cand (sort keys %cands) { - my $c = $cands{$cand}; + foreach my $c (values %cands) { next if $c->{NonCont}; - $c->{Total} = 0; + $c->{Total} = 0/1; $c->{Total} += $_->{Weight} foreach @{ $c->{Votes} }; - prf "candidate %-10s: %10s votes\n", $cand, $c->{Total}; + print DEBUG "counted $c->{Cand} $c->{Total}\n"; $c->{History}[$stage-1] = $c->{Total}; } + + foreach my $c (reverse sort total_history_cmp + grep { !$_->{NonCont} } values %cands) { + prf "candidate %-10s: %10s votes\n", $c->{Cand}, $c->{Total}; + } } sub computequota () { - my $totalvalid = 0; + my $totalvalid = 0/1; $totalvalid += $_->{Total} foreach values %cands; $quota = ($totalvalid / (1 + $seats)) -> bfloor(); prf "quota %10s\n", $quota; @@ -170,13 +186,15 @@ sub computequota () { sub total_history_cmp () { my $ha = $a->{History}; my $hb = $b->{History}; + my $m = "stage $stage history cmp $a->{Cand} $b->{Cand}"; + print DEBUG "$m...\n"; foreach my $s (reverse 0 .. $stage-1) { my $d = $ha->[$s] <=> $hb->[$s]; next unless $d; - print DEBUG "history cmp $a->{Cand} $b->{Cand}". - " => $d (#$s $ha->[$s] $hb->[$s])\n"; + print DEBUG "$m => $d (#$s $ha->[$s] $hb->[$s])\n"; return $d; } + print DEBUG "$m => 0\n"; return 0; } @@ -205,13 +223,14 @@ sub select_best_worst ($$$$) { for (;;) { my $nextc = $maybe[$nequal]; + last unless $nextc; # Only interested in those who compare equal according to the # history (SLGEO 49(2)); NB our history includes the current # round. last if $signum*($a = $maybe[0], $b = $nextc, total_history_cmp) > 0; - $nextc++; + $nequal++; } if ($nequal > 1 && !$wanttiebreak->($maybe[0]{Total})) { @@ -244,15 +263,13 @@ sub elect_core ($) { $c->{NonCont} = 'Elected'; } -$stage = 1; - -sortballots @allvotes; -countballots(); -computequota(); +$stage = 0; for (;;) { $stage++; + sortballots @allvotes if $stage == 1; + my $seats_remain = $seats - grep { ($_->{NonCont} // '') eq 'Elected' } values %cands; if (continuing() <= $seats_remain) { @@ -265,6 +282,8 @@ for (;;) { countballots(); + computequota if $stage == 1; + my $c = select_best_worst sub { $_->{Total} >= $quota }, sub { $_ > $quota }, @@ -277,7 +296,7 @@ for (;;) { # SLGEO 48 my $surplus = $c->{Total} - $quota; - if ($surplus <= 0) { + if ($surplus <= 0/1) { prf "no surplus\n"; next; } @@ -306,8 +325,9 @@ for (;;) { prf "transfer value of ballots %s: %10s\n", "@$previously", $xfervalue; } - sortballots $v; } + sortballots @{ $c->{Votes} }; + $c->{Votes} = { }; # will crash if we access it again next; } @@ -319,8 +339,10 @@ for (;;) { -1, 'eliminating'; if ($c) { - prf "=== eliminating %s (%s) ===\n", $c->{Cand}, $c->{Desc}; + prf "=== eliminating %s \`%s' ===\n", $c->{Cand}, $c->{Desc}; $c->{NonCont} = 'Eliminated'; + + sortballots @{ $c->{Votes} }; next; }