Update terminology and remove "stratify (floor)" support

Cincinnati -> Inclusive Hare (previous usage was erroneous/nonstandard)
Every n-th ballot -> Cincinnati
Remove "stratify (floor)" as it is not in contemporary use
This commit is contained in:
RunasSudo 2021-09-27 19:02:30 +10:00
parent 0506283ae4
commit 93cb72c33a
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
8 changed files with 55 additions and 56 deletions

View File

@ -97,8 +97,8 @@ Other Gregory methods are supported, but not recommended:
Random sample methods are also supported, but also not recommended:
* *Cincinnati (inclusive sample)*: During surplus transfers, a subset of the elected candidate's ballot papers, equal in size to the surplus, is examined.
* *Hare (exclusive sample)*: During surplus transfers, a subset of the ballot papers received in the last transfer, equal in size to the surplus, is examined.
* *Inclusive Hare (sample)*: During surplus transfers, a subset of the elected candidate's ballot papers, equal in size to the surplus, is examined.
The use of a random sample method requires *Normalise ballots* to be enabled, and will usually be used with a *Quota criterion* set to *>=*.
@ -128,10 +128,9 @@ 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:
* *Stratify (LR)* (default): The candidate's ballot papers are first stratified into subparcels according to next available preference, and an equal proportion of each subparcel is transferred, with the subset transferred comprising the ballot papers in each subparcel most recently received by the candidate. In the calculation of proportions, the largest remainders are rounded up so there is no loss by fraction. This is the method specified by the [*Electoral Act 1992* (Ireland)](http://www.irishstatutebook.ie/eli/1992/act/23/section/121/enacted/en/html#sec121).
* *Stratify (floor)*: The same as *Stratify (LR)*, except in the calculation of proportions, all remainders are disregarded, and the difference is lost by fraction.
* *Stratify* (default): The candidate's ballot papers are first stratified into subparcels according to next available preference, and an equal proportion of each subparcel is transferred, with the subset transferred comprising the ballot papers in each subparcel most recently received by the candidate. In the calculation of proportions, the largest remainders are rounded up so there is no loss by fraction. This is the method specified by the [*Electoral Act 1992* (Ireland)](http://www.irishstatutebook.ie/eli/1992/act/23/section/121/enacted/en/html#sec121).
* *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*).
* *Cincinnati*: 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*).
In any case, the subset selected depends on the order of ballot papers in the BLT file, and is independent of the *Random seed* option.

View File

@ -115,8 +115,8 @@
<option value="uig">Unweighted inclusive Gregory</option>
<option value="eg">Exclusive Gregory (last bundle)</option>
<option value="meek">Meek method</option>
<option value="cincinnati">Cincinnati (inclusive sample)</option>
<option value="hare">Hare (exclusive sample)</option>
<option value="ihare">Inclusive Hare (sample)</option>
</select>
</label>
<label>
@ -146,13 +146,13 @@
</div>
<div>
<label style="margin-right:1em;">
<span class="pill-grey" title="This option has effect only if “Method” is set to a random sample method">Sample</span>
<span class="pill-grey" title="This option has effect only if “Method” is set to a Hare method">Hare</span>
Sample method:
<select id="selSample">
<option value="stratify_lr" selected>Stratify (LR)</option>
<option value="stratify_floor" selected>Stratify (floor)</option>
<option value="stratify" selected>Stratify</option>
<!--<option value="stratify_floor" selected>Stratify (floor)</option>-->
<option value="by_order">By order</option>
<option value="nth_ballot">Every n-th ballot</option>
<option value="cincinnati">Cincinnati</option>
</select>
</label>
<label>

View File

@ -671,7 +671,7 @@ function changePreset() {
document.getElementById('chkBulkExclusion').checked = false;
document.getElementById('chkDeferSurpluses').checked = false;
document.getElementById('chkImmediateElect').checked = true;
document.getElementById('selSample').value = 'nth_ballot';
document.getElementById('selSample').value = 'cincinnati';
document.getElementById('chkSamplePerBallot').checked = true;
document.getElementById('txtMinThreshold').value = '49';
document.getElementById('selNumbers').value = 'rational';
@ -680,7 +680,7 @@ function changePreset() {
document.getElementById('chkRoundQuota').checked = true;
document.getElementById('txtRoundQuota').value = '0';
document.getElementById('selSumTransfers').value = 'by_value';
document.getElementById('selMethod').value = 'cincinnati';
document.getElementById('selMethod').value = 'hare';
document.getElementById('selPapers').value = 'transferable';
document.getElementById('selExclusion').value = 'single_stage';
document.getElementById('selTies').value = 'backwards,random';
@ -692,7 +692,7 @@ function changePreset() {
document.getElementById('chkBulkExclusion').checked = false;
document.getElementById('chkDeferSurpluses').checked = true;
document.getElementById('chkImmediateElect').checked = true;
document.getElementById('selSample').value = 'stratify_lr';
document.getElementById('selSample').value = 'stratify';
document.getElementById('chkSamplePerBallot').checked = false;
document.getElementById('txtMinThreshold').value = '0';
document.getElementById('selNumbers').value = 'rational';

View File

@ -113,8 +113,8 @@ pub struct SubcmdOptions {
#[clap(help_heading=Some("STV VARIANTS"), long, value_name="seed")]
random_seed: Option<String>,
/// Method of surplus distributions
#[clap(help_heading=Some("STV VARIANTS"), short='s', long, possible_values=&["wig", "uig", "eg", "meek", "cincinnati", "hare"], default_value="wig", value_name="method")]
/// Method of surplus distributions [default: wig] [possible values: wig, uig, eg, meek, ihare, hare]
#[clap(help_heading=Some("STV VARIANTS"), short='s', long, possible_values=&["wig", "uig", "eg", "meek", "ihare", "hare", "eh"], default_value="wig", value_name="method", hide_possible_values=true, hide_default_value=true)]
surplus: String,
/// (Gregory STV) Order to distribute surpluses
@ -133,11 +133,11 @@ pub struct SubcmdOptions {
#[clap(help_heading=Some("STV VARIANTS"), long)]
meek_nz_exclusion: bool,
/// (Cincinnati/Hare) Method of drawing a sample
#[clap(help_heading=Some("STV VARIANTS"), long, possible_values=&["stratify_lr", "stratify_floor", "by_order", "nth_ballot"], default_value="stratify_lr", value_name="method")]
/// (Hare) Method of drawing a sample [default: stratify] [possible values: stratify, by_order, cincinnati]
#[clap(help_heading=Some("STV VARIANTS"), long, possible_values=&["stratify", "stratify_lr", "by_order", "cincinnati", "nth_ballot"], default_value="stratify", value_name="method", hide_possible_values=true, hide_default_value=true)]
sample: String,
/// (Cincinnati/Hare) Sample-based methods: Check for candidate election after each individual ballot paper transfer
/// (Hare) Sample-based methods: Check for candidate election after each individual ballot paper transfer
#[clap(help_heading=Some("STV VARIANTS"), long)]
sample_per_ballot: bool,

View File

@ -158,7 +158,7 @@ where
match opts.surplus {
SurplusMethod::WIG | SurplusMethod::UIG | SurplusMethod::EG => { distribute_surplus(state, &opts, elected_candidate); }
SurplusMethod::Cincinnati | SurplusMethod::Hare => { sample::distribute_surplus(state, &opts, elected_candidate)?; }
SurplusMethod::IHare | SurplusMethod::Hare => { sample::distribute_surplus(state, &opts, elected_candidate)?; }
_ => unreachable!()
}

View File

@ -111,11 +111,11 @@ pub struct STVOptions {
#[builder(default="false")]
pub meek_nz_exclusion: bool,
/// (Cincinnati/Hare) Method of drawing a sample
/// (Hare) Method of drawing a sample
#[builder(default="SampleMethod::StratifyLR")]
pub sample: SampleMethod,
/// (Cincinnati/Hare) Sample-based methods: Check for candidate election after each individual ballot paper transfer
/// (Hare) Sample-based methods: Check for candidate election after each individual ballot paper transfer
#[builder(default="false")]
pub sample_per_ballot: bool,
@ -169,7 +169,7 @@ impl STVOptions {
pub fn describe<N: Number>(&self) -> String {
let mut flags = Vec::new();
let n_str = N::describe_opt(); if !n_str.is_empty() { flags.push(N::describe_opt()) };
if self.surplus != SurplusMethod::Cincinnati && self.surplus != SurplusMethod::Hare {
if self.surplus != SurplusMethod::IHare && self.surplus != SurplusMethod::Hare {
if let Some(dps) = self.round_surplus_fractions { flags.push(format!("--round-surplus-fractions {}", dps)); }
if let Some(dps) = self.round_values { flags.push(format!("--round-values {}", dps)); }
if let Some(dps) = self.round_votes { flags.push(format!("--round-votes {}", dps)); }
@ -191,8 +191,8 @@ impl STVOptions {
if self.exclusion != ExclusionMethod::SingleStage { flags.push(self.exclusion.describe()); }
}
if self.surplus == SurplusMethod::Meek && self.meek_nz_exclusion { flags.push("--meek-nz-exclusion".to_string()); }
if (self.surplus == SurplusMethod::Cincinnati || self.surplus == SurplusMethod::Hare) && self.sample != SampleMethod::StratifyLR { flags.push(self.sample.describe()); }
if (self.surplus == SurplusMethod::Cincinnati || self.surplus == SurplusMethod::Hare) && self.sample_per_ballot { flags.push("--sample-per-ballot".to_string()); }
if (self.surplus == SurplusMethod::IHare || self.surplus == SurplusMethod::Hare) && self.sample != SampleMethod::StratifyLR { flags.push(self.sample.describe()); }
if (self.surplus == SurplusMethod::IHare || self.surplus == SurplusMethod::Hare) && self.sample_per_ballot { flags.push("--sample-per-ballot".to_string()); }
if !self.early_bulk_elect { flags.push("--no-early-bulk-elect".to_string()); }
if self.bulk_exclude { flags.push("--bulk-exclude".to_string()); }
if self.defer_surpluses { flags.push("--defer-surpluses".to_string()); }
@ -216,11 +216,11 @@ impl STVOptions {
if self.transferable_only { return Err(STVError::InvalidOptions("--surplus meek is incompatible with --transferable-only")); }
if self.exclusion != ExclusionMethod::SingleStage { return Err(STVError::InvalidOptions("--surplus meek requires --exclusion single_stage")); }
}
if self.surplus == SurplusMethod::Cincinnati || self.surplus == SurplusMethod::Hare {
if self.round_quota != Some(0) { return Err(STVError::InvalidOptions("--surplus cincinnati and --surplus hare require --round-quota 0")); }
if !self.normalise_ballots { return Err(STVError::InvalidOptions("--surplus cincinnati and --surplus hare require --normalise-ballots")); }
if self.surplus == SurplusMethod::IHare || self.surplus == SurplusMethod::Hare {
if self.round_quota != Some(0) { return Err(STVError::InvalidOptions("--surplus ihare and --surplus hare require --round-quota 0")); }
if !self.normalise_ballots { return Err(STVError::InvalidOptions("--surplus ihare and --surplus hare require --normalise-ballots")); }
if self.sample == SampleMethod::StratifyLR && self.sample_per_ballot { return Err(STVError::InvalidOptions("--sample stratify_lr 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 == SampleMethod::StratifyFloor && self.sample_per_ballot { return Err(STVError::InvalidOptions("--sample stratify_floor is incompatible with --sample-per-ballot")); }
if self.sample == SampleMethod::StratifyLR && self.round_surplus_fractions.is_some() { return Err(STVError::InvalidOptions("--sample stratify_lr is incompatible with --round-surplus-fractions")); }
if self.sample_per_ballot && !self.immediate_elect { return Err(STVError::InvalidOptions("--sample-per-ballot is incompatible with --no-immediate-elect")); }
}
@ -386,9 +386,9 @@ pub enum SurplusMethod {
EG,
/// Meek method
Meek,
/// Cincinnati method (inclusive random subset)
Cincinnati,
/// Hare method (exclusive random subset)
/// Inclusive Hare method (random subset)
IHare,
/// (Exclusive) Hare method (random subset)
Hare,
}
@ -400,7 +400,7 @@ impl SurplusMethod {
SurplusMethod::UIG => "--surplus uig",
SurplusMethod::EG => "--surplus eg",
SurplusMethod::Meek => "--surplus meek",
SurplusMethod::Cincinnati => "--surplus cincinnati",
SurplusMethod::IHare => "--surplus ihare",
SurplusMethod::Hare => "--surplus hare",
}.to_string()
}
@ -422,8 +422,8 @@ impl<S: AsRef<str>> From<S> for SurplusMethod {
"uig" => SurplusMethod::UIG,
"eg" => SurplusMethod::EG,
"meek" => SurplusMethod::Meek,
"cincinnati" => SurplusMethod::Cincinnati,
"hare" => SurplusMethod::Hare,
"ihare" | "ih" | "cincinnati" => SurplusMethod::IHare, // Inclusive Hare method used to be erroneously referred to as "Cincinnati" method - accept for backwards compatibility
"hare" | "eh" => SurplusMethod::Hare,
_ => panic!("Invalid --surplus"),
}
}
@ -510,22 +510,22 @@ impl<S: AsRef<str>> From<S> for ExclusionMethod {
pub enum SampleMethod {
/// Stratify the ballots into parcels according to next available preference and transfer the last ballots from each parcel; round fractions according to largest remainders
StratifyLR,
/// Stratify the ballots into parcels according to next available preference and transfer the last ballots from each parcel; disregard fractions
StratifyFloor,
// Stratify the ballots into parcels according to next available preference and transfer the last ballots from each parcel; disregard fractions
//StratifyFloor,
/// Transfer the last ballots
ByOrder,
/// Transfer every n-th ballot, Cincinnati style
NthBallot,
Cincinnati,
}
impl SampleMethod {
/// Convert to CLI argument representation
fn describe(self) -> String {
match self {
SampleMethod::StratifyLR => "--sample stratify_lr",
SampleMethod::StratifyFloor => "--sample stratify_floor",
SampleMethod::StratifyLR => "--sample stratify",
//SampleMethod::StratifyFloor => "--sample stratify_floor",
SampleMethod::ByOrder => "--sample by_order",
SampleMethod::NthBallot => "--sample nth_ballot",
SampleMethod::Cincinnati => "--sample cincinnati",
}.to_string()
}
}
@ -533,10 +533,10 @@ impl SampleMethod {
impl<S: AsRef<str>> From<S> for SampleMethod {
fn from(s: S) -> Self {
match s.as_ref() {
"stratify_lr" => SampleMethod::StratifyLR,
"stratify_floor" => SampleMethod::StratifyFloor,
"stratify" | "stratify_lr" => SampleMethod::StratifyLR,
//"stratify_floor" => SampleMethod::StratifyFloor,
"by_order" => SampleMethod::ByOrder,
"nth_ballot" => SampleMethod::NthBallot,
"cincinnati" | "nth_ballot" => SampleMethod::Cincinnati,
_ => panic!("Invalid --sample-method"),
}
}
@ -780,7 +780,7 @@ where
for<'r> &'r N: ops::Mul<&'r N, Output=N>,
{
match opts.surplus {
SurplusMethod::WIG | SurplusMethod::UIG | SurplusMethod::EG | SurplusMethod::Cincinnati | SurplusMethod::Hare => {
SurplusMethod::WIG | SurplusMethod::UIG | SurplusMethod::EG | SurplusMethod::IHare | SurplusMethod::Hare => {
gregory::distribute_first_preferences(state, opts);
}
SurplusMethod::Meek => {
@ -1227,7 +1227,7 @@ where
for<'r> &'r N: ops::Neg<Output=N>,
{
match opts.surplus {
SurplusMethod::WIG | SurplusMethod::UIG | SurplusMethod::EG | SurplusMethod::Cincinnati | SurplusMethod::Hare => {
SurplusMethod::WIG | SurplusMethod::UIG | SurplusMethod::EG | SurplusMethod::IHare | SurplusMethod::Hare => {
return gregory::distribute_surpluses(state, opts);
}
SurplusMethod::Meek => {
@ -1558,7 +1558,7 @@ where
SurplusMethod::Meek => {
meek::exclude_candidates(state, opts, excluded_candidates);
}
SurplusMethod::Cincinnati | SurplusMethod::Hare => {
SurplusMethod::IHare | SurplusMethod::Hare => {
sample::exclude_candidates(state, opts, excluded_candidates)?;
}
}

View File

@ -60,7 +60,7 @@ where
let mut votes;
match opts.surplus {
SurplusMethod::Cincinnati => {
SurplusMethod::IHare => {
// Inclusive
votes = count_card.concat_parcels();
}
@ -73,7 +73,7 @@ where
}
match opts.sample {
SampleMethod::StratifyLR | SampleMethod::StratifyFloor => {
SampleMethod::StratifyLR /*| SampleMethod::StratifyFloor*/ => {
// Stratified by next available preference (round fractions according to largest remainders)
let result = super::next_preferences(state, votes);
@ -122,7 +122,7 @@ where
let mut candidate_transfers;
let remainder;
match surplus_fraction {
Some(ref f) => {
Some(_) => {
match opts.sample {
SampleMethod::StratifyLR => {
// Incompatible with --round-surplus-fractions
@ -130,7 +130,7 @@ where
candidate_transfers.floor_mut(0);
remainder = (&entry.num_ballots * &surplus) % surplus_denom.as_ref().unwrap();
}
SampleMethod::StratifyFloor => {
/*SampleMethod::StratifyFloor => {
match opts.round_surplus_fractions {
Some(_) => {
candidate_transfers = &entry.num_ballots * f;
@ -141,7 +141,7 @@ where
}
candidate_transfers.floor_mut(0);
remainder = N::new();
}
}*/
_ => unreachable!()
}
}
@ -166,7 +166,7 @@ where
exhausted_transfers.floor_mut(0);
remainder = (&result.exhausted.num_ballots * &surplus) % surplus_denom.as_ref().unwrap();
}
SampleMethod::StratifyFloor => {
/*SampleMethod::StratifyFloor => {
match opts.round_surplus_fractions {
Some(_) => {
exhausted_transfers = &result.exhausted.num_ballots * surplus_fraction.as_ref().unwrap();
@ -177,7 +177,7 @@ where
}
exhausted_transfers.floor_mut(0);
remainder = N::new();
}
}*/
_ => unreachable!()
}
@ -314,7 +314,7 @@ where
}
}
}
SampleMethod::NthBallot => {
SampleMethod::Cincinnati => {
// Every nth-ballot (Cincinnati-style)
// Calculate skip value

View File

@ -26,15 +26,15 @@ fn cambridge_cc03_rational() {
.round_quota(Some(0))
.normalise_ballots(true)
.quota_criterion(stv::QuotaCriterion::GreaterOrEqual)
.surplus(stv::SurplusMethod::Cincinnati)
.surplus(stv::SurplusMethod::Hare)
.transferable_only(true)
.sample(stv::SampleMethod::NthBallot)
.sample(stv::SampleMethod::Cincinnati)
.sample_per_ballot(true)
.early_bulk_elect(false)
.min_threshold("49".to_string())
.build().unwrap();
assert_eq!(stv_opts.describe::<Rational>(), "--round-quota 0 --normalise-ballots --quota-criterion geq --surplus cincinnati --transferable-only --sample nth_ballot --sample-per-ballot --no-early-bulk-elect --min-threshold 49");
assert_eq!(stv_opts.describe::<Rational>(), "--round-quota 0 --normalise-ballots --quota-criterion geq --surplus hare --transferable-only --sample cincinnati --sample-per-ballot --no-early-bulk-elect --min-threshold 49");
utils::read_validate_election::<Rational>("tests/data/CambCC2003.csv", "tests/data/CambCC2003.blt", stv_opts, None, &["exhausted"]);
}