Implement exclusion of parcels by value + Senate STV

This commit is contained in:
RunasSudo 2020-12-30 02:33:09 +11:00
parent 803941a53a
commit 61506f0082
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
2 changed files with 33 additions and 11 deletions

View File

@ -40,7 +40,7 @@
<select id="selPreset" onchange="changePreset()">
<option value="scottish" selected>Scottish STV</option>
<option value="stvc">pyRCV STV-C</option>
<!--<option value="senate">Australian Senate STV</option>-->
<option value="senate">Australian Senate STV</option>
<option value="wright">Wright STV</option>
<option value="prsa77">PRSA 1977</option>
</select>
@ -119,7 +119,7 @@
<select id="selExclusion">
<option value="one_round" selected>Exclude in one round</option>
<option value="parcels_by_order">Exclude by parcel (by order)</option>
<!--<option value="parcels_by_value">Exclude by parcel (by value)</option>-->
<option value="parcels_by_value">Exclude by parcel (by value)</option>
</select>
</label>
<br>

View File

@ -20,6 +20,8 @@ from pyRCV2.model import CandidateState, CountCard, CountCompleted, CountStepRes
from pyRCV2.numbers import Num, Rational
from pyRCV2.safedict import SafeDict
import itertools
class STVException(Exception):
pass
@ -535,11 +537,28 @@ class WIGSTVCounter(BaseSTVCounter):
def do_exclusion(self, candidate_excluded, count_card):
if self.options['exclusion'] == 'parcels_by_order':
parcel = count_card.parcels[0]
next_preferences, total_ballots, total_votes, next_exhausted, exhausted_ballots, exhausted_votes = self.next_preferences([parcel])
if len(count_card.parcels) > 0:
parcel = count_card.parcels[0]
next_preferences, total_ballots, total_votes, next_exhausted, exhausted_ballots, exhausted_votes = self.next_preferences([parcel])
else:
# TODO: Skip this entirely if this is the case
parcel = []
count_card.parcels.remove(parcel)
elif self.options['exclusion'] == 'parcels_by_value':
raise Exception('Not implemented')
# Sort the parcels by value
ballots = [(b, bv) for p in count_card.parcels for b, bv in p]
__pragma__('opov')
ballots.sort(key=lambda x: x[1] / x[0].value.to_rational(), reverse=True)
count_card.parcels = [list(g) for k, g in itertools.groupby(ballots, lambda x: x[1] / x[0].value.to_rational())]
__pragma__('noopov')
if len(count_card.parcels) > 0:
parcel = count_card.parcels[0]
count_card.parcels.remove(parcel)
else:
parcel = []
next_preferences, total_ballots, total_votes, next_exhausted, exhausted_ballots, exhausted_votes = self.next_preferences([parcel])
else: # one_round
next_preferences, total_ballots, total_votes, next_exhausted, exhausted_ballots, exhausted_votes = self.next_preferences(count_card.parcels)
count_card.parcels = []
@ -573,6 +592,9 @@ class WIGSTVCounter(BaseSTVCounter):
__pragma__('noopov')
if len(count_card.parcels) == 0:
__pragma__('opov')
count_card.transfers -= count_card.votes
__pragma__('noopov')
count_card.state = CandidateState.EXCLUDED
class UIGSTVCounter(WIGSTVCounter):
@ -590,14 +612,14 @@ class UIGSTVCounter(WIGSTVCounter):
if self.options['papers'] == 'transferable':
__pragma__('opov')
transferable_ballots = total_ballots - exhausted_ballots
transferable_votes = total_votes.to_num() - exhausted_votes.to_num()
transferable_ballots = total_ballots - exhausted_ballots # Num
transferable_votes = total_votes - exhausted_votes # Rational
__pragma__('noopov')
for candidate, x in next_preferences.items():
cand_ballots = x[0]
num_ballots = x[1]
num_votes = x[2]
num_ballots = x[1] # Num
num_votes = x[2] # Rational
new_parcel = []
if len(cand_ballots) > 0:
@ -619,11 +641,11 @@ class UIGSTVCounter(WIGSTVCounter):
__pragma__('opov')
if self.options['papers'] == 'transferable':
if transferable_votes > surplus:
new_value = (ballot.value * surplus) / transferable_ballots
new_value = (ballot.value * surplus).to_rational() / transferable_ballots.to_rational()
else:
new_value = ballot_value
else:
new_value = (ballot.value * surplus) / total_ballots
new_value = (ballot.value * surplus).to_rational() / total_ballots.to_rational()
new_parcel.append((ballot, new_value))
__pragma__('noopov')