Fix bug where withdrawn candidates would interfere with bulk exclusion, etc. logic

This commit is contained in:
RunasSudo 2021-01-15 16:00:22 +11:00
parent 1369fb3cfc
commit 1e2f74e60b
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
3 changed files with 10 additions and 4 deletions

View File

@ -66,12 +66,14 @@ class BaseSTVCounter:
self.step_results = []
self.num_elected = 0
self.num_excluded = 0
self.num_withdrawn = 0
# Withdraw candidates
for candidate in self.election.withdrawn:
__pragma__('opov')
self.candidates[candidate].state = CandidateState.WITHDRAWN
__pragma__('noopov')
self.num_withdrawn += 1
def reset(self):
"""
@ -177,7 +179,7 @@ class BaseSTVCounter:
# Are there just enough candidates to fill all the seats?
if self.options['bulk_elect']:
# Include EXCLUDING to avoid interrupting an exclusion
if len(self.election.candidates) - self.num_excluded + sum(1 for c, cc in self.candidates.items() if cc.state == CandidateState.EXCLUDING) <= self.election.seats:
if len(self.election.candidates) - self.num_withdrawn - self.num_excluded + sum(1 for c, cc in self.candidates.items() if cc.state == CandidateState.EXCLUDING) <= self.election.seats:
# Declare elected all remaining candidates
candidates_elected = [(c, cc) for c, cc in self.candidates.items() if cc.state == CandidateState.HOPEFUL]
if len(candidates_elected) == 1:
@ -295,7 +297,7 @@ class BaseSTVCounter:
# If we did not perform bulk election in before_surpluses: Are there just enough candidates to fill all the seats?
if not self.options['bulk_elect']:
if len(self.election.candidates) - self.num_excluded <= self.election.seats:
if len(self.election.candidates) - self.num_withdrawn - self.num_excluded <= self.election.seats:
# Declare elected one remaining candidate at a time
hopefuls = [(c, cc) for c, cc in self.candidates.items() if cc.state == CandidateState.HOPEFUL]
hopefuls.sort(key=lambda x: x[1].votes, reverse=True)
@ -367,7 +369,7 @@ class BaseSTVCounter:
Returns List[Tuple[Candidate, CountCard]]
"""
remaining_candidates = len(self.election.candidates) - self.num_excluded
remaining_candidates = len(self.election.candidates) - self.num_withdrawn - self.num_excluded
__pragma__('opov')
total_surpluses = sum((cc.votes - self.quota for c, cc in self.candidates.items() if cc.votes > self.quota), Num(0))
__pragma__('noopov')

View File

@ -47,6 +47,7 @@ def test_aec_tas19():
counter = UIGSTVCounter(election, {
'surplus_order': 'order',
'exclusion': 'by_value',
'bulk_exclude': True,
'round_quota': 0,
'round_votes': 0,
})

View File

@ -59,6 +59,9 @@ def maketst(numbers, counter_cls, options, options_description):
return t_py, t_js
test_prsa1_scottish_py, test_prsa1_scottish_js = maketst('Fixed', 'pyRCV2.method.gregory.WIGSTVCounter', {'round_quota': 0}, '--round-quota 0')
test_prsa1_senate_py, test_prsa1_senate_js = maketst('Fixed', 'pyRCV2.method.gregory.UIGSTVCounter', {'surplus_order': 'order', 'exclusion': 'by_value', 'round_quota': 3, 'round_votes': 3, 'round_tvs': 3, 'round_weights': 3}, '--method uig --round-quota 3 --round-votes 3 --round-tvs 3 --round-weights 3 --surplus-order order --exclusion by_value')
test_prsa1_senate_py, test_prsa1_senate_js = maketst('Fixed', 'pyRCV2.method.gregory.UIGSTVCounter', {'surplus_order': 'order', 'exclusion': 'by_value', 'bulk_exclude': True, 'round_quota': 0, 'round_votes': 0}, '--method uig --bulk-exclude --round-quota 0 --round-votes 0 --surplus-order order --exclusion by_value')
test_prsa1_meek_py, test_prsa1_meek_js = maketst('Fixed', 'pyRCV2.method.meek.MeekSTVCounter', {'quota_criterion': 'gt', 'quota': 'droop_exact', 'quota_mode': 'progressive'}, '--method meek --quota droop_exact --quota-criterion gt --quota-mode progressive')
test_prsa1_wright_py, test_prsa1_wright_js = maketst('Fixed', 'pyRCV2.method.gregory.WIGSTVCounter', {'exclusion': 'wright', 'round_quota': 0, 'bulk_exclude': True}, '--bulk-exclude --round-quota 0 --exclusion wright')
# Regression test: Withdrawn candidates interfering with bulk exclusion
test_meekm_senate_py, test_meekm_senate_js = maketst('Fixed', 'pyRCV2.method.gregory.UIGSTVCounter', {'surplus_order': 'order', 'exclusion': 'by_value', 'bulk_exclude': True, 'round_quota': 0, 'round_votes': 0}, '--method uig --bulk-exclude --round-quota 0 --round-votes 0 --surplus-order order --exclusion by_value')