Fix bug attempting to defer surplus with 0 or 1 continuing candidates

Add regression test
This commit is contained in:
RunasSudo 2021-09-09 13:36:27 +10:00
parent 3b41eae11b
commit ab3067566d
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
3 changed files with 111 additions and 1 deletions

View File

@ -1114,6 +1114,11 @@ where
let mut hopefuls: Vec<(&&Candidate, &CountCard<N>)> = state.candidates.iter()
.filter(|(_, cc)| cc.state == CandidateState::Hopeful || cc.state == CandidateState::Guarded)
.collect();
if hopefuls.len() < 2 {
return true;
}
hopefuls.sort_unstable_by(|(_, cc1), (_, cc2)| cc1.votes.cmp(&cc2.votes));
if total_surpluses > &(&hopefuls[1].1.votes - &hopefuls[0].1.votes) {
return false;

70
tests/data/A34.blt Normal file
View File

@ -0,0 +1,70 @@
# Comment: BY STV
# Comment: Number of truncated papers: 0
# Comment: AKA R039 in Wichmann's database
# Source: Nicolaus Tideman via Warren D Smith <https://rangevoting.org/TidemanData.html>
14 12
1 9 8 4 5 0
1 9 12 1 14 4 10 0
1 14 1 2 10 5 7 11 13 3 4 12 0
1 2 7 10 6 0
1 7 6 0
1 7 11 10 1 5 6 14 2 8 4 12 3 0
1 7 8 10 6 12 14 4 11 0
1 11 4 10 3 13 8 14 2 12 7 6 1 0
1 11 3 7 10 4 13 2 1 6 14 8 12 0
1 11 1 13 12 9 10 6 5 4 3 2 7 0
1 11 14 12 10 1 6 7 8 4 0
1 14 3 4 5 12 13 6 9 0
1 2 3 11 7 8 14 9 13 0
1 3 2 7 11 6 5 14 1 12 8 4 10 0
1 3 8 12 1 13 2 14 4 11 10 7 6 0
1 3 11 4 5 8 12 10 13 0
1 3 11 10 13 4 1 2 5 14 12 7 8 6 0
1 5 2 1 8 12 10 0
1 5 4 1 2 6 12 10 8 13 14 3 7 0
1 5 8 6 7 10 12 1 4 11 0
1 2 6 8 4 5 10 12 14 7 1 11 3 0
1 2 6 14 10 4 1 8 13 5 12 0
1 6 2 10 8 7 11 12 1 14 3 0
1 6 14 8 4 5 12 1 0
1 6 11 14 7 1 13 8 2 3 10 12 4 5 9 0
1 5 10 13 12 2 6 4 11 7 1 8 0
1 10 8 13 4 1 7 14 11 6 12 5 2 3 0
1 13 8 12 5 14 4 0
1 13 12 8 4 0
1 13 10 6 4 14 8 11 3 1 7 2 12 5 0
1 13 10 6 4 14 8 11 3 1 7 2 12 5 0
1 14 12 13 10 5 4 6 2 11 8 7 1 3 9 0
1 14 8 10 2 1 12 11 6 5 7 3 4 0
1 14 12 2 5 8 10 1 11 6 13 4 3 0
1 5 8 14 2 12 6 4 0
1 5 12 6 2 1 4 7 10 11 9 8 3 14 13 0
1 5 8 14 2 12 4 6 0
1 10 12 8 13 3 7 6 5 4 11 14 1 0
1 10 2 14 12 8 6 5 11 13 1 4 3 7 9 0
1 2 5 12 13 14 8 1 7 10 11 3 6 0
1 12 10 13 4 1 11 14 6 0
1 12 10 6 13 11 3 2 1 4 14 8 0
1 10 1 8 11 7 6 4 13 3 14 2 12 5 9 0
1 10 2 8 1 4 5 11 0
1 10 14 1 4 5 8 12 6 13 2 3 7 9 11 0
1 2 10 1 5 14 4 7 9 12 3 6 0
1 1 12 2 10 11 13 3 4 6 7 8 14 0
1 1 7 6 10 11 2 9 4 8 12 0
1 1 2 13 4 3 10 9 5 11 12 14 8 6 7 0
1 5 4 12 10 2 0
1 10 4 1 6 8 14 11 12 13 2 7 3 0
1 10 4 1 2 14 5 6 13 8 12 0
1 2 4 5 1 9 10 12 14 0
1 2 4 10 13 14 1 5 11 12 7 3 8 6 0
1 4 8 12 5 2 10 0
1 4 10 13 9 5 12 8 2 1 14 11 7 6 3 0
1 4 10 1 14 11 6 2 5 8 7 13 12 0
1 8 10 5 1 6 7 11 4 14 13 3 12 2 9 0
1 8 14 13 11 7 12 4 10 1 3 2 6 0
1 8 10 14 4 1 11 6 5 12 7 2 0
1 8 10 5 6 11 7 3 12 13 4 0
1 8 6 7 5 11 13 3 0
1 2 0
0
"A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "f:a34"

View File

@ -86,7 +86,7 @@ fn tideman_a33_ers97_rational() {
.quota(stv::QuotaType::DroopExact)
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
.quota_mode(stv::QuotaMode::ERS97)
.ties(vec![TieStrategy::Random(String::new("20210908"))])
.ties(vec![TieStrategy::Random(String::from("20210908"))])
.surplus(stv::SurplusMethod::EG)
.transferable_only(true)
.exclusion(stv::ExclusionMethod::ByValue)
@ -113,3 +113,38 @@ fn tideman_a33_ers97_rational() {
let num_winners = state.candidates.values().filter(|cc| cc.state == CandidateState::Elected).count();
assert_eq!(num_winners, 3);
}
/// Tideman A34 election: surplus deferred with only 1 hopeful
#[test]
fn tideman_a34_prsa1977_rational() {
let stv_opts = stv::STVOptionsBuilder::default()
.round_surplus_fractions(Some(3))
.round_values(Some(3))
.round_votes(Some(3))
.round_quota(Some(3))
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
.ties(vec![TieStrategy::Backwards, TieStrategy::Random(String::from("0"))])
.surplus(stv::SurplusMethod::EG)
.surplus_order(stv::SurplusOrder::ByOrder)
.transferable_only(true)
.exclusion(stv::ExclusionMethod::ParcelsByOrder)
.early_bulk_elect(false)
.build().unwrap();
let mut election: Election<Rational> = blt::parse_path("tests/data/A34.blt").expect("Syntax Error");
stv::preprocess_election(&mut election, &stv_opts);
let mut state = CountState::new(&election);
stv::count_init(&mut state, &stv_opts).unwrap();
loop {
let result = stv::count_one_stage::<Rational>(&mut state, &stv_opts);
match result {
Ok(done) => { if done { break; } }
Err(err) => { panic!("{}", err); }
}
}
// Assert count completes
}