diff --git a/docs/options.md b/docs/options.md index d32881d..8b9eda1 100644 --- a/docs/options.md +++ b/docs/options.md @@ -102,7 +102,7 @@ Random sample methods are also supported, but also not recommended: * *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 *>=*. +A random sample method will usually be used with a *Quota criterion* set to *>=*. ### Papers to examine in surplus transfer (--transferable-only/--subtract-nontransferable) @@ -219,14 +219,6 @@ This dropdown allows you to select how numbers (vote totals, etc.) are represent * *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. -### Normalise ballots (--normalise-ballots) - -In the BLT file format, each set of preferences can have a specified weight – this is typically used to indicate multiple voters who had the same preferences. - -When ballots are not normalised (default), a set of preferences with weight *n* > 1 is represented as a single ballot with value *n*. This is known as [list-packed ballots](http://www.votingmatters.org.uk/ISSUE21/I21P1.pdf). - -When ballots are normalised, a set of preferences with weight *n* > 1 is instead converted to *n* ballots each with value 1. - ## Count optimisations ### Early bulk election (--no-early-bulk-elect) diff --git a/html/index.html b/html/index.html index d26c216..685cef3 100644 --- a/html/index.html +++ b/html/index.html @@ -233,10 +233,6 @@ -
Count optimisations:
diff --git a/html/index.js b/html/index.js index cd8a296..9df3b30 100644 --- a/html/index.js +++ b/html/index.js @@ -146,7 +146,6 @@ async function clickCount() { document.getElementById('chkRoundQuota').checked ? parseInt(document.getElementById('txtRoundQuota').value) : null, document.getElementById('selSumTransfers').value, document.getElementById('txtMeekSurplusTolerance').value, - document.getElementById('chkNormaliseBallots').checked, document.getElementById('selQuota').value, document.getElementById('selQuotaCriterion').value, document.getElementById('selQuotaMode').value, @@ -189,7 +188,6 @@ async function clickCount() { 'optsStr': optsStr, 'numbers': document.getElementById('selNumbers').value, 'decimals': document.getElementById('txtDP').value, - 'normaliseBallots': document.getElementById('chkNormaliseBallots').checked, 'reportStyle': document.getElementById('selReport').value, }); } diff --git a/html/presets.js b/html/presets.js index fdb311c..00f85b1 100644 --- a/html/presets.js +++ b/html/presets.js @@ -27,7 +27,6 @@ function changePreset() { document.getElementById('txtMinThreshold').value = '0'; document.getElementById('selNumbers').value = 'rational'; document.getElementById('txtPPDP').value = '2'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = false; document.getElementById('chkRoundVotes').checked = false; document.getElementById('chkRoundSFs').checked = false; @@ -50,7 +49,6 @@ function changePreset() { document.getElementById('selNumbers').value = 'fixed'; document.getElementById('txtDP').value = '5'; document.getElementById('txtPPDP').value = '5'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '0'; document.getElementById('chkRoundVotes').checked = false; @@ -76,7 +74,6 @@ function changePreset() { document.getElementById('selNumbers').value = 'fixed'; document.getElementById('txtDP').value = '5'; document.getElementById('txtPPDP').value = '2'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = false; document.getElementById('chkRoundVotes').checked = false; document.getElementById('chkRoundSFs').checked = false; @@ -101,7 +98,6 @@ function changePreset() { document.getElementById('selNumbers').value = 'fixed'; document.getElementById('txtDP').value = '12'; document.getElementById('txtPPDP').value = '2'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '9'; document.getElementById('chkRoundVotes').checked = true; @@ -130,7 +126,6 @@ function changePreset() { document.getElementById('selNumbers').value = 'fixed'; document.getElementById('txtDP').value = '12'; document.getElementById('txtPPDP').value = '2'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '9'; document.getElementById('chkRoundVotes').checked = true; @@ -157,7 +152,6 @@ function changePreset() { document.getElementById('txtMinThreshold').value = '0'; document.getElementById('selNumbers').value = 'rational'; document.getElementById('txtPPDP').value = '0'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '0'; document.getElementById('chkRoundVotes').checked = true; @@ -181,7 +175,6 @@ function changePreset() { document.getElementById('txtMinThreshold').value = '0'; document.getElementById('selNumbers').value = 'rational'; document.getElementById('txtPPDP').value = '0'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '0'; document.getElementById('chkRoundVotes').checked = true; @@ -205,7 +198,6 @@ function changePreset() { document.getElementById('txtMinThreshold').value = '0'; document.getElementById('selNumbers').value = 'rational'; document.getElementById('txtPPDP').value = '2'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '0'; document.getElementById('chkRoundVotes').checked = true; @@ -229,7 +221,6 @@ function changePreset() { document.getElementById('txtMinThreshold').value = '0'; document.getElementById('selNumbers').value = 'rational'; document.getElementById('txtPPDP').value = '0'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '0'; document.getElementById('chkRoundVotes').checked = true; @@ -254,7 +245,6 @@ function changePreset() { document.getElementById('selNumbers').value = 'fixed'; document.getElementById('txtDP').value = '4'; document.getElementById('txtPPDP').value = '4'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '0'; document.getElementById('chkRoundVotes').checked = false; @@ -280,7 +270,6 @@ function changePreset() { document.getElementById('txtMinThreshold').value = '49'; document.getElementById('selNumbers').value = 'rational'; document.getElementById('txtPPDP').value = '0'; - document.getElementById('chkNormaliseBallots').checked = true; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '0'; document.getElementById('selSumTransfers').value = 'single_step'; @@ -301,7 +290,6 @@ function changePreset() { document.getElementById('txtMinThreshold').value = '0'; document.getElementById('selNumbers').value = 'rational'; document.getElementById('txtPPDP').value = '0'; - document.getElementById('chkNormaliseBallots').checked = true; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '0'; document.getElementById('selSumTransfers').value = 'single_step'; @@ -322,7 +310,6 @@ function changePreset() { document.getElementById('selNumbers').value = 'fixed'; document.getElementById('txtDP').value = '5'; document.getElementById('txtPPDP').value = '2'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '0'; document.getElementById('chkRoundVotes').checked = false; @@ -346,7 +333,6 @@ function changePreset() { document.getElementById('selNumbers').value = 'fixed'; document.getElementById('txtDP').value = '6'; document.getElementById('txtPPDP').value = '3'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '3'; document.getElementById('chkRoundVotes').checked = true; @@ -373,7 +359,6 @@ function changePreset() { document.getElementById('selNumbers').value = 'fixed'; document.getElementById('txtDP').value = '5'; document.getElementById('txtPPDP').value = '2'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '2'; document.getElementById('chkRoundVotes').checked = true; @@ -400,7 +385,6 @@ function changePreset() { document.getElementById('selNumbers').value = 'fixed'; document.getElementById('txtDP').value = '5'; document.getElementById('txtPPDP').value = '2'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '2'; document.getElementById('chkRoundVotes').checked = true; @@ -427,7 +411,6 @@ function changePreset() { document.getElementById('selNumbers').value = 'fixed'; document.getElementById('txtDP').value = '5'; document.getElementById('txtPPDP').value = '2'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '2'; document.getElementById('chkRoundVotes').checked = true; @@ -454,7 +437,6 @@ function changePreset() { document.getElementById('selNumbers').value = 'fixed'; document.getElementById('txtDP').value = '5'; document.getElementById('txtPPDP').value = '2'; - document.getElementById('chkNormaliseBallots').checked = false; document.getElementById('chkRoundQuota').checked = true; document.getElementById('txtRoundQuota').value = '2'; document.getElementById('chkRoundVotes').checked = true; diff --git a/src/cli/stv.rs b/src/cli/stv.rs index fef4708..6edbe5d 100644 --- a/src/cli/stv.rs +++ b/src/cli/stv.rs @@ -56,10 +56,6 @@ pub struct SubcmdOptions { #[clap(help_heading=Some("NUMBERS"), long, default_value="5", value_name="dps")] decimals: usize, - /// Convert ballots with value >1 to multiple ballots of value 1 - #[clap(help_heading=Some("NUMBERS"), long)] - normalise_ballots: bool, - // ----------------------- // -- Rounding settings -- @@ -294,7 +290,6 @@ where cmd_opts.round_quota, cmd_opts.round_subtransfers.into(), cmd_opts.meek_surplus_tolerance, - cmd_opts.normalise_ballots, cmd_opts.quota.into(), cmd_opts.quota_criterion.into(), cmd_opts.quota_mode.into(), diff --git a/src/stv/mod.rs b/src/stv/mod.rs index 3058734..57b32e5 100644 --- a/src/stv/mod.rs +++ b/src/stv/mod.rs @@ -71,10 +71,6 @@ pub struct STVOptions { #[builder(default=r#"String::from("0.001%")"#)] pub meek_surplus_tolerance: String, - /// Convert ballots with value >1 to multiple ballots of value 1 (used only for [STVOptions::describe]) - #[builder(default="false")] - pub normalise_ballots: bool, - /// Quota type #[builder(default="QuotaType::Droop")] pub quota: QuotaType, @@ -181,7 +177,6 @@ impl STVOptions { if let Some(dps) = self.round_quota { flags.push(format!("--round-quota {}", dps)); } if self.surplus != SurplusMethod::Meek && self.round_subtransfers != RoundSubtransfersMode::SingleStep { flags.push(self.round_subtransfers.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::Droop { flags.push(self.quota.describe()); } if self.quota_criterion != QuotaCriterion::Greater { flags.push(self.quota_criterion.describe()); } if self.quota_mode != QuotaMode::Static { flags.push(self.quota_mode.describe()); } @@ -224,7 +219,6 @@ impl STVOptions { } 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 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")); } @@ -623,8 +617,8 @@ impl fmt::Display for STVError { /// Preprocess the given election pub fn preprocess_election(election: &mut Election, opts: &STVOptions) { - // Normalise ballots if requested - if opts.normalise_ballots { + // Normalise ballots if required + if opts.surplus == SurplusMethod::IHare || opts.surplus == SurplusMethod::Hare { election.normalise_ballots(); } diff --git a/src/stv/wasm.rs b/src/stv/wasm.rs index 4488e4c..04f8e76 100644 --- a/src/stv/wasm.rs +++ b/src/stv/wasm.rs @@ -246,7 +246,6 @@ impl STVOptions { round_quota: Option, round_subtransfers: &str, meek_surplus_tolerance: String, - normalise_ballots: bool, quota: &str, quota_criterion: &str, quota_mode: &str, @@ -275,7 +274,6 @@ impl STVOptions { round_quota, round_subtransfers.into(), meek_surplus_tolerance, - normalise_ballots, quota.into(), quota_criterion.into(), quota_mode.into(), diff --git a/tests/tests_impl/cambridge.rs b/tests/tests_impl/cambridge.rs index 2f6fd9a..9a0131b 100644 --- a/tests/tests_impl/cambridge.rs +++ b/tests/tests_impl/cambridge.rs @@ -24,7 +24,6 @@ use opentally::stv; fn cambridge_cc03_rational() { let stv_opts = stv::STVOptionsBuilder::default() .round_quota(Some(0)) - .normalise_ballots(true) .quota_criterion(stv::QuotaCriterion::GreaterOrEqual) .surplus(stv::SurplusMethod::Hare) .transferable_only(true) @@ -34,7 +33,7 @@ fn cambridge_cc03_rational() { .min_threshold("49".to_string()) .build().unwrap(); - assert_eq!(stv_opts.describe::(), "--round-quota 0 --normalise-ballots --quota-criterion geq --surplus hare --transferable-only --sample cincinnati --sample-per-ballot --no-early-bulk-elect --min-threshold 49"); + assert_eq!(stv_opts.describe::(), "--round-quota 0 --quota-criterion geq --surplus hare --transferable-only --sample cincinnati --sample-per-ballot --no-early-bulk-elect --min-threshold 49"); utils::read_validate_election::("tests/data/CambCC2003.csv", "tests/data/CambCC2003.blt", stv_opts, None, &["exhausted"]); } diff --git a/tests/tests_impl/dail.rs b/tests/tests_impl/dail.rs index 901d3e2..41fbb41 100644 --- a/tests/tests_impl/dail.rs +++ b/tests/tests_impl/dail.rs @@ -25,7 +25,6 @@ use opentally::ties::TieStrategy; fn dublin_north_2002_rational() { let stv_opts = stv::STVOptionsBuilder::default() .round_quota(Some(0)) - .normalise_ballots(true) .quota_criterion(stv::QuotaCriterion::GreaterOrEqual) .surplus(stv::SurplusMethod::Hare) .surplus_order(stv::SurplusOrder::ByOrder) @@ -33,7 +32,7 @@ fn dublin_north_2002_rational() { .defer_surpluses(true) .build().unwrap(); - assert_eq!(stv_opts.describe::(), "--round-quota 0 --normalise-ballots --quota-criterion geq --surplus hare --surplus-order by_order --transferable-only --defer-surpluses"); + assert_eq!(stv_opts.describe::(), "--round-quota 0 --quota-criterion geq --surplus hare --surplus-order by_order --transferable-only --defer-surpluses"); utils::read_validate_election::("tests/data/DublinNorthSorted.csv", "tests/data/DublinNorthSorted.blt", stv_opts, None, &["exhausted"]); } @@ -42,7 +41,6 @@ fn dublin_north_2002_rational() { fn grey_fitzgerald_rational() { let stv_opts = stv::STVOptionsBuilder::default() .round_quota(Some(0)) - .normalise_ballots(true) .quota_criterion(stv::QuotaCriterion::GreaterOrEqual) .ties(vec![TieStrategy::Forwards]) .surplus(stv::SurplusMethod::Hare) @@ -52,7 +50,7 @@ fn grey_fitzgerald_rational() { .defer_surpluses(true) .build().unwrap(); - assert_eq!(stv_opts.describe::(), "--round-quota 0 --normalise-ballots --quota-criterion geq --ties forwards --surplus hare --transferable-only --bulk-exclude --defer-surpluses"); + assert_eq!(stv_opts.describe::(), "--round-quota 0 --quota-criterion geq --ties forwards --surplus hare --transferable-only --bulk-exclude --defer-surpluses"); utils::read_validate_election::("tests/data/grey_fitzgerald.csv", "tests/data/grey_fitzgerald.blt", stv_opts, None, &["exhausted"]); }