Various tidyups
Use "Droop" as default quota (since same as "Droop (exact)" when quota not rounded) Rename ers97.blt Update documentation
This commit is contained in:
parent
46e895ee5a
commit
764ebd98e6
@ -43,7 +43,7 @@ This functionality is not available on the command line.
|
||||
|
||||
The quota dropdowns allow you to define the quota used in the election, and the quota criterion used to elect candidates. The quota may be set to:
|
||||
|
||||
* *Droop* and *Droop (exact)*: *V*/(*S*+1)
|
||||
* *Droop* (default) and *Droop (exact)*: *V*/(*S*+1)
|
||||
* *Hare* and *Hare (exact)*: *V*/*S*
|
||||
|
||||
where *V* is the number of votes and *S* is the number of seats.
|
||||
@ -54,15 +54,15 @@ When *Round quota to [n] d.p.* is not enabled, *Droop* (or *Droop (exact)*) is a
|
||||
|
||||
### Quota criterion (-c/--quota-criterion)
|
||||
|
||||
The quota criterion may be set to *>=* (candidates are elected if they meet or exceed the quota) or *>* (candidates are elected only if they strictly exceed the quota).
|
||||
The quota criterion may be set to *>=* (candidates are elected if they meet or exceed the quota) or *>* (default; candidates are elected only if they strictly exceed the quota).
|
||||
|
||||
Note that the combination ‘*>= Droop (exact)*’ (with *Round quota to [n] d.p.* enabled) can result in more candidates meeting the quota than there are available vacancies, hence this particular combination is not recommended.
|
||||
Note that the combination ‘*>= Droop (exact)*’ (or, when *Round quota to [n] d.p.* is disabled, ‘*>= Droop*’) can result in more candidates meeting the quota than there are available vacancies, hence this particular combination is not recommended.
|
||||
|
||||
### Quota mode (--quota-mode)
|
||||
|
||||
This option allows you to specify whether the votes required for election can change during the count. The options are:
|
||||
|
||||
* *Static quota*: The quota is calculated once after all first-preference votes are allocated, and remains constant throughout the count.
|
||||
* *Static quota* (default): The quota is calculated once after all first-preference votes are allocated, and remains constant throughout the count.
|
||||
* *Static with ERS97 rules*: The quota is static, but candidates may be elected if their vote exceeds (or equals, according to the *Quota criterion*) the active vote, divided by (*S* + 1).
|
||||
* *Dynamic by total vote*: The quota is recalculated at the end of each stage, according to the *Quota* option.
|
||||
* *Dynamic by active vote*: The quota is recalculated at the end of each stage, according to the *Quota* option, but where *V* is the active vote and *S* is the number of remaining vacancies.
|
||||
@ -99,10 +99,10 @@ Random sample methods are also supported, but also not recommended:
|
||||
|
||||
The use of a random sample method requires *Normalise ballots* to be enabled, and will usually be used with a *Quota criterion* set to *>=*.
|
||||
|
||||
### Papers to examine in surplus transfer (--t ransferable-only)
|
||||
### Papers to examine in surplus transfer (--transferable-only)
|
||||
|
||||
* *Include non-transferable papers* (default): When this option is selected, all ballot papers of the transferring candidate are examined. Non-transferable papers are always exhausted at the relevant surplus fractions.
|
||||
* *Use transferable papers only* (CLI: --transferable-only): When this option is selected, only transferable papers of the transferring candidate are examined. Non-transferable papers are exhausted only if the value of the transferable papers is less than the surplus.
|
||||
* *Include non-transferable papers* (default): When this option is selected, all ballot papers of the transferring candidate are examined. Non-transferable papers are always exhausted at the relevant surplus fractions. This is the method typically used with the weighted inclusive Gregory or Meek methods.
|
||||
* *Use transferable papers only*: When this option is selected, only transferable papers of the transferring candidate are examined. Non-transferable papers are exhausted only if the value of the transferable papers is less than the surplus. This is the method typically used with other surplus distribution methods.
|
||||
|
||||
### (Gregory) Exclusion method (--exclusion)
|
||||
|
||||
@ -125,7 +125,7 @@ When *Surplus method* is set to *Meek method*, this option controls how candidat
|
||||
|
||||
When *Surplus method* is set to a random sample method, this option controls which subset of ballot papers is selected for transfer during surplus distributions:
|
||||
|
||||
* *Stratified (then by order)*: The candidate's ballot papers are first stratified into subparcels according to next available preference. From each subparcel, the subset transferred comprises the ballot papers most recently received by the candidate.
|
||||
* *Stratified (then by order)* (default): The candidate's ballot papers are first stratified into subparcels according to next available preference. From each subparcel, the subset transferred comprises the ballot papers most recently received by the candidate.
|
||||
* *By order*: The subset transferred comprises the ballot papers most recently received by the candidate.
|
||||
* *Every n-th ballot*: The subset is selected using the deterministic method used in [Cambridge, Massachusetts](https://web.archive.org/web/20081118104049/http://www.fairvote.org/media/1993countmanual.pdf) (derived from Article IX of the former 1938 Cincinnati *Code of Ordinances*).
|
||||
|
||||
@ -173,7 +173,7 @@ This dropdown allows you to select how numbers (vote totals, etc.) are represent
|
||||
|
||||
* *Fixed*: Numbers are represented as fixed-precision decimals, up to a certain number of decimal places (default: 5).
|
||||
* *Fixed (guarded)*: Numbers are represented as fixed-precision decimals with ‘guard digits’ – also known as [‘quasi-exact’ arithmetic](http://www.votingmatters.org.uk/ISSUE24/I24P2.pdf). If *n* decimal places are requested, numbers are represented up to 2*n* decimal places, and two values are considered equal if the absolute difference is less than (10<sup>−*n*</sup>)/2.
|
||||
* *Rational*: Numbers are represented exactly as fractions, resulting in the elimination of rounding error, but increasing computational complexity when the number of surplus transfers is very large.
|
||||
* *Rational* (default): Numbers are represented exactly as fractions, resulting in the elimination of rounding error, but increasing computational complexity when the number of surplus transfers is very large.
|
||||
* *Float (64-bit)*: Numbers are represented as native 64-bit floating-point numbers. This is fast, but not recommended as unexpectedly large rounding errors may be introduced in some circumstances.
|
||||
|
||||
### Display up to [n] d.p. (--pp-decimals)
|
||||
|
@ -365,7 +365,7 @@ async function printResult() {
|
||||
function changePreset() {
|
||||
if (document.getElementById('selPreset').value === 'wigm') {
|
||||
document.getElementById('selQuotaCriterion').value = 'gt';
|
||||
document.getElementById('selQuota').value = 'droop_exact';
|
||||
document.getElementById('selQuota').value = 'droop';
|
||||
document.getElementById('selQuotaMode').value = 'static';
|
||||
document.getElementById('chkBulkElection').checked = true;
|
||||
document.getElementById('chkBulkExclusion').checked = false;
|
||||
|
@ -97,7 +97,7 @@ struct STV {
|
||||
// -- Quota --
|
||||
|
||||
/// Quota type
|
||||
#[clap(help_heading=Some("QUOTA"), short, long, possible_values=&["droop", "hare", "droop_exact", "hare_exact"], default_value="droop_exact")]
|
||||
#[clap(help_heading=Some("QUOTA"), short, long, possible_values=&["droop", "hare", "droop_exact", "hare_exact"], default_value="droop")]
|
||||
quota: String,
|
||||
|
||||
/// Whether to elect candidates on meeting (geq) or strictly exceeding (gt) the quota
|
||||
|
@ -75,7 +75,7 @@ pub struct STVOptions {
|
||||
pub normalise_ballots: bool,
|
||||
|
||||
/// Quota type
|
||||
#[builder(default="QuotaType::DroopExact")]
|
||||
#[builder(default="QuotaType::Droop")]
|
||||
pub quota: QuotaType,
|
||||
|
||||
/// Whether to elect candidates on meeting (geq) or strictly exceeding (gt) the quota
|
||||
@ -173,7 +173,7 @@ impl STVOptions {
|
||||
if self.surplus != SurplusMethod::Meek && self.sum_surplus_transfers != SumSurplusTransfersMode::SingleStep { flags.push(self.sum_surplus_transfers.describe()); }
|
||||
if self.surplus == SurplusMethod::Meek && self.meek_surplus_tolerance != "0.001%" { flags.push(format!("--meek-surplus-tolerance {}", self.meek_surplus_tolerance)); }
|
||||
if self.normalise_ballots { flags.push("--normalise-ballots".to_string()); }
|
||||
if self.quota != QuotaType::DroopExact { flags.push(self.quota.describe()); }
|
||||
if self.quota != QuotaType::Droop { flags.push(self.quota.describe()); }
|
||||
if self.quota_criterion != QuotaCriterion::Greater { flags.push(self.quota_criterion.describe()); }
|
||||
if self.surplus != SurplusMethod::Meek && self.quota_mode != QuotaMode::Static { flags.push(self.quota_mode.describe()); }
|
||||
let ties_str = self.ties.iter().map(|t| t.describe()).join(" ");
|
||||
|
@ -25,7 +25,6 @@ fn act_kurrajong20_rational() {
|
||||
let stv_opts = stv::STVOptionsBuilder::default()
|
||||
.round_votes(Some(6))
|
||||
.round_quota(Some(0))
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.surplus(stv::SurplusMethod::EG)
|
||||
.surplus_order(stv::SurplusOrder::ByOrder)
|
||||
|
@ -62,7 +62,6 @@ fn aec_tas19_rational() {
|
||||
let stv_opts = stv::STVOptionsBuilder::default()
|
||||
.round_votes(Some(0))
|
||||
.round_quota(Some(0))
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.surplus(stv::SurplusMethod::UIG)
|
||||
.surplus_order(stv::SurplusOrder::ByOrder)
|
||||
|
@ -25,7 +25,6 @@ fn cambridge_cc03_rational() {
|
||||
let stv_opts = stv::STVOptionsBuilder::default()
|
||||
.round_quota(Some(0))
|
||||
.normalise_ballots(true)
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.surplus(stv::SurplusMethod::Cincinnati)
|
||||
.transferable_only(true)
|
||||
|
@ -19,9 +19,9 @@ use assert_cmd::Command;
|
||||
use predicates::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn cli_ers97() {
|
||||
fn cli_ers97old() {
|
||||
Command::cargo_bin("opentally").expect("Cargo Error")
|
||||
.args(&["stv", "tests/data/ers97.blt", "--numbers", "fixed", "--decimals", "5", "--round-tvs", "2", "--round-weights", "2", "--round-votes", "2", "--round-quota", "2", "--quota", "droop_exact", "--quota-mode", "ers97", "--surplus", "eg", "--transferable-only", "--exclusion", "by_value"])
|
||||
.args(&["stv", "tests/data/ers97old.blt", "--numbers", "fixed", "--decimals", "5", "--round-tvs", "2", "--round-weights", "2", "--round-votes", "2", "--round-quota", "2", "--quota", "droop_exact", "--quota-mode", "ers97", "--surplus", "eg", "--transferable-only", "--exclusion", "by_value"])
|
||||
.assert().success();
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,6 @@ fn prsa1_constr1_rational() {
|
||||
.round_values(Some(3))
|
||||
.round_votes(Some(3))
|
||||
.round_quota(Some(3))
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.surplus(stv::SurplusMethod::EG)
|
||||
.surplus_order(stv::SurplusOrder::ByOrder)
|
||||
@ -93,7 +92,6 @@ fn prsa1_constr2_rational() {
|
||||
.round_values(Some(3))
|
||||
.round_votes(Some(3))
|
||||
.round_quota(Some(3))
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.surplus(stv::SurplusMethod::EG)
|
||||
.surplus_order(stv::SurplusOrder::ByOrder)
|
||||
@ -143,7 +141,6 @@ fn prsa1_constr3_rational() {
|
||||
.round_values(Some(3))
|
||||
.round_votes(Some(3))
|
||||
.round_quota(Some(3))
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.surplus(stv::SurplusMethod::EG)
|
||||
.surplus_order(stv::SurplusOrder::ByOrder)
|
||||
@ -177,11 +174,11 @@ fn prsa1_constr3_rational() {
|
||||
|
||||
/// Same election data as ers97_rational, but with a constraint that prevents the bulk exclusion of Glazier and Wright
|
||||
#[test]
|
||||
fn ers97_cantbulkexclude_rational() {
|
||||
fn ers97old_cantbulkexclude_rational() {
|
||||
// Read CSV file
|
||||
let reader = csv::ReaderBuilder::new()
|
||||
.has_headers(false)
|
||||
.from_path("tests/data/ers97_cantbulkexclude.csv")
|
||||
.from_path("tests/data/ers97old_cantbulkexclude.csv")
|
||||
.expect("IO Error");
|
||||
let records: Vec<csv::StringRecord> = reader.into_records().map(|r| r.expect("Syntax Error")).collect();
|
||||
|
||||
@ -192,10 +189,10 @@ fn ers97_cantbulkexclude_rational() {
|
||||
let stages: Vec<usize> = records.first().unwrap().iter().skip(1).step_by(2).map(|s| s.parse().unwrap()).collect();
|
||||
|
||||
// Read BLT
|
||||
let mut election: Election<Rational> = Election::from_file("tests/data/ers97.blt").expect("Syntax Error");
|
||||
let mut election: Election<Rational> = Election::from_file("tests/data/ers97old.blt").expect("Syntax Error");
|
||||
|
||||
// Read CON
|
||||
let file = File::open("tests/data/ers97_cantbulkexclude.con").expect("IO Error");
|
||||
let file = File::open("tests/data/ers97old_cantbulkexclude.con").expect("IO Error");
|
||||
let file_reader = io::BufReader::new(file);
|
||||
let lines = file_reader.lines();
|
||||
election.constraints = Some(Constraints::from_con(lines.map(|r| r.expect("IO Error").to_string()).into_iter()));
|
||||
@ -205,6 +202,7 @@ fn ers97_cantbulkexclude_rational() {
|
||||
.round_values(Some(2))
|
||||
.round_votes(Some(2))
|
||||
.round_quota(Some(2))
|
||||
.quota(stv::QuotaType::DroopExact)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.quota_mode(stv::QuotaMode::ERS97)
|
||||
.surplus(stv::SurplusMethod::EG)
|
||||
@ -213,7 +211,7 @@ fn ers97_cantbulkexclude_rational() {
|
||||
.early_bulk_elect(false)
|
||||
.bulk_exclude(true)
|
||||
.defer_surpluses(true)
|
||||
.constraints_path(Some("tests/data/ers97_cantbulkexclude".to_string()))
|
||||
.constraints_path(Some("tests/data/ers97old_cantbulkexclude".to_string()))
|
||||
.build().unwrap();
|
||||
|
||||
utils::validate_election::<Rational>(stages, records, election, stv_opts, None, &["nt", "vre"]);
|
||||
|
@ -24,7 +24,6 @@ use opentally::stv;
|
||||
fn csm15_float64() {
|
||||
let stv_opts = stv::STVOptionsBuilder::default()
|
||||
.round_quota(Some(0))
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.exclusion(stv::ExclusionMethod::Wright)
|
||||
.early_bulk_elect(false)
|
||||
|
@ -21,12 +21,13 @@ use opentally::numbers::Rational;
|
||||
use opentally::stv;
|
||||
|
||||
#[test]
|
||||
fn ers97_rational() {
|
||||
fn ers97old_rational() {
|
||||
let stv_opts = stv::STVOptionsBuilder::default()
|
||||
.round_surplus_fractions(Some(2))
|
||||
.round_values(Some(2))
|
||||
.round_votes(Some(2))
|
||||
.round_quota(Some(2))
|
||||
.quota(stv::QuotaType::DroopExact)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.quota_mode(stv::QuotaMode::ERS97)
|
||||
.surplus(stv::SurplusMethod::EG)
|
||||
@ -37,5 +38,5 @@ fn ers97_rational() {
|
||||
.defer_surpluses(true)
|
||||
.build().unwrap();
|
||||
|
||||
utils::read_validate_election::<Rational>("tests/data/ers97.csv", "tests/data/ers97.blt", stv_opts, None, &["nt", "vre"]);
|
||||
utils::read_validate_election::<Rational>("tests/data/ers97old.csv", "tests/data/ers97old.blt", stv_opts, None, &["nt", "vre"]);
|
||||
}
|
||||
|
@ -21,30 +21,30 @@ use opentally::election::{CandidateState, CountState, Election};
|
||||
use opentally::numbers::{Fixed, NativeFloat64, Number};
|
||||
use opentally::stv;
|
||||
|
||||
// Compare ers97.blt count with result produced by 1987 Hill–Wichmann–Woodall reference implementation
|
||||
// Compare ers97old.blt count with result produced by 1987 Hill–Wichmann–Woodall reference implementation
|
||||
#[test]
|
||||
fn meek87_ers97_float64() {
|
||||
fn meek87_ers97old_float64() {
|
||||
let stv_opts = stv::STVOptionsBuilder::default()
|
||||
.meek_surplus_tolerance("0.001%".to_string())
|
||||
.quota(stv::QuotaType::DroopExact)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.quota_mode(stv::QuotaMode::DynamicByTotal)
|
||||
.surplus(stv::SurplusMethod::Meek)
|
||||
.immediate_elect(false)
|
||||
.build().unwrap();
|
||||
|
||||
utils::read_validate_election::<NativeFloat64>("tests/data/ers97_meek.csv", "tests/data/ers97.blt", stv_opts, Some(2), &["exhausted", "quota"]);
|
||||
utils::read_validate_election::<NativeFloat64>("tests/data/ers97old_meek.csv", "tests/data/ers97old.blt", stv_opts, Some(2), &["exhausted", "quota"]);
|
||||
}
|
||||
|
||||
// Compare ers97.blt count with result produced by OpenSTV 1.7 "Meek STV"
|
||||
// Compare ers97old.blt count with result produced by OpenSTV 1.7 "Meek STV"
|
||||
#[test]
|
||||
fn meek06_ers97_fixed12() {
|
||||
fn meek06_ers97old_fixed12() {
|
||||
let stv_opts = stv::STVOptionsBuilder::default()
|
||||
.round_surplus_fractions(Some(9))
|
||||
.round_values(Some(9))
|
||||
.round_votes(Some(9))
|
||||
.round_quota(Some(9))
|
||||
.meek_surplus_tolerance("0.0001".to_string())
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.quota_mode(stv::QuotaMode::DynamicByTotal)
|
||||
.surplus(stv::SurplusMethod::Meek)
|
||||
@ -54,7 +54,7 @@ fn meek06_ers97_fixed12() {
|
||||
Fixed::set_dps(12);
|
||||
|
||||
// Read BLT
|
||||
let election: Election<Fixed> = Election::from_file("tests/data/ers97.blt").expect("Syntax Error");
|
||||
let election: Election<Fixed> = Election::from_file("tests/data/ers97old.blt").expect("Syntax Error");
|
||||
|
||||
// Initialise count state
|
||||
let mut state = CountState::new(&election);
|
||||
@ -95,16 +95,15 @@ fn meek06_ers97_fixed12() {
|
||||
}
|
||||
}
|
||||
|
||||
// Compare ers97.blt count with result produced by OpenSTV 1.7 "New Zealand Meek STV" (same result as Hill 2006 implementation)
|
||||
// Compare ers97old.blt count with result produced by OpenSTV 1.7 "New Zealand Meek STV" (same result as Hill 2006 implementation)
|
||||
#[test]
|
||||
fn meeknz_ers97_fixed12() {
|
||||
fn meeknz_ers97old_fixed12() {
|
||||
let stv_opts = stv::STVOptionsBuilder::default()
|
||||
.round_surplus_fractions(Some(9))
|
||||
.round_values(Some(9))
|
||||
.round_votes(Some(9))
|
||||
.round_quota(Some(9))
|
||||
.meek_surplus_tolerance("0.0001".to_string())
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.quota_mode(stv::QuotaMode::DynamicByTotal)
|
||||
.surplus(stv::SurplusMethod::Meek)
|
||||
@ -115,7 +114,7 @@ fn meeknz_ers97_fixed12() {
|
||||
Fixed::set_dps(12);
|
||||
|
||||
// Read BLT
|
||||
let election: Election<Fixed> = Election::from_file("tests/data/ers97.blt").expect("Syntax Error");
|
||||
let election: Election<Fixed> = Election::from_file("tests/data/ers97old.blt").expect("Syntax Error");
|
||||
|
||||
// Initialise count state
|
||||
let mut state = CountState::new(&election);
|
||||
|
@ -25,7 +25,6 @@ fn minneapolis_boe09_rational() {
|
||||
let stv_opts = stv::STVOptionsBuilder::default()
|
||||
.round_surplus_fractions(Some(4))
|
||||
.round_quota(Some(0))
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.early_bulk_elect(true)
|
||||
.bulk_exclude(true)
|
||||
@ -41,7 +40,6 @@ fn minneapolis_pal13_rational() {
|
||||
let stv_opts = stv::STVOptionsBuilder::default()
|
||||
.round_surplus_fractions(Some(4))
|
||||
.round_quota(Some(0))
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.early_bulk_elect(true)
|
||||
.bulk_exclude(true)
|
||||
|
@ -27,7 +27,6 @@ fn prsa1_rational() {
|
||||
.round_values(Some(3))
|
||||
.round_votes(Some(3))
|
||||
.round_quota(Some(3))
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.surplus(stv::SurplusMethod::EG)
|
||||
.surplus_order(stv::SurplusOrder::ByOrder)
|
||||
|
@ -33,7 +33,6 @@ fn scotland_linn07_fixed5() {
|
||||
.round_quota(Some(0))
|
||||
.sum_surplus_transfers(stv::SumSurplusTransfersMode::PerBallot)
|
||||
.normalise_ballots(true)
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.early_bulk_elect(false)
|
||||
.pp_decimals(5)
|
||||
@ -52,7 +51,6 @@ fn scotland_linn07_gfixed5() {
|
||||
.round_quota(Some(0))
|
||||
.sum_surplus_transfers(stv::SumSurplusTransfersMode::PerBallot)
|
||||
.normalise_ballots(true)
|
||||
.quota(stv::QuotaType::Droop)
|
||||
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
|
||||
.early_bulk_elect(false)
|
||||
.pp_decimals(5)
|
||||
|
Loading…
Reference in New Issue
Block a user