Refactor/clean up (un)weighted inclusive Gregory handling

This commit is contained in:
RunasSudo 2020-12-23 20:03:15 +11:00
parent f73e2eaa53
commit 5f4d6aa7ca
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
5 changed files with 50 additions and 63 deletions

View File

@ -31,6 +31,8 @@ class BaseSTVCounter:
def __init__(self, election, options=None):
self.election = election
self.cls_ballot_value = Num # Need to use Rational in unweighted inclusive Gregory
# Default options
self.options = {
'prog_quota': False, # Progressively reducing quota?
@ -60,9 +62,35 @@ class BaseSTVCounter:
"""
Public function:
Reset the count and perform the first step
Subclasses must override this function
"""
raise NotImplementedError('Method not implemented')
# Distribute first preferences
for ballot in self.election.ballots:
__pragma__('opov')
candidate = next((c for c in ballot.preferences if self.candidates[c].state == CandidateState.HOPEFUL), None)
if candidate is not None:
self.candidates[candidate].transfers += ballot.value
self.candidates[candidate].ballots.append((ballot, self.cls_ballot_value(ballot.value)))
else:
self.exhausted.transfers += ballot.value
self.exhausted.ballots.append((ballot, self.cls_ballot_value(ballot.value)))
__pragma__('noopov')
self.quota = None
self.compute_quota()
self.elect_meeting_quota()
__pragma__('opov')
return CountStepResult(
'First preferences',
self.candidates,
self.exhausted,
self.loss_fraction,
self.total + self.exhausted.votes + self.loss_fraction.votes,
self.quota
)
__pragma__('noopov')
def step(self):
"""
@ -295,35 +323,6 @@ class BaseWIGSTVCounter(BaseSTVCounter):
Basic weighted inclusive Gregory STV counter
"""
def reset(self):
# Distribute first preferences
for ballot in self.election.ballots:
__pragma__('opov')
candidate = next((c for c in ballot.preferences if self.candidates[c].state == CandidateState.HOPEFUL), None)
if candidate is not None:
self.candidates[candidate].transfers += ballot.value
self.candidates[candidate].ballots.append((ballot, ballot.value))
else:
self.exhausted.transfers += ballot.value
self.exhausted.ballots.append((ballot, ballot.value))
__pragma__('noopov')
self.quota = None
self.compute_quota()
self.elect_meeting_quota()
__pragma__('opov')
return CountStepResult(
'First preferences',
self.candidates,
self.exhausted,
self.loss_fraction,
self.total + self.exhausted.votes + self.loss_fraction.votes,
self.quota
)
__pragma__('noopov')
def do_surplus(self, candidate_surplus, count_card, surplus):
for ballot, ballot_value in count_card.ballots:
__pragma__('opov')
@ -357,34 +356,10 @@ class BaseUIGSTVCounter(BaseSTVCounter):
Basic unweighted inclusive Gregory STV counter
"""
def reset(self):
# Distribute first preferences
for ballot in self.election.ballots:
__pragma__('opov')
candidate = next((c for c in ballot.preferences if self.candidates[c].state == CandidateState.HOPEFUL), None)
if candidate is not None:
self.candidates[candidate].transfers += ballot.value
self.candidates[candidate].ballots.append((ballot, Rational(ballot.value.pp(0))))
else:
self.exhausted.transfers += ballot.value
self.exhausted.ballots.append((ballot, Rational(ballot.value.pp(0))))
__pragma__('noopov')
self.quota = None
self.compute_quota()
self.elect_meeting_quota()
__pragma__('opov')
return CountStepResult(
'First preferences',
self.candidates,
self.exhausted,
self.loss_fraction,
self.total + self.exhausted.votes + self.loss_fraction.votes,
self.quota
)
__pragma__('noopov')
def __init__(self, *args, **kwargs):
BaseSTVCounter.__init__(self, *args, **kwargs)
# Need to use Rational for ballot value internally, as Num may be set to integers only
self.cls_ballot_value = Rational
def do_surplus(self, candidate_surplus, count_card, surplus):
# FIXME: Is it okay to use native int's here?

View File

@ -25,7 +25,10 @@ class Fixed:
"""
def __init__(self, val):
self.impl = Big(val)
if isinstance(val, Fixed):
self.impl = val.impl
else:
self.impl = Big(val)
def pp(self, dp):
"""Pretty print to specified number of decimal places"""

View File

@ -20,7 +20,10 @@ class NativeInt:
"""
def __init__(self, val):
self.impl = Math.floor(parseFloat(val))
if isinstance(val, NativeInt):
self.impl = val.impl
else:
self.impl = Math.floor(parseFloat(val))
def pp(self, dp):
"""Pretty print to specified number of decimal places"""

View File

@ -20,7 +20,10 @@ class Native:
"""
def __init__(self, val):
self.impl = parseFloat(val)
if isinstance(val, Native):
self.impl = val.impl
else:
self.impl = parseFloat(val)
def pp(self, dp):
"""Pretty print to specified number of decimal places"""

View File

@ -20,7 +20,10 @@ class Rational:
"""
def __init__(self, val):
self.impl = bigRat(val)
if isinstance(val, Rational):
self.impl = val.impl
else:
self.impl = bigRat(val)
def pp(self, dp):
"""