Add test case for ERS97

This commit is contained in:
RunasSudo 2021-01-04 20:46:38 +11:00
parent 64d23751a5
commit a0709e4506
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
3 changed files with 101 additions and 0 deletions

15
tests/data/ers97.csv Normal file
View File

@ -0,0 +1,15 @@
Stage:,1,,2,,3,,4,,5,,6,,7,,8,
Comment:,First preferences,,Surplus of Smith,,Exclusion of Monk,,Exclusion of Monk,,"Exclusion of Glazier, Wright",,"Exclusion of Glazier, Wright",,Surplus of Carpenter,,Exclusion of Abbot,
Smith,134,PEL,107.58,EL,107.58,EL,107.58,EL,107.58,EL,107.58,EL,107.58,EL,107.58,EL
Carpenter,81,,88.35,,88.35,,88.35,,122.35,PEL,122.35,PEL,107.58,EL,107.58,EL
Wright,27,,32.25,,32.25,,32.25,,5.25,EXCLUDING,0,EX,0,EX,0,EX
Glazier,24,,30.51,,30.51,,30.51,,6.51,EXCLUDING,0,EX,0,EX,0,EX
Duke,105,,106.68,,108.68,PEL,108.68,PEL,108.68,PEL,108.68,PEL,108.68,PEL,108.68,PEL
Prince,91,,91,,91,,91,,102,,104.31,,104.31,PEL,104.31,PEL
Baron,64,,64,,64,,64.21,,67.21,,68.26,,70.26,,82.26,
Abbot,59,,59.84,,64.84,,64.84,,65.84,,67.1,,68.1,,2.1,EXCLUDING
Vicar,55,,55,,69,,69.21,,69.21,,71.31,,71.31,,113.31,PEL
Monk,23,,23.42,,0.42,EXCLUDING,0,EX,0,EX,0,EX,0,EX,0,EX
Freeman,90,,93.78,,95.78,,95.78,,95.78,,96.62,,101.62,,101.62,PEL
Non-transferable,0,,0.59,,0.59,,0.59,,2.59,,6.79,,13.56,,25.56,
Votes required,,,,,,,,,,,105.87,,104.13,,96.41,
1 Stage: 1 2 3 4 5 6 7 8
2 Comment: First preferences Surplus of Smith Exclusion of Monk Exclusion of Monk Exclusion of Glazier, Wright Exclusion of Glazier, Wright Surplus of Carpenter Exclusion of Abbot
3 Smith 134 PEL 107.58 EL 107.58 EL 107.58 EL 107.58 EL 107.58 EL 107.58 EL 107.58 EL
4 Carpenter 81 88.35 88.35 88.35 122.35 PEL 122.35 PEL 107.58 EL 107.58 EL
5 Wright 27 32.25 32.25 32.25 5.25 EXCLUDING 0 EX 0 EX 0 EX
6 Glazier 24 30.51 30.51 30.51 6.51 EXCLUDING 0 EX 0 EX 0 EX
7 Duke 105 106.68 108.68 PEL 108.68 PEL 108.68 PEL 108.68 PEL 108.68 PEL 108.68 PEL
8 Prince 91 91 91 91 102 104.31 104.31 PEL 104.31 PEL
9 Baron 64 64 64 64.21 67.21 68.26 70.26 82.26
10 Abbot 59 59.84 64.84 64.84 65.84 67.1 68.1 2.1 EXCLUDING
11 Vicar 55 55 69 69.21 69.21 71.31 71.31 113.31 PEL
12 Monk 23 23.42 0.42 EXCLUDING 0 EX 0 EX 0 EX 0 EX 0 EX
13 Freeman 90 93.78 95.78 95.78 95.78 96.62 101.62 101.62 PEL
14 Non-transferable 0 0.59 0.59 0.59 2.59 6.79 13.56 25.56
15 Votes required 105.87 104.13 96.41

BIN
tests/data/ers97.ods Normal file

Binary file not shown.

86
tests/test_ers97.py Normal file
View File

@ -0,0 +1,86 @@
# pyRCV2: Preferential vote counting
# Copyright © 2020–2021 Lee Yingtong Li (RunasSudo)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from pytest_steps import test_steps
import pyRCV2.blt
import pyRCV2.numbers
from pyRCV2.method.base_stv import EGSTVCounter
from pyRCV2.model import CandidateState, CountCompleted
import csv
# Read model CSV
with open('tests/data/ers97.csv', 'r', newline='') as f:
reader = csv.reader(f)
data = [x for x in reader]
candidates = [data[i][0] for i in range(2, len(data) - 2)]
@test_steps(*['Stage {}'.format(data[0][i]) for i in range(1, len(data[0]), 2)])
def test_aec_tas19():
"""Compare count of ers97.blt with model result computed by hand"""
pyRCV2.numbers.set_numclass(pyRCV2.numbers.Fixed)
pyRCV2.numbers.set_dps(5)
with open('tests/data/ers97.blt', 'r') as f:
election = pyRCV2.blt.readBLT(f.read())
assert len(election.candidates) == len(candidates)
counter = EGSTVCounter(election, {
'quota': 'droop_exact',
'quota_mode': 'ers97',
'bulk_exclude': True,
'defer_surpluses': True,
'round_quota': 2,
'round_votes': 2,
'round_tvs': 2,
'round_weights': 2,
'papers': 'transferable',
'exclusion': 'by_value',
})
result = counter.reset()
assert result.quota == pyRCV2.numbers.Num('107.58')
for i in range(1, len(data[0]), 2):
stage = int(data[0][i])
while len(counter.step_results) < stage:
result = counter.step()
comment = data[1][i]
assert result.comment == comment, 'Failed to verify comment'
for j, cand in enumerate(candidates):
votes = pyRCV2.numbers.Num(data[j + 2][i])
cc = next(cc for c, cc in result.candidates.items() if c.name == cand)
assert cc.votes == votes, 'Failed to verify candidate "{}" votes, got {} expected {}'.format(cand, cc.votes.pp(0), votes.pp(0))
state = data[j + 2][i + 1] if len(data[j + 2]) > (i + 1) else ''
accept = {'': CandidateState.HOPEFUL, 'PEL': CandidateState.PROVISIONALLY_ELECTED, 'EL': CandidateState.ELECTED, 'EX': CandidateState.EXCLUDED, 'EXCLUDING': CandidateState.EXCLUDING}
assert cc.state == accept[state], 'Failed to verify candidate "{}" state'.format(cand)
nontransferable = pyRCV2.numbers.Num(data[len(candidates) + 2][i])
assert (result.exhausted.votes + result.loss_fraction.votes) == nontransferable, 'Failed to verify non-transferable votes, got {} expected {}'.format((result.exhausted.votes + result.loss_fraction.votes).pp(2), nontransferable.pp(2))
if data[len(candidates) + 3][i]:
votes_required = pyRCV2.numbers.Num(data[len(candidates) + 3][i])
assert result.vote_required_election.pp(2) == votes_required.pp(2), 'Failed to verify votes required for election, got {} expected {}'.format(result.vote_required_election.pp(2), votes_required.pp(2))
yield 'Stage {}'.format(stage)