2020-12-31 01:52:04 +11:00
# pyRCV2: Preferential vote counting
2021-01-01 22:26:57 +11:00
# Copyright © 2020–2021 Lee Yingtong Li (RunasSudo)
2020-12-31 01:52:04 +11:00
#
# 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/>.
2021-01-03 01:23:11 +11:00
from pytest import approx
2020-12-31 17:00:23 +11:00
from pytest_steps import test_steps
2020-12-31 01:52:04 +11:00
import pyRCV2 . blt
import pyRCV2 . numbers
2021-01-08 19:21:33 +11:00
from pyRCV2 . method . gregory import UIGSTVCounter
2020-12-31 01:52:04 +11:00
from pyRCV2 . model import CandidateState , CountCompleted
import csv
import gzip
2020-12-31 17:00:23 +11:00
# Read model CSV
2021-01-02 23:34:09 +11:00
with open ( ' tests/data/aec-senate-formalpreferences-24310-TAS.csv ' , ' r ' , newline = ' ' ) as f :
2020-12-31 17:00:23 +11:00
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 ) ] )
2020-12-31 01:52:04 +11:00
def test_aec_tas19 ( ) :
""" Compare count of aec-senate-formalpreferences-24310-TAS.blt.gz with model result at https://results.aec.gov.au/24310/Website/External/SenateStateDop-24310-TAS.pdf """
2021-01-03 01:23:11 +11:00
pyRCV2 . numbers . set_numclass ( pyRCV2 . numbers . Native )
2020-12-31 01:52:04 +11:00
2021-01-02 23:34:09 +11:00
with gzip . open ( ' tests/data/aec-senate-formalpreferences-24310-TAS.blt.gz ' , ' rt ' ) as f :
2020-12-31 01:52:04 +11:00
election = pyRCV2 . blt . readBLT ( f . read ( ) )
assert len ( election . candidates ) == len ( candidates )
counter = UIGSTVCounter ( election , {
' surplus_order ' : ' order ' ,
2021-01-03 01:23:11 +11:00
' exclusion ' : ' by_value ' ,
2021-01-15 16:00:22 +11:00
' bulk_exclude ' : True ,
2021-01-01 22:26:57 +11:00
' round_quota ' : 0 ,
2021-01-03 01:23:11 +11:00
' round_votes ' : 0 ,
2020-12-31 01:52:04 +11:00
} )
result = counter . reset ( )
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 ]
2021-01-03 01:23:11 +11:00
assert result . comment == comment , ' Failed to verify comment '
2020-12-31 01:52:04 +11:00
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 )
2021-01-03 01:23:11 +11:00
assert cc . votes . impl == approx ( votes . impl ) , ' Failed to verify candidate " {} " votes, got {} expected {} ' . format ( cand , cc . votes . pp ( 0 ) , votes . pp ( 0 ) )
2020-12-31 01:52:04 +11:00
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 }
2021-01-03 01:23:11 +11:00
assert cc . state == accept [ state ] , ' Failed to verify candidate " {} " state ' . format ( cand )
2020-12-31 01:52:04 +11:00
exhausted = pyRCV2 . numbers . Num ( data [ len ( candidates ) + 2 ] [ i ] )
2021-01-03 01:23:11 +11:00
assert result . exhausted . votes . impl == approx ( exhausted . impl ) , ' Failed to verify exhausted votes, got {} expected {} ' . format ( result . exhausted . votes . pp ( 0 ) , exhausted . pp ( 0 ) )
2020-12-31 01:52:04 +11:00
loss_fraction = pyRCV2 . numbers . Num ( data [ len ( candidates ) + 3 ] [ i ] )
2021-01-03 01:23:11 +11:00
assert result . loss_fraction . votes . impl == approx ( loss_fraction . impl ) , ' Failed to verify loss to fraction, got {} expected {} ' . format ( result . loss_fraction . votes . pp ( 0 ) , loss_fraction . pp ( 0 ) )
2020-12-31 17:00:23 +11:00
yield ' Stage {} ' . format ( stage )