Complete implementation and tests for NSW Local Government STV
This commit is contained in:
parent
c5d6b8d460
commit
8af0fa1178
@ -13,17 +13,17 @@ The preset dropdown allows you to choose from a hardcoded list of preloaded STV
|
|||||||
| • Meek STV (2006) | Operates according to Hill's 2006 revisions ([*Voting Matters* 2006;(22):7–10](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. | [E1] | ✓ |
|
| • Meek STV (2006) | Operates according to Hill's 2006 revisions ([*Voting Matters* 2006;(22):7–10](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. | [E1] | ✓ |
|
||||||
| • 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). | [E1] | ✓ |
|
| • 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). | [E1] | ✓ |
|
||||||
| 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. | [E2] [E3] [E4] | ✓ |
|
| 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. | [E2] [E3] [E4] | ✓ |
|
||||||
| NSW Local Government STV | Rules from the [*Local Government (General) Regulation 2021*](https://legislation.nsw.gov.au/view/html/inforce/current/sl-2021-0460), using the weighted inclusive Gregory method. | [E2] | |
|
| NSW Local Government STV | Rules from the [*Local Government (General) Regulation 2021*](https://legislation.nsw.gov.au/view/html/inforce/current/sl-2021-0460), using the weighted inclusive Gregory method. | [E2] [E5] | |
|
||||||
| Western Australia STV | Rules from the [*Electoral Act 1907* (WA)](https://www.legislation.wa.gov.au/legislation/prod/filestore.nsf/FileURL/mrdoc_29498.pdf/$FILE/Electoral%20Act%201907%20-%20[17-a0-06].pdf), using the weighted inclusive Gregory method. | [E2] [E3] | |
|
| Western Australia STV | Rules from the [*Electoral Act 1907* (WA)](https://www.legislation.wa.gov.au/legislation/prod/filestore.nsf/FileURL/mrdoc_29498.pdf/$FILE/Electoral%20Act%201907%20-%20[17-a0-06].pdf), using the weighted inclusive Gregory method. | [E2] [E3] | |
|
||||||
| Australian Capital Territory STV | Rules from the [*Electoral Act 1992* (ACT)](https://www.legislation.act.gov.au/View/a/1992-71/current/PDF/1992-71.PDF), using the exclusive Gregory method. | | ✓ |
|
| Australian Capital Territory STV | Rules from the [*Electoral Act 1992* (ACT)](https://www.legislation.act.gov.au/View/a/1992-71/current/PDF/1992-71.PDF), using the exclusive Gregory method. | | ✓ |
|
||||||
| Minneapolis STV | Rules from chapter 167 of the [*Minneapolis Code of Ordinances*](https://library.municode.com/mn/minneapolis/codes/code_of_ordinances?nodeId=COOR_TIT8.5EL_CH167MUELRUCO), using the weighted inclusive Gregory method. | [E5] | ✓ |
|
| Minneapolis STV | Rules from chapter 167 of the [*Minneapolis Code of Ordinances*](https://library.municode.com/mn/minneapolis/codes/code_of_ordinances?nodeId=COOR_TIT8.5EL_CH167MUELRUCO), using the weighted inclusive Gregory method. | [E6] | ✓ |
|
||||||
| Cambridge STV | Rules in force in Cambridge, Massachusetts, using random sample transfers. These rules are derived from the [former chapter 54A of the Massachusetts General Laws](https://www.cambridgema.gov/-/media/Files/electioncommission/massachusettsgenerallawschapter54a.pdf), but have by regulation been modified to incorporate the procedures set out in Article IX of the former [1938 Charter of the City of Cincinnati](https://catalog.hathitrust.org/Record/001754258). See also [here](https://web.archive.org/web/20081118104049/http://www.fairvote.org/media/1993countmanual.pdf). | | ✓ |
|
| Cambridge STV | Rules in force in Cambridge, Massachusetts, using random sample transfers. These rules are derived from the [former chapter 54A of the Massachusetts General Laws](https://www.cambridgema.gov/-/media/Files/electioncommission/massachusettsgenerallawschapter54a.pdf), but have by regulation been modified to incorporate the procedures set out in Article IX of the former [1938 Charter of the City of Cincinnati](https://catalog.hathitrust.org/Record/001754258). See also [here](https://web.archive.org/web/20081118104049/http://www.fairvote.org/media/1993countmanual.pdf). | | ✓ |
|
||||||
| Dáil Éireann STV | Rules from the [*Electoral Act 1992* (Ireland)](http://www.irishstatutebook.ie/eli/1992/act/23/enacted/en/print), using stratified random sample transfers. | [E4] [E6] | ✓ |
|
| Dáil Éireann STV | Rules from the [*Electoral Act 1992* (Ireland)](http://www.irishstatutebook.ie/eli/1992/act/23/enacted/en/print), using stratified random sample transfers. | [E4] [E7] | ✓ |
|
||||||
| [Wright STV](https://www.aph.gov.au/Parliamentary_Business/Committees/House_of_Representatives_Committees?url=em/elect07/subs/sub051.1.pdf) | Rules proposed by Anthony van der Craats designed for computer counting, involving reset and re-iteration of the count after each candidate exclusion. | | ✓ |
|
| [Wright STV](https://www.aph.gov.au/Parliamentary_Business/Committees/House_of_Representatives_Committees?url=em/elect07/subs/sub051.1.pdf) | Rules proposed by Anthony van der Craats designed for computer counting, involving reset and re-iteration of the count after each candidate exclusion. | | ✓ |
|
||||||
| [PRSA 1977](https://www.prsa.org.au/rule1977.htm) | Simple rules designed for hand counting, using the exclusive Gregory method, with counting performed in thousandths of a vote. | | ✓ |
|
| [PRSA 1977](https://www.prsa.org.au/rule1977.htm) | Simple rules designed for hand counting, using the exclusive Gregory method, with counting performed in thousandths of a vote. | | ✓ |
|
||||||
| [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. | [E7] | ✓ |
|
| [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. | [E8] | ✓ |
|
||||||
| • ERS76 | Former rules from the 1976 2nd edition. | [E7] [E8] | ✓ |
|
| • ERS76 | Former rules from the 1976 2nd edition. | [E8] [E9] | ✓ |
|
||||||
| • ERS73 | Former rules from the 1973 1st edition. | [E7] [E8] | |
|
| • ERS73 | Former rules from the 1973 1st edition. | [E8] [E9] | |
|
||||||
| Church of England | Rules from the Church of England [*Single Transferable Vote Rules 2020*](https://www.churchofengland.org/sites/default/files/2020-02/STV%20Rules%202020%20-%20final.pdf), similar to ERS73. | | ✓ |
|
| Church of England | Rules from the Church of England [*Single Transferable Vote Rules 2020*](https://www.churchofengland.org/sites/default/files/2020-02/STV%20Rules%202020%20-%20final.pdf), similar to ERS73. | | ✓ |
|
||||||
|
|
||||||
Exceptions:
|
Exceptions:
|
||||||
@ -32,10 +32,11 @@ Exceptions:
|
|||||||
* [E2] When breaking ties backwards, OpenTally selects the candidate who had more/fewer votes at the last stage when *any* tied candidate had more/fewer votes, rather than the method described in the legislation (when each all had unequal votes). The OpenTally developers regard the method described in the legislation as a defect. For an independent discussion, see <a href="https://dl.acm.org/doi/10.1145/3014812.3014837">Conway et al.</a>
|
* [E2] When breaking ties backwards, OpenTally selects the candidate who had more/fewer votes at the last stage when *any* tied candidate had more/fewer votes, rather than the method described in the legislation (when each all had unequal votes). The OpenTally developers regard the method described in the legislation as a defect. For an independent discussion, see <a href="https://dl.acm.org/doi/10.1145/3014812.3014837">Conway et al.</a>
|
||||||
* [E3] A tie between 2 candidates for the final vacancy will be broken backwards then at random, rather than the method described in the legislation.
|
* [E3] A tie between 2 candidates for the final vacancy will be broken backwards then at random, rather than the method described in the legislation.
|
||||||
* [E4] Bulk exclusion is not performed, as the prescribed rules are more conservative than OpenTally's. See also the section on *Bulk exclusion* for further discussion.
|
* [E4] Bulk exclusion is not performed, as the prescribed rules are more conservative than OpenTally's. See also the section on *Bulk exclusion* for further discussion.
|
||||||
* [E5] The ‘mathematically eliminated by the sum of all ranked-choice votes comparison’ is not implemented.
|
* [E5] The legislation specifies that, when rounding subtransfers, surpluses are to be transferred ‘by value’ while exclusions are to be transferred ‘by value and source’. One imagines this differing treatment was a drafting oversight, and the New South Wales Electoral Commission has instead applied the ‘by value and source’ method for both in practice, which OpenTally follows. See also <a href="https://github.com/AndrewConway/ConcreteSTV/blob/main/nsw/NSWLocalCouncilLegislation2021Commentary.md">Conway</a>.
|
||||||
* [E6] The ‘quarter of a quota’ provision is disregarded when determining whether to defer surplus distributions.
|
* [E6] The ‘mathematically eliminated by the sum of all ranked-choice votes comparison’ is not implemented.
|
||||||
* [E7] No distinction is made between stages and substages (during exclusion). This affects only the numbering of stages and not the result.
|
* [E7] The ‘quarter of a quota’ provision is disregarded when determining whether to defer surplus distributions.
|
||||||
* [E8] By default, the quota is always calculated to 2 decimal places. For full ERS76 (ERS73) compliance, set *Round quota to 0 d.p.* when the quota is more than 100 (100 or more).
|
* [E8] No distinction is made between stages and substages (during exclusion). This affects only the numbering of stages and not the result.
|
||||||
|
* [E9] By default, the quota is always calculated to 2 decimal places. For full ERS76 (ERS73) compliance, set *Round quota to 0 d.p.* when the quota is more than 100 (100 or more).
|
||||||
|
|
||||||
For details of validation, see [validation.md](https://yingtongli.me/git/OpenTally/about/docs/validation.md).
|
For details of validation, see [validation.md](https://yingtongli.me/git/OpenTally/about/docs/validation.md).
|
||||||
|
|
||||||
@ -278,6 +279,7 @@ When *Surplus method* is set to a Gregory method, this option allows you to spec
|
|||||||
|
|
||||||
* *Single step* (default): The total value of all votes expressing a next available preference for that candidate is multiplied by the surplus fraction. The product (rounded if requested) is credited to that candidate.
|
* *Single step* (default): The total value of all votes expressing a next available preference for that candidate is multiplied by the surplus fraction. The product (rounded if requested) is credited to that candidate.
|
||||||
* *By value*: The votes expressing a next available preference for that candidate are further divided according to value. For each group of votes at a particular value, the total value of all such votes is multiplied by the surplus fraction. The product (rounded if requested) is credited to that candidate.
|
* *By value*: The votes expressing a next available preference for that candidate are further divided according to value. For each group of votes at a particular value, the total value of all such votes is multiplied by the surplus fraction. The product (rounded if requested) is credited to that candidate.
|
||||||
|
* *By value and source*: The votes are further divided according to value, and according to who they were received from by the elected/excluded candidate. Then as per *By value*.
|
||||||
* *Per ballot*: For each individual vote expressing a next available preference for that candidate, the value of the vote is multiplied by the surplus fraction. The product (rounded if requested) is credited to that candidate.
|
* *Per ballot*: For each individual vote expressing a next available preference for that candidate, the value of the vote is multiplied by the surplus fraction. The product (rounded if requested) is credited to that candidate.
|
||||||
|
|
||||||
This option affects the result only as far as rounding (due to use of fixed-precision/floating-point arithmetic, or an explicit rounding option) is concerned.
|
This option affects the result only as far as rounding (due to use of fixed-precision/floating-point arithmetic, or an explicit rounding option) is concerned.
|
||||||
|
@ -299,6 +299,7 @@
|
|||||||
<select id="selSumTransfers">
|
<select id="selSumTransfers">
|
||||||
<option value="single_step" selected>Single step</option>
|
<option value="single_step" selected>Single step</option>
|
||||||
<option value="by_value">By value</option>
|
<option value="by_value">By value</option>
|
||||||
|
<option value="by_value_and_source">By value and source</option>
|
||||||
<option value="per_ballot">Per ballot</option>
|
<option value="per_ballot">Per ballot</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
|
@ -236,7 +236,7 @@ function changePreset() {
|
|||||||
document.getElementById('txtRoundVotes').value = '0';
|
document.getElementById('txtRoundVotes').value = '0';
|
||||||
document.getElementById('chkRoundSFs').checked = false;
|
document.getElementById('chkRoundSFs').checked = false;
|
||||||
document.getElementById('chkRoundValues').checked = false;
|
document.getElementById('chkRoundValues').checked = false;
|
||||||
document.getElementById('selSumTransfers').value = 'per_ballot';
|
document.getElementById('selSumTransfers').value = 'by_value_and_source';
|
||||||
document.getElementById('selSurplus').value = 'by_order';
|
document.getElementById('selSurplus').value = 'by_order';
|
||||||
document.getElementById('selMethod').value = 'wig';
|
document.getElementById('selMethod').value = 'wig';
|
||||||
document.getElementById('selPapers').value = 'transferable';
|
document.getElementById('selPapers').value = 'transferable';
|
||||||
|
@ -80,7 +80,7 @@ pub struct SubcmdOptions {
|
|||||||
round_quota: Option<usize>,
|
round_quota: Option<usize>,
|
||||||
|
|
||||||
/// (Gregory STV) How to round subtransfers during surpluses/exclusions
|
/// (Gregory STV) How to round subtransfers during surpluses/exclusions
|
||||||
#[clap(help_heading=Some("ROUNDING"), long, possible_values=&["single_step", "per_ballot"], default_value="single_step", value_name="mode")]
|
#[clap(help_heading=Some("ROUNDING"), long, possible_values=&["single_step", "by_value", "by_value_and_source", "per_ballot"], default_value="single_step", value_name="mode")]
|
||||||
round_subtransfers: String,
|
round_subtransfers: String,
|
||||||
|
|
||||||
/// (Meek STV) Limit for stopping iteration of surplus distribution
|
/// (Meek STV) Limit for stopping iteration of surplus distribution
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* OpenTally: Open-source election vote counting
|
/* OpenTally: Open-source election vote counting
|
||||||
* Copyright © 2021 Lee Yingtong Li (RunasSudo)
|
* Copyright © 2021–2022 Lee Yingtong Li (RunasSudo)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@ -28,7 +28,7 @@ pub mod prettytable_html;
|
|||||||
// --------
|
// --------
|
||||||
// STV code
|
// STV code
|
||||||
|
|
||||||
use super::{ExclusionMethod, STVError, STVOptions, SurplusMethod, SurplusOrder};
|
use super::{ExclusionMethod, RoundSubtransfersMode, STVError, STVOptions, SurplusMethod, SurplusOrder};
|
||||||
use super::sample;
|
use super::sample;
|
||||||
|
|
||||||
use crate::constraints;
|
use crate::constraints;
|
||||||
@ -254,7 +254,7 @@ where
|
|||||||
exhausted_ballots += &result.exhausted.num_ballots;
|
exhausted_ballots += &result.exhausted.num_ballots;
|
||||||
exhausted_votes += &result.exhausted.num_ballots * &parcel.value_fraction;
|
exhausted_votes += &result.exhausted.num_ballots * &parcel.value_fraction;
|
||||||
|
|
||||||
parcels_next_prefs.push((parcel.value_fraction, result));
|
parcels_next_prefs.push((parcel.value_fraction, parcel.source_order, result));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate and print surplus fraction
|
// Calculate and print surplus fraction
|
||||||
@ -316,10 +316,15 @@ where
|
|||||||
surplus.clone(), surplus_fraction.clone(), surplus_numer.clone(), surplus_denom.clone()
|
surplus.clone(), surplus_fraction.clone(), surplus_numer.clone(), surplus_denom.clone()
|
||||||
);
|
);
|
||||||
|
|
||||||
for (value_fraction, result) in parcels_next_prefs {
|
for (value_fraction, source_order, result) in parcels_next_prefs {
|
||||||
for (candidate, entry) in result.candidates.into_iter() {
|
for (candidate, entry) in result.candidates.into_iter() {
|
||||||
// Record transfers
|
// Record transfers
|
||||||
transfer_table.add_transfers(&value_fraction, candidate, &entry.num_ballots);
|
transfer_table.add_transfers(
|
||||||
|
&value_fraction,
|
||||||
|
if opts.round_subtransfers == RoundSubtransfersMode::ByValueAndSource { Some(source_order) } else { None },
|
||||||
|
candidate,
|
||||||
|
&entry.num_ballots
|
||||||
|
);
|
||||||
|
|
||||||
let mut new_value_fraction;
|
let mut new_value_fraction;
|
||||||
if opts.surplus.is_weighted() {
|
if opts.surplus.is_weighted() {
|
||||||
@ -351,7 +356,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Record exhausted votes
|
// Record exhausted votes
|
||||||
transfer_table.add_exhausted(&value_fraction, &result.exhausted.num_ballots);
|
transfer_table.add_exhausted(
|
||||||
|
&value_fraction,
|
||||||
|
if opts.round_subtransfers == RoundSubtransfersMode::ByValueAndSource { Some(source_order) } else { None },
|
||||||
|
&result.exhausted.num_ballots
|
||||||
|
);
|
||||||
|
|
||||||
// Transfer exhausted votes
|
// Transfer exhausted votes
|
||||||
let parcel = Parcel {
|
let parcel = Parcel {
|
||||||
@ -571,23 +580,28 @@ where
|
|||||||
state.election.candidates.iter().filter(|c| state.candidates[c].state == CandidateState::Hopeful || state.candidates[c].state == CandidateState::Guarded).collect(),
|
state.election.candidates.iter().filter(|c| state.candidates[c].state == CandidateState::Hopeful || state.candidates[c].state == CandidateState::Guarded).collect(),
|
||||||
);
|
);
|
||||||
|
|
||||||
for parcel in parcels {
|
for src_parcel in parcels {
|
||||||
// Count next preferences
|
// Count next preferences
|
||||||
let result = super::next_preferences(state, parcel.votes);
|
let result = super::next_preferences(state, src_parcel.votes);
|
||||||
|
|
||||||
total_ballots += &result.total_ballots;
|
total_ballots += &result.total_ballots;
|
||||||
total_votes += &result.total_ballots * &parcel.value_fraction;
|
total_votes += &result.total_ballots * &src_parcel.value_fraction;
|
||||||
|
|
||||||
// Transfer candidate votes
|
// Transfer candidate votes
|
||||||
for (candidate, entry) in result.candidates.into_iter() {
|
for (candidate, entry) in result.candidates.into_iter() {
|
||||||
let parcel = Parcel {
|
let parcel = Parcel {
|
||||||
votes: entry.votes,
|
votes: entry.votes,
|
||||||
value_fraction: parcel.value_fraction.clone(),
|
value_fraction: src_parcel.value_fraction.clone(),
|
||||||
source_order: state.num_elected + state.num_excluded,
|
source_order: state.num_elected + state.num_excluded,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Record transfers
|
// Record transfers
|
||||||
transfer_table.add_transfers(&parcel.value_fraction, candidate, &entry.num_ballots);
|
transfer_table.add_transfers(
|
||||||
|
&parcel.value_fraction,
|
||||||
|
if opts.round_subtransfers == RoundSubtransfersMode::ByValueAndSource { Some(src_parcel.source_order) } else { None },
|
||||||
|
candidate,
|
||||||
|
&entry.num_ballots
|
||||||
|
);
|
||||||
|
|
||||||
let count_card = state.candidates.get_mut(candidate).unwrap();
|
let count_card = state.candidates.get_mut(candidate).unwrap();
|
||||||
count_card.parcels.push(parcel);
|
count_card.parcels.push(parcel);
|
||||||
@ -596,12 +610,16 @@ where
|
|||||||
// Transfer exhausted votes
|
// Transfer exhausted votes
|
||||||
let parcel = Parcel {
|
let parcel = Parcel {
|
||||||
votes: result.exhausted.votes,
|
votes: result.exhausted.votes,
|
||||||
value_fraction: parcel.value_fraction,
|
value_fraction: src_parcel.value_fraction,
|
||||||
source_order: state.num_elected + state.num_excluded,
|
source_order: state.num_elected + state.num_excluded,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Record transfers
|
// Record transfers
|
||||||
transfer_table.add_exhausted(&parcel.value_fraction, &result.exhausted.num_ballots);
|
transfer_table.add_exhausted(
|
||||||
|
&parcel.value_fraction,
|
||||||
|
if opts.round_subtransfers == RoundSubtransfersMode::ByValueAndSource { Some(src_parcel.source_order) } else { None },
|
||||||
|
&result.exhausted.num_ballots
|
||||||
|
);
|
||||||
|
|
||||||
state.exhausted.parcels.push(parcel);
|
state.exhausted.parcels.push(parcel);
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,7 @@ impl<'e, N: Number> TransferTable<'e, N> {
|
|||||||
columns: Vec::new(),
|
columns: Vec::new(),
|
||||||
total: TransferTableColumn {
|
total: TransferTableColumn {
|
||||||
value_fraction: N::new(),
|
value_fraction: N::new(),
|
||||||
|
source_order: None,
|
||||||
cells: HashMap::new(),
|
cells: HashMap::new(),
|
||||||
exhausted: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
exhausted: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
||||||
total: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
total: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
||||||
@ -74,6 +75,7 @@ impl<'e, N: Number> TransferTable<'e, N> {
|
|||||||
columns: Vec::new(),
|
columns: Vec::new(),
|
||||||
total: TransferTableColumn {
|
total: TransferTableColumn {
|
||||||
value_fraction: N::new(),
|
value_fraction: N::new(),
|
||||||
|
source_order: None,
|
||||||
cells: HashMap::new(),
|
cells: HashMap::new(),
|
||||||
exhausted: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
exhausted: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
||||||
total: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
total: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
||||||
@ -86,9 +88,9 @@ impl<'e, N: Number> TransferTable<'e, N> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Record the specified transfer
|
/// Record the specified transfer
|
||||||
pub fn add_transfers(&mut self, value_fraction: &N, candidate: &'e Candidate, ballots: &N) {
|
pub fn add_transfers(&mut self, value_fraction: &N, source_order: Option<usize>, candidate: &'e Candidate, ballots: &N) {
|
||||||
for col in self.columns.iter_mut() {
|
for col in self.columns.iter_mut() {
|
||||||
if &col.value_fraction == value_fraction {
|
if &col.value_fraction == value_fraction && col.source_order == source_order {
|
||||||
col.add_transfers(candidate, ballots);
|
col.add_transfers(candidate, ballots);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -96,6 +98,7 @@ impl<'e, N: Number> TransferTable<'e, N> {
|
|||||||
|
|
||||||
let mut col = TransferTableColumn {
|
let mut col = TransferTableColumn {
|
||||||
value_fraction: value_fraction.clone(),
|
value_fraction: value_fraction.clone(),
|
||||||
|
source_order: source_order,
|
||||||
cells: HashMap::new(),
|
cells: HashMap::new(),
|
||||||
exhausted: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
exhausted: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
||||||
total: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
total: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
||||||
@ -105,9 +108,9 @@ impl<'e, N: Number> TransferTable<'e, N> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Record the specified exhaustion
|
/// Record the specified exhaustion
|
||||||
pub fn add_exhausted(&mut self, value_fraction: &N, ballots: &N) {
|
pub fn add_exhausted(&mut self, value_fraction: &N, source_order: Option<usize>, ballots: &N) {
|
||||||
for col in self.columns.iter_mut() {
|
for col in self.columns.iter_mut() {
|
||||||
if &col.value_fraction == value_fraction {
|
if &col.value_fraction == value_fraction && col.source_order == source_order {
|
||||||
col.exhausted.ballots += ballots;
|
col.exhausted.ballots += ballots;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -115,6 +118,7 @@ impl<'e, N: Number> TransferTable<'e, N> {
|
|||||||
|
|
||||||
let col = TransferTableColumn {
|
let col = TransferTableColumn {
|
||||||
value_fraction: value_fraction.clone(),
|
value_fraction: value_fraction.clone(),
|
||||||
|
source_order: source_order,
|
||||||
cells: HashMap::new(),
|
cells: HashMap::new(),
|
||||||
exhausted: TransferTableCell { ballots: ballots.clone(), votes_in: N::new(), votes_out: N::new() },
|
exhausted: TransferTableCell { ballots: ballots.clone(), votes_in: N::new(), votes_out: N::new() },
|
||||||
total: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
total: TransferTableCell { ballots: N::new(), votes_in: N::new(), votes_out: N::new() },
|
||||||
@ -199,7 +203,7 @@ impl<'e, N: Number> TransferTable<'e, N> {
|
|||||||
self.total.exhausted.votes_out.floor_mut(dps);
|
self.total.exhausted.votes_out.floor_mut(dps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RoundSubtransfersMode::ByValue => {
|
RoundSubtransfersMode::ByValue | RoundSubtransfersMode::ByValueAndSource => {
|
||||||
// Calculate votes_out for each column
|
// Calculate votes_out for each column
|
||||||
for column in self.columns.iter_mut() {
|
for column in self.columns.iter_mut() {
|
||||||
// Calculate votes_out per candidate in the column
|
// Calculate votes_out per candidate in the column
|
||||||
@ -245,7 +249,7 @@ impl<'e, N: Number> TransferTable<'e, N> {
|
|||||||
|
|
||||||
// Sum total votes_out per candidate
|
// Sum total votes_out per candidate
|
||||||
for (candidate, cell) in self.total.cells.iter_mut() {
|
for (candidate, cell) in self.total.cells.iter_mut() {
|
||||||
cell.votes_out = self.columns.iter().fold(N::new(), |acc, col| acc + &col.cells[candidate].votes_out);
|
cell.votes_out = self.columns.iter().fold(N::new(), |acc, col| if let Some(cell) = col.cells.get(candidate) { acc + &cell.votes_out } else { acc });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sum total exhausted votes
|
// Sum total exhausted votes
|
||||||
@ -307,13 +311,12 @@ impl<'e, N: Number> TransferTable<'e, N> {
|
|||||||
|
|
||||||
// Sum total votes_out per candidate
|
// Sum total votes_out per candidate
|
||||||
for (candidate, cell) in self.total.cells.iter_mut() {
|
for (candidate, cell) in self.total.cells.iter_mut() {
|
||||||
cell.votes_out = self.columns.iter().fold(N::new(), |acc, col| acc + &col.cells[candidate].votes_out);
|
cell.votes_out = self.columns.iter().fold(N::new(), |acc, col| if let Some(cell) = col.cells.get(candidate) { acc + &cell.votes_out } else { acc });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sum total exhausted votes
|
// Sum total exhausted votes
|
||||||
self.total.exhausted.votes_out = self.columns.iter().fold(N::new(), |acc, col| acc + &col.exhausted.votes_out);
|
self.total.exhausted.votes_out = self.columns.iter().fold(N::new(), |acc, col| acc + &col.exhausted.votes_out);
|
||||||
}
|
}
|
||||||
_ => todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,6 +565,9 @@ pub struct TransferTableColumn<'e, N: Number> {
|
|||||||
/// Value fraction of ballots counted in this column
|
/// Value fraction of ballots counted in this column
|
||||||
pub value_fraction: N,
|
pub value_fraction: N,
|
||||||
|
|
||||||
|
/// Number to separate parcels in modes where subtransfers by parcel, or `None` if unused
|
||||||
|
pub source_order: Option<usize>,
|
||||||
|
|
||||||
/// Cells in this column
|
/// Cells in this column
|
||||||
pub cells: HashMap<&'e Candidate, TransferTableCell<N>>,
|
pub cells: HashMap<&'e Candidate, TransferTableCell<N>>,
|
||||||
|
|
||||||
|
@ -224,7 +224,8 @@ impl STVOptions {
|
|||||||
//if self.sample == SampleMethod::StratifyFloor && self.sample_per_ballot { return Err(STVError::InvalidOptions("--sample stratify_floor is incompatible with --sample-per-ballot")); }
|
//if self.sample == SampleMethod::StratifyFloor && self.sample_per_ballot { return Err(STVError::InvalidOptions("--sample stratify_floor is incompatible with --sample-per-ballot")); }
|
||||||
if self.sample_per_ballot && !self.immediate_elect { return Err(STVError::InvalidOptions("--sample-per-ballot is incompatible with --no-immediate-elect")); }
|
if self.sample_per_ballot && !self.immediate_elect { return Err(STVError::InvalidOptions("--sample-per-ballot is incompatible with --no-immediate-elect")); }
|
||||||
}
|
}
|
||||||
if self.min_threshold != "0" && self.defer_surpluses { return Err(STVError::InvalidOptions("--min-threshold is incompatible with --defer-surpluses")); } // TODO: Permit this
|
if self.min_threshold != "0" && self.defer_surpluses { return Err(STVError::InvalidOptions("--min-threshold is incompatible with --defer-surpluses (not yet implemented)")); } // TODO: NYI
|
||||||
|
if self.round_subtransfers == RoundSubtransfersMode::ByValueAndSource && self.bulk_exclude { return Err(STVError::InvalidOptions("--round-subtransfers by_value_and_source is incompatible with --bulk-exclude (not yet implemented)")); } // TODO: NYI
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,10 +249,10 @@ impl RoundSubtransfersMode {
|
|||||||
/// Convert to CLI argument representation
|
/// Convert to CLI argument representation
|
||||||
fn describe(self) -> String {
|
fn describe(self) -> String {
|
||||||
match self {
|
match self {
|
||||||
RoundSubtransfersMode::SingleStep => "--sum-surplus-transfers single_step",
|
RoundSubtransfersMode::SingleStep => "--round-subtransfers single_step",
|
||||||
RoundSubtransfersMode::ByValue => "--sum-surplus-transfers by_value",
|
RoundSubtransfersMode::ByValue => "--round-subtransfers by_value",
|
||||||
RoundSubtransfersMode::ByValueAndSource => "--sum-surplus-transfers by_value_and_source",
|
RoundSubtransfersMode::ByValueAndSource => "--round-subtransfers by_value_and_source",
|
||||||
RoundSubtransfersMode::PerBallot => "--sum-surplus-transfers per_ballot",
|
RoundSubtransfersMode::PerBallot => "--round-subtransfers per_ballot",
|
||||||
}.to_string()
|
}.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7921
tests/data/City_of_Albury-finalpreferencedatafile.blt
Normal file
7921
tests/data/City_of_Albury-finalpreferencedatafile.blt
Normal file
File diff suppressed because it is too large
Load Diff
53
tests/data/City_of_Albury-finalpreferencedatafile.csv
Normal file
53
tests/data/City_of_Albury-finalpreferencedatafile.csv
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
Stage:,1,,2,,3,,4,,5,,6,,7,,8,,9,,10,,11,,12,,13,,14,,15,,16,,17,,18,,19,,20,,21,,22,,23,,24,,25,,26,,27,,28,,29,,30,,31,,32,,33,,34,,35,,36,,37,,38,,39,,40,,41,,42,,43,,44,,45,,46,,47,,48,,49,
|
||||||
|
Comment:,First preferences,,Surplus of KING Kylie,,Surplus of BAKER Stuart,,Surplus of GLACHAN Alice,,Surplus of EDWARDS Ashley,,Surplus of BOWEN Steve,,Exclusion of HARTNETT Diann,,Exclusion of MOORE John,,Exclusion of STAR C,,Exclusion of HEATHER Esther,,Exclusion of MARTIN Christopher,,Exclusion of BARBER Trevor,,Exclusion of VAN NOORDENNEN Bill,,Exclusion of PATTINSON Jill,,Exclusion of MACHIN Michael,,Exclusion of HAMILTON Claire,,Exclusion of ALLEN Geoffrey,,Exclusion of WALLIS Lucie,,Exclusion of TRATZ Mathew,,Exclusion of MONTE Susie,,Exclusion of PEARCE Garry,,Exclusion of DOYLE Mark,,Exclusion of SINGH Naziya,,Exclusion of RYAN Christopher,,Exclusion of PEMBERTON Louise,,Exclusion of WATKINS Sarah,,Exclusion of SMITH Taneesha,,Exclusion of GRELLMAN Emily,,Exclusion of ARMSTRONG Paul,,Exclusion of DUNN Jackie,,Exclusion of CALE Danielle,,Exclusion of ROWLAND Marcus,,Exclusion of GRENFELL Brian,,Exclusion of CHAN Aimee,,Exclusion of HULL Barbara,,Exclusion of THOMAS Dianne,,Exclusion of HOOD Peter,,Exclusion of CAMERON Amelia,,Exclusion of TIERNAN Jodie,,Exclusion of DOCKSEY Graham,,Exclusion of ISAACS Kofi,,Exclusion of COHN Amanda,,Exclusion of MAMOUNEY Stephen,,Exclusion of VENESS Rhiannon,,Exclusion of BARBER Andrew,,Exclusion of PEARSON Lindsay,,Surplus of BETTERIDGE Daryl,,Surplus of CAMERON Darren,,Exclusion of VAN DE VEN Henk,
|
||||||
|
BETTERIDGE Daryl,2526,H,2539,H,2583,H,2606,H,2606,H,2632,H,2632,H,2632,H,2632,H,2632,H,2633,H,2633,H,2633,H,2634,H,2634,H,2634,H,2634,H,2636,H,2638,H,2638,H,2639,H,2639,H,2640,H,2640,H,2640,H,2640,H,2641,H,2641,H,2644,H,2644,H,2646,H,2648,H,2660,H,2660,H,2675,H,2681,H,2687,H,2688,H,2721,H,2726,H,2726,H,2733,H,2770,H,2788,H,2826,H,2864,EL,2838,EL,2838,EL,2838,EL
|
||||||
|
HULL Barbara,38,H,38,H,39,H,39,H,39,H,39,H,39,H,39,H,39,H,39,H,39,H,39,H,39,H,39,H,39,H,39,H,39,H,39,H,40,H,40,H,41,H,42,H,42,H,42,H,43,H,43,H,44,H,45,H,45,H,45,H,45,H,46,H,47,H,47,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
TIERNAN Jodie,51,H,51,H,59,H,61,H,61,H,65,H,65,H,65,H,65,H,65,H,65,H,65,H,65,H,65,H,65,H,66,H,66,H,66,H,66,H,67,H,67,H,67,H,67,H,67,H,68,H,69,H,69,H,70,H,70,H,70,H,70,H,71,H,77,H,77,H,85,H,86,H,88,H,94,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
GRENFELL Brian,32,H,32,H,34,H,34,H,34,H,35,H,35,H,35,H,35,H,35,H,35,H,35,H,37,H,37,H,37,H,37,H,38,H,38,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,42,H,42,H,42,H,43,H,43,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
TRATZ Mathew,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
CAMERON Darren,2595,H,2602,H,2613,H,2617,H,2617,H,2623,H,2623,H,2623,H,2623,H,2623,H,2623,H,2623,H,2623,H,2623,H,2623,H,2623,H,2625,H,2625,H,2625,H,2625,H,2625,H,2625,H,2625,H,2631,H,2631,H,2632,H,2632,H,2633,H,2634,H,2634,H,2634,H,2649,H,2653,H,2654,H,2657,H,2658,H,2665,H,2722,H,2724,H,2729,H,2731,H,2754,H,2757,H,2769,H,2812,H,2833,H,2839,EL,2838,EL,2838,EL
|
||||||
|
ROWLAND Marcus,39,H,39,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,40,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
CAMERON Amelia,51,H,51,H,51,H,51,H,51,H,51,H,51,H,51,H,51,H,51,H,51,H,51,H,51,H,52,H,52,H,52,H,56,H,56,H,59,H,59,H,59,H,59,H,59,H,72,H,72,H,72,H,73,H,76,H,76,H,76,H,76,H,83,H,83,H,83,H,86,H,86,H,86,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
ALLEN Geoffrey,13,H,13,H,13,H,13,H,13,H,13,H,13,H,13,H,13,H,13,H,13,H,13,H,13,H,13,H,13,H,13,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
RYAN Christopher,16,H,16,H,16,H,16,H,16,H,16,H,16,H,16,H,16,H,16,H,16,H,16,H,16,H,16,H,16,H,16,H,19,H,19,H,20,H,21,H,21,H,21,H,21,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
HAMILTON Ross,1244,H,1252,H,1265,H,1270,H,1270,H,1277,H,1277,H,1277,H,1277,H,1277,H,1277,H,1277,H,1278,H,1278,H,1278,H,1279,H,1280,H,1282,H,1284,H,1284,H,1286,H,1286,H,1286,H,1286,H,1286,H,1288,H,1288,H,1295,H,1296,H,1296,H,1296,H,1297,H,1300,H,1301,H,1303,H,1329,H,1331,H,1333,H,1338,H,1339,H,1341,H,1354,H,1360,H,1371,H,1452,H,1473,H,1478,H,1478,H,1530,H
|
||||||
|
THOMAS Dianne,40,H,40,H,45,H,47,H,47,H,49,H,49,H,49,H,49,H,49,H,49,H,49,H,49,H,49,H,49,H,50,H,50,H,52,H,52,H,53,H,53,H,53,H,53,H,53,H,53,H,54,H,54,H,61,H,61,H,61,H,61,H,62,H,62,H,63,H,66,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
GRELLMAN Emily,18,H,18,H,18,H,18,H,18,H,18,H,18,H,18,H,18,H,18,H,18,H,19,H,19,H,20,H,20,H,22,H,23,H,27,H,27,H,27,H,27,H,27,H,27,H,27,H,27,H,27,H,27,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
WALLIS Lucie,12,H,12,H,12,H,12,H,12,H,12,H,12,H,12,H,12,H,12,H,12,H,12,H,12,H,12,H,12,H,14,H,14,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
HAMILTON Claire,10,H,10,H,11,H,11,H,11,H,11,H,11,H,11,H,11,H,11,H,12,H,12,H,12,H,12,H,12,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
KING Kylie,5517,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL
|
||||||
|
BOWEN Steve,884,H,3476,EL,3476,EL,3476,EL,3476,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL
|
||||||
|
VENESS Rhiannon,5,H,11,H,11,H,11,H,11,H,501,H,501,H,501,H,501,H,502,H,502,H,502,H,502,H,502,H,502,H,502,H,502,H,502,H,502,H,502,H,502,H,502,H,502,H,502,H,503,H,503,H,509,H,509,H,509,H,509,H,509,H,510,H,511,H,541,H,543,H,546,H,548,H,550,H,553,H,553,H,553,H,558,H,562,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
CHAN Aimee,12,H,15,H,15,H,15,H,15,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,31,H,39,H,40,H,40,H,43,H,43,H,43,H,43,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
SMITH Taneesha,8,H,11,H,11,H,11,H,11,H,23,H,23,H,23,H,23,H,23,H,23,H,23,H,23,H,23,H,23,H,23,H,23,H,23,H,23,H,23,H,23,H,23,H,24,H,25,H,25,H,27,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
BARBER Andrew,737,H,743,H,754,H,759,H,759,H,763,H,763,H,763,H,763,H,763,H,763,H,768,H,768,H,768,H,768,H,769,H,769,H,770,H,770,H,770,H,770,H,771,H,771,H,771,H,771,H,781,H,781,H,781,H,782,H,782,H,784,H,784,H,784,H,784,H,784,H,784,H,786,H,788,H,789,H,793,H,794,H,804,H,809,H,819,H,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
WATKINS Sarah,19,H,20,H,21,H,21,H,21,H,21,H,21,H,21,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,23,H,23,H,23,H,23,H,23,H,23,H,23,H,24,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
BARBER Trevor,6,H,6,H,6,H,6,H,6,H,6,H,7,H,7,H,9,H,9,H,9,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
STAR C,4,H,4,H,4,H,4,H,4,H,4,H,5,H,6,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
HARTNETT Diann,2,H,2,H,2,H,2,H,2,H,2,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
EDWARDS Ashley,2913,EL,2913,EL,2913,EL,2913,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL
|
||||||
|
ISAACS Kofi,33,H,33,H,35,H,35,H,104,H,106,H,106,H,106,H,107,H,107,H,107,H,107,H,107,H,109,H,110,H,110,H,110,H,110,H,110,H,115,H,115,H,115,H,115,H,115,H,116,H,116,H,116,H,116,H,116,H,116,H,117,H,117,H,119,H,119,H,120,H,120,H,122,H,125,H,127,H,127,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
PATTINSON Jill,9,H,9,H,9,H,9,H,9,H,9,H,9,H,9,H,9,H,9,H,9,H,9,H,9,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
MONTE Susie,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,14,H,16,H,16,H,16,H,16,H,16,H,16,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
COHN Amanda,105,H,107,H,113,H,115,H,116,H,120,H,120,H,120,H,120,H,120,H,120,H,120,H,120,H,121,H,121,H,121,H,121,H,122,H,123,H,130,H,130,H,130,H,131,H,131,H,133,H,133,H,134,H,134,H,135,H,138,H,138,H,138,H,139,H,139,H,140,H,144,H,148,H,149,H,154,H,154,H,244,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
GLACHAN Alice,3837,EL,3837,EL,3837,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL
|
||||||
|
PEARSON Lindsay,47,H,48,H,53,H,914,H,914,H,919,H,919,H,919,H,920,H,920,H,921,H,921,H,921,H,921,H,923,H,923,H,923,H,923,H,924,H,924,H,924,H,924,H,928,H,928,H,928,H,928,H,929,H,929,H,929,H,941,H,944,H,945,H,946,H,946,H,947,H,948,H,951,H,954,H,956,H,981,H,985,H,990,H,992,H,1015,H,1056,H,0,EX,0,EX,0,EX,0,EX
|
||||||
|
DOCKSEY Graham,39,H,39,H,48,H,66,H,66,H,68,H,68,H,68,H,68,H,68,H,68,H,68,H,68,H,68,H,68,H,68,H,68,H,68,H,68,H,68,H,68,H,68,H,71,H,71,H,71,H,72,H,72,H,72,H,74,H,82,H,83,H,86,H,90,H,90,H,90,H,90,H,92,H,94,H,96,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
SINGH Naziya,13,H,13,H,14,H,19,H,19,H,19,H,19,H,19,H,19,H,20,H,20,H,20,H,20,H,20,H,20,H,20,H,20,H,20,H,20,H,20,H,20,H,20,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
DUNN Jackie,23,H,23,H,24,H,29,H,29,H,29,H,29,H,29,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,35,H,35,H,35,H,35,H,35,H,35,H,35,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
BAKER Stuart,4494,EL,4494,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL,2838,EL
|
||||||
|
KELLAHAN Jessica,104,H,104,H,1486,H,1488,H,1488,H,1491,H,1491,H,1491,H,1491,H,1491,H,1491,H,1492,H,1492,H,1492,H,1492,H,1492,H,1492,H,1492,H,1492,H,1492,H,1492,H,1492,H,1492,H,1492,H,1495,H,1495,H,1495,H,1497,H,1497,H,1498,H,1512,H,1513,H,1513,H,1514,H,1515,H,1518,H,1521,H,1522,H,1526,H,1531,H,1532,H,1540,H,1723,H,1752,H,1792,H,1872,H,1876,H,1876,H,1941,EL
|
||||||
|
MAMOUNEY Stephen,224,H,225,H,278,H,283,H,283,H,288,H,288,H,288,H,288,H,288,H,289,H,289,H,290,H,290,H,290,H,290,H,290,H,290,H,290,H,291,H,291,H,291,H,291,H,291,H,296,H,297,H,297,H,298,H,301,H,304,H,314,H,314,H,315,H,316,H,316,H,319,H,320,H,321,H,322,H,325,H,326,H,331,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
CALE Danielle,24,H,24,H,33,H,33,H,33,H,33,H,33,H,33,H,33,H,33,H,33,H,33,H,33,H,33,H,34,H,35,H,36,H,36,H,36,H,36,H,36,H,37,H,38,H,38,H,39,H,39,H,40,H,40,H,40,H,40,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
PEMBERTON Louise,17,H,17,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,22,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
VAN DE VEN Henk,1240,H,1247,H,1280,H,1300,H,1300,H,1307,H,1307,H,1307,H,1307,H,1307,H,1308,H,1309,H,1310,H,1311,H,1311,H,1311,H,1311,H,1311,H,1311,H,1311,H,1318,H,1319,H,1319,H,1319,H,1320,H,1320,H,1321,H,1322,H,1335,H,1336,H,1337,H,1338,H,1338,H,1338,H,1338,H,1342,H,1344,H,1345,H,1348,H,1361,H,1362,H,1368,H,1380,H,1385,H,1405,H,1431,H,1433,H,1433,H,0,EX
|
||||||
|
PEARCE Garry,13,H,13,H,14,H,14,H,14,H,15,H,15,H,15,H,15,H,15,H,16,H,16,H,17,H,17,H,17,H,17,H,17,H,17,H,17,H,17,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
ARMSTRONG Paul,25,H,25,H,26,H,28,H,28,H,28,H,28,H,28,H,28,H,28,H,29,H,29,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,30,H,33,H,33,H,33,H,33,H,33,H,33,H,33,H,33,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
VAN NOORDENNEN Bill,9,H,9,H,9,H,9,H,9,H,9,H,9,H,9,H,9,H,9,H,9,H,9,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
MARTIN Christopher,7,H,7,H,7,H,7,H,7,H,7,H,7,H,8,H,8,H,8,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
THURLEY David,1211,H,1221,H,1250,H,1272,H,1272,H,1280,H,1280,H,1280,H,1280,H,1282,H,1282,H,1283,H,1285,H,1285,H,1288,H,1289,H,1289,H,1290,H,1290,H,1290,H,1290,H,1304,H,1304,H,1304,H,1305,H,1306,H,1306,H,1306,H,1311,H,1311,H,1312,H,1313,H,1314,H,1314,H,1314,H,1318,H,1333,H,1334,H,1338,H,1348,H,1350,H,1379,H,1394,H,1399,H,1438,H,1465,H,1467,H,1467,H,1617,EL
|
||||||
|
DOYLE Mark,16,H,16,H,16,H,17,H,17,H,17,H,17,H,17,H,17,H,18,H,18,H,18,H,18,H,18,H,19,H,19,H,19,H,19,H,19,H,19,H,19,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
HEATHER Esther,5,H,5,H,5,H,5,H,5,H,5,H,5,H,6,H,6,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
MOORE John,4,H,4,H,4,H,4,H,4,H,4,H,4,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
MACHIN Michael,8,H,8,H,8,H,8,H,8,H,8,H,8,H,8,H,8,H,9,H,10,H,10,H,10,H,10,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
||||||
|
HOOD Peter,51,H,51,H,54,H,54,H,54,H,56,H,56,H,57,H,57,H,57,H,57,H,57,H,57,H,57,H,59,H,60,H,60,H,60,H,61,H,61,H,61,H,61,H,61,H,61,H,62,H,62,H,63,H,63,H,64,H,64,H,65,H,66,H,66,H,66,H,67,H,69,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
|
|
BIN
tests/data/City_of_Albury-finalpreferencedatafile.ods
Normal file
BIN
tests/data/City_of_Albury-finalpreferencedatafile.ods
Normal file
Binary file not shown.
@ -35,7 +35,7 @@ fn ers97_coe_rational() {
|
|||||||
.defer_surpluses(true)
|
.defer_surpluses(true)
|
||||||
.build().unwrap();
|
.build().unwrap();
|
||||||
|
|
||||||
assert_eq!(stv_opts.describe::<Rational>(), "--round-surplus-fractions 2 --round-values 2 --round-votes 2 --round-quota 2 --sum-surplus-transfers per_ballot --quota-criterion geq --surplus eg --transferable-only --exclusion by_value --defer-surpluses");
|
assert_eq!(stv_opts.describe::<Rational>(), "--round-surplus-fractions 2 --round-values 2 --round-votes 2 --round-quota 2 --round-subtransfers per_ballot --quota-criterion geq --surplus eg --transferable-only --exclusion by_value --defer-surpluses");
|
||||||
|
|
||||||
utils::read_validate_election::<Rational>("tests/data/ers97_coe.csv", "tests/data/ers97.blt", stv_opts, None, &["nt"]);
|
utils::read_validate_election::<Rational>("tests/data/ers97_coe.csv", "tests/data/ers97.blt", stv_opts, None, &["nt"]);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* OpenTally: Open-source election vote counting
|
/* OpenTally: Open-source election vote counting
|
||||||
* Copyright © 2021 Lee Yingtong Li (RunasSudo)
|
* Copyright © 2021–2022 Lee Yingtong Li (RunasSudo)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@ -28,6 +28,7 @@ mod equal_ranks;
|
|||||||
mod ers;
|
mod ers;
|
||||||
mod meek;
|
mod meek;
|
||||||
mod minneapolis;
|
mod minneapolis;
|
||||||
|
mod nswlg;
|
||||||
mod prsa;
|
mod prsa;
|
||||||
mod scotland;
|
mod scotland;
|
||||||
mod special_cases;
|
mod special_cases;
|
||||||
|
41
tests/tests_impl/nswlg.rs
Normal file
41
tests/tests_impl/nswlg.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/* OpenTally: Open-source election vote counting
|
||||||
|
* Copyright © 2021–2022 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Compare results under NSW Local Government STV with official results from NSW Electoral Commission
|
||||||
|
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
use opentally::numbers::Rational;
|
||||||
|
use opentally::stv;
|
||||||
|
use opentally::ties::TieStrategy;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nswlg_albury21_rational() {
|
||||||
|
let stv_opts = stv::STVOptionsBuilder::default()
|
||||||
|
.round_votes(Some(0))
|
||||||
|
.round_quota(Some(0))
|
||||||
|
.round_subtransfers(stv::RoundSubtransfersMode::ByValueAndSource)
|
||||||
|
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||||
|
.ties(vec![TieStrategy::Backwards, TieStrategy::Random(String::from("20220322"))])
|
||||||
|
.surplus_order(stv::SurplusOrder::ByOrder)
|
||||||
|
.transferable_only(true)
|
||||||
|
.build().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(stv_opts.describe::<Rational>(), "--round-votes 0 --round-quota 0 --round-subtransfers by_value_and_source --quota-criterion geq --ties backwards random --random-seed 20220322 --surplus-order by_order --transferable-only");
|
||||||
|
|
||||||
|
utils::read_validate_election::<Rational>("tests/data/City_of_Albury-finalpreferencedatafile.csv", "tests/data/City_of_Albury-finalpreferencedatafile.blt", stv_opts, None, &[]);
|
||||||
|
}
|
@ -40,7 +40,7 @@ fn scotland_linn07_fixed5() {
|
|||||||
|
|
||||||
Fixed::set_dps(5);
|
Fixed::set_dps(5);
|
||||||
|
|
||||||
assert_eq!(stv_opts.describe::<Fixed>(), "--numbers fixed --decimals 5 --round-surplus-fractions 5 --round-quota 0 --sum-surplus-transfers per_ballot --quota-criterion geq --no-early-bulk-elect --pp-decimals 5");
|
assert_eq!(stv_opts.describe::<Fixed>(), "--numbers fixed --decimals 5 --round-surplus-fractions 5 --round-quota 0 --round-subtransfers per_ballot --quota-criterion geq --no-early-bulk-elect --pp-decimals 5");
|
||||||
|
|
||||||
scotland_linn07::<Fixed>(stv_opts);
|
scotland_linn07::<Fixed>(stv_opts);
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ fn scotland_linn07_gfixed5() {
|
|||||||
|
|
||||||
GuardedFixed::set_dps(5);
|
GuardedFixed::set_dps(5);
|
||||||
|
|
||||||
assert_eq!(stv_opts.describe::<GuardedFixed>(), "--numbers gfixed --decimals 5 --round-surplus-fractions 5 --round-values 5 --round-votes 5 --round-quota 0 --sum-surplus-transfers per_ballot --quota-criterion geq --no-early-bulk-elect --pp-decimals 5");
|
assert_eq!(stv_opts.describe::<GuardedFixed>(), "--numbers gfixed --decimals 5 --round-surplus-fractions 5 --round-values 5 --round-votes 5 --round-quota 0 --round-subtransfers per_ballot --quota-criterion geq --no-early-bulk-elect --pp-decimals 5");
|
||||||
|
|
||||||
scotland_linn07::<GuardedFixed>(stv_opts);
|
scotland_linn07::<GuardedFixed>(stv_opts);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user