Add test case for NZ Meek STV

This commit is contained in:
RunasSudo 2021-06-20 01:37:51 +10:00
parent 1b39b8b138
commit cd42899ba8
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
6 changed files with 83 additions and 2 deletions

View File

@ -8,7 +8,8 @@ The preset dropdown allows you to choose from a hardcoded list of preloaded STV
* *Scottish STV*: Rules from the [*Scottish Local Government Elections Order 2011*](https://www.legislation.gov.uk/ssi/2011/399/schedule/1/made), using the weighted inclusive Gregory method. Validated against the [2007 Scottish local government election result for Linn ward](https://web.archive.org/web/20121004213938/http://www.glasgow.gov.uk/en/YourCouncil/Elections_Voting/Election_Results/ElectionScotland2007/LGWardResults.htm?ward=1&wardname=1%20-%20Linn).
* [*Meek STV*](http://www.dia.govt.nz/diawebsite.NSF/Files/meekm/%24file/meekm.pdf): Advanced STV rules designed for computer counting, recognised by the Proportional Representation Society of Australia (Victoria–Tasmania) as the superior STV system.
* *Meek STV (1987)* operates according to the original [Hill–Wichmann–Woodall specification](https://www.dia.govt.nz/diawebsite.NSF/Files/meekm/%24file/meekm.pdf) of Meek STV, with the modifications, relevant only in exceptional cases, that (a) fixed-point arithmetic with 5 decimal places is used, and (b) candidates are elected on strictly exceeding the quota. Validated against the Hill–Wichmann–Woodall implementation for the [ERS97 model election](https://www.electoral-reform.org.uk/latest-news-and-research/publications/how-to-conduct-an-election-by-the-single-transferable-vote-3rd-edition/#sub-section-24).
* *Meek STV (2006)* operates according to [Hill's 2006 revisions](http://www.votingmatters.org.uk/ISSUE22/I22P2.pdf). This is the algorithm referred to in OpenSTV/OpaVote as ‘Meek STV’, and forms the basis of New Zealand's Meek STV rules. Validated against OpenSTV for the ERS97 model election.
* *Meek STV (2006)* operates according to [Hill's 2006 revisions](http://www.votingmatters.org.uk/ISSUE22/I22P2.pdf). This is the algorithm referred to in OpenSTV/OpaVote as ‘Meek STV’, and forms the basis of New Zealand's Meek STV rules. Validated against OpenSTV 1.7 for the ERS97 model election.
* *Meek STV (New Zealand)* operates according to Schedule 1A of the [*Local Electoral Regulations 2001*](https://www.legislation.govt.nz/regulation/public/2001/0145/latest/DLM57125.html). Validated against OpenSTV 1.7 for the ERS97 model election.
* *Australian Senate STV*: Rules from the [*Commonwealth Electoral Act 1918*](https://www.legislation.gov.au/Details/C2020C00400/Html/Text#_Toc59107700), using the unweighted inclusive Gregory method. Validated against the [2019 Australian Senate election result for Tasmania](https://results.aec.gov.au/24310/Website/SenateDownloadsMenu-24310-Csv.htm).
* [*PRSA 1977*](https://www.prsa.org.au/rule1977.htm): Simple rules designed for hand counting, using the exclusive Gregory method, with counting automatically performed in thousandths of a vote. Validated against [example 1](https://www.prsa.org.au/example1.pdf) of the PRSA's [*Proportional Representation Manual*](https://www.prsa.org.au/publicat.htm#p2).
* [*ERS97*](https://www.electoral-reform.org.uk/latest-news-and-research/publications/how-to-conduct-an-election-by-the-single-transferable-vote-3rd-edition/): More complex rules designed for hand counting, using the exclusive Gregory method. Validated against the ERS97 model election.

View File

@ -70,6 +70,7 @@ fn aec_tas19_rational() {
surplus_order: stv::SurplusOrder::ByOrder,
transferable_only: false,
exclusion: stv::ExclusionMethod::ByValue,
meek_nz_exclusion: false,
bulk_exclude: true,
defer_surpluses: false,
meek_immediate_elect: false,

View File

@ -38,6 +38,7 @@ fn ers97_rational() {
surplus_order: stv::SurplusOrder::BySize,
transferable_only: true,
exclusion: stv::ExclusionMethod::ByValue,
meek_nz_exclusion: false,
bulk_exclude: true,
defer_surpluses: true,
meek_immediate_elect: false,

View File

@ -43,6 +43,7 @@ fn meek87_ers97_float64() {
surplus_order: stv::SurplusOrder::BySize,
transferable_only: false,
exclusion: stv::ExclusionMethod::SingleStage,
meek_nz_exclusion: false,
bulk_exclude: false,
defer_surpluses: false,
meek_immediate_elect: false,
@ -51,7 +52,7 @@ fn meek87_ers97_float64() {
utils::read_validate_election::<NativeFloat64>("tests/data/ers97_meek.csv", "tests/data/ers97.blt", stv_opts, Some(2), &["exhausted", "quota"]);
}
// Compare ers97.blt count with result produced by OpenSTV "Meek STV"
// Compare ers97.blt count with result produced by OpenSTV 1.7 "Meek STV"
#[test]
fn meek06_ers97_fixed12() {
let stv_opts = stv::STVOptions {
@ -70,6 +71,7 @@ fn meek06_ers97_fixed12() {
surplus_order: stv::SurplusOrder::BySize,
transferable_only: false,
exclusion: stv::ExclusionMethod::SingleStage,
meek_nz_exclusion: false,
bulk_exclude: false,
defer_surpluses: true,
meek_immediate_elect: true,
@ -122,3 +124,76 @@ fn meek06_ers97_fixed12() {
}
}
}
// Compare ers97.blt count with result produced by OpenSTV 1.7 "New Zealand Meek STV"
#[test]
fn meeknz_ers97_fixed12() {
let stv_opts = stv::STVOptions {
round_tvs: Some(9),
round_weights: Some(9),
round_votes: Some(9),
round_quota: Some(9),
sum_surplus_transfers: stv::SumSurplusTransfersMode::SingleStep,
meek_surplus_tolerance: String::from("0.0001"),
normalise_ballots: false,
quota: stv::QuotaType::Droop,
quota_criterion: stv::QuotaCriterion::GreaterOrEqual,
quota_mode: stv::QuotaMode::Static,
ties: vec![],
surplus: stv::SurplusMethod::Meek,
surplus_order: stv::SurplusOrder::BySize,
transferable_only: false,
exclusion: stv::ExclusionMethod::SingleStage,
meek_nz_exclusion: true,
bulk_exclude: false,
defer_surpluses: true,
meek_immediate_elect: true,
pp_decimals: 2,
};
Fixed::set_dps(12);
// Read BLT
let file = File::open("tests/data/ers97.blt").expect("IO Error");
let file_reader = io::BufReader::new(file);
let lines = file_reader.lines();
let election: Election<Fixed> = Election::from_blt(lines.map(|r| r.expect("IO Error").to_string()).into_iter());
// Initialise count state
let mut state = CountState::new(&election);
// Count to completion
stv::count_init(&mut state, &stv_opts);
while !stv::count_one_stage(&mut state, &stv_opts).unwrap() {}
// Check states and keep values
for (candidate, count_card) in state.candidates.iter() {
match candidate.name.as_str() {
"Smith" => {
assert!(count_card.state == CandidateState::Elected);
assert_eq!(count_card.keep_value, Some(Fixed::parse("0.452154292")));
}
"Carpenter" => {
assert!(count_card.state == CandidateState::Elected);
assert_eq!(count_card.keep_value, Some(Fixed::parse("0.614574172")));
}
"Duke" => {
assert!(count_card.state == CandidateState::Elected);
assert_eq!(count_card.keep_value, Some(Fixed::parse("0.610780881")));
}
"Prince" => {
assert!(count_card.state == CandidateState::Elected);
assert_eq!(count_card.keep_value, Some(Fixed::parse("0.741808717")));
}
"Freeman" => {
assert!(count_card.state == CandidateState::Elected);
assert_eq!(count_card.keep_value, Some(Fixed::parse("0.715384286")));
}
"Vicar" => {
assert!(count_card.state == CandidateState::Elected);
assert_eq!(count_card.keep_value, Some(Fixed::parse("1.0")));
}
_ => {}
}
}
}

View File

@ -38,6 +38,7 @@ fn prsa1_rational() {
surplus_order: stv::SurplusOrder::ByOrder,
transferable_only: true,
exclusion: stv::ExclusionMethod::ParcelsByOrder,
meek_nz_exclusion: false,
bulk_exclude: false,
defer_surpluses: false,
meek_immediate_elect: false,

View File

@ -45,6 +45,7 @@ fn scotland_linn07_fixed5() {
surplus_order: stv::SurplusOrder::BySize,
transferable_only: false,
exclusion: stv::ExclusionMethod::SingleStage,
meek_nz_exclusion: false,
bulk_exclude: false,
defer_surpluses: false,
meek_immediate_elect: false,
@ -72,6 +73,7 @@ fn scotland_linn07_gfixed5() {
surplus_order: stv::SurplusOrder::BySize,
transferable_only: false,
exclusion: stv::ExclusionMethod::SingleStage,
meek_nz_exclusion: false,
bulk_exclude: false,
defer_surpluses: false,
meek_immediate_elect: false,