def test_bulk_athena(): # Same as Minerva (that is, delta = infinity) # Ballot-by-ballot Minerva should yield identical stopping rules to BRAVO. contest = Contest(100000, { 'A': 60000, 'B': 40000 }, 1, ['A'], ContestType.MAJORITY) athena = Athena(.1, 2**31 - 1, .01, contest) athena.compute_all_min_winner_ballots(athena.sub_audits['A-B']) # p0 not hardcoded as .5 for scalability with odd total contest ballots. p0 = (athena.contest.contest_ballots // 2) / athena.contest.contest_ballots log_winner_multiplier = math.log( athena.sub_audits['A-B'].sub_contest.winner_prop / p0) log_loser_multiplier = math.log( (1 - athena.sub_audits['A-B'].sub_contest.winner_prop) / p0) log_rhs = math.log(1 / athena.alpha) for i in range(len(athena.rounds)): n = athena.rounds[i] kmin = athena.sub_audits['A-B'].min_winner_ballots[i] # Assert this kmin satisfies ratio, but a kmin one less does not. assert kmin * log_winner_multiplier + ( n - kmin) * log_loser_multiplier > log_rhs assert (kmin - 1) * log_winner_multiplier + ( n - kmin + 1) * log_loser_multiplier <= log_rhs
def test_exceptions(): contest = Contest(100000, { 'A': 60000, 'B': 40000 }, 1, ['A'], ContestType.MAJORITY) with pytest.raises(ValueError): Athena(.1, 0, .1, contest) athena = Athena(.1, 1, .1, contest) with pytest.raises(Exception): athena.stopping_condition_pairwise('A-B') athena.rounds.append(10) with pytest.raises(ValueError): athena.stopping_condition_pairwise('X') athena.rounds = [] with pytest.raises(ValueError): athena.compute_min_winner_ballots(athena.sub_audits['A-B'], []) with pytest.raises(ValueError): athena.compute_min_winner_ballots(athena.sub_audits['A-B'], [0]) with pytest.raises(ValueError): athena.compute_min_winner_ballots(athena.sub_audits['A-B'], [1, 2]) with pytest.raises(ValueError): athena.compute_min_winner_ballots(athena.sub_audits['A-B'], [20, 20]) with pytest.raises(ValueError): athena.compute_min_winner_ballots(athena.sub_audits['A-B'], [20, 19]) with pytest.raises(ValueError): athena.compute_min_winner_ballots(athena.sub_audits['A-B'], [10001]) athena.compute_min_winner_ballots(athena.sub_audits['A-B'], [20]) with pytest.raises(ValueError): athena.compute_min_winner_ballots(athena.sub_audits['A-B'], [20]) with pytest.raises(ValueError): athena.compute_min_winner_ballots(athena.sub_audits['A-B'], [19]) with pytest.raises(ValueError): athena.compute_min_winner_ballots(athena.sub_audits['A-B'], [10001]) contest2 = Contest(100, {'A': 60, 'B': 30}, 1, ['A'], ContestType.MAJORITY) athena2 = Athena(0.1, 1, 1.0, contest2) with pytest.raises(ValueError): athena2.compute_min_winner_ballots(athena2.sub_audits['A-B'], [91]) athena2.rounds.append(10) with pytest.raises(Exception): athena2.compute_all_min_winner_ballots(athena2.sub_audits['A-B']) athena2.rounds = [] with pytest.raises(ValueError): athena2.compute_all_min_winner_ballots(athena2.sub_audits['A-B'], 0) with pytest.raises(ValueError): athena2.compute_all_min_winner_ballots(athena2.sub_audits['A-B'], 200) with pytest.raises(ValueError): athena2.compute_all_min_winner_ballots(athena2.sub_audits['A-B'], 0)