From e059a6a3d931fee0e393d290fd0fce0e808bc65c Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Sat, 12 Jun 2021 16:03:31 +1000 Subject: [PATCH] Fixes to count description --- html/index.js | 1 + src/main.rs | 12 ++++++++++++ src/numbers/mod.rs | 1 + src/numbers/rational_num.rs | 1 + src/numbers/rational_rug.rs | 1 + src/stv/mod.rs | 23 ++++++++++++++++++++--- src/stv/wasm.rs | 10 +++++++++- 7 files changed, 45 insertions(+), 4 deletions(-) diff --git a/html/index.js b/html/index.js index bdb2549..604e944 100644 --- a/html/index.js +++ b/html/index.js @@ -103,6 +103,7 @@ async function clickCount() { document.getElementById('chkRoundVotes').checked ? parseInt(document.getElementById('txtRoundVotes').value) : null, document.getElementById('chkRoundQuota').checked ? parseInt(document.getElementById('txtRoundQuota').value) : null, document.getElementById('selSumTransfers').value, + document.getElementById('chkNormaliseBallots').checked, document.getElementById('selQuota').value, document.getElementById('selQuotaCriterion').value, document.getElementById('selQuotaMode').value, diff --git a/src/main.rs b/src/main.rs index 90a1048..c70dbf6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -181,6 +181,7 @@ where cmd_opts.round_votes, cmd_opts.round_quota, &cmd_opts.sum_surplus_transfers, + cmd_opts.normalise_ballots, &cmd_opts.quota, &cmd_opts.quota_criterion, &cmd_opts.quota_mode, @@ -193,6 +194,17 @@ where cmd_opts.pp_decimals, ); + // Describe count + let total_ballots = election.ballots.iter().fold(N::zero(), |acc, b| { acc + &b.orig_value }); + print!("Count computed by OpenTally (revision {}). Read {:.0} ballots from \"{}\" for election \"{}\". There are {} candidates for {} vacancies. ", opentally::VERSION, total_ballots, cmd_opts.filename, election.name, election.candidates.len(), election.seats); + let opts_str = stv_opts.describe::(); + if opts_str.len() > 0 { + println!("Counting using options \"{}\".", opts_str); + } else { + println!("Counting using default options."); + } + println!(); + // Normalise ballots if requested if cmd_opts.normalise_ballots { election.normalise_ballots(); diff --git a/src/numbers/mod.rs b/src/numbers/mod.rs index 2842809..ba87026 100644 --- a/src/numbers/mod.rs +++ b/src/numbers/mod.rs @@ -47,6 +47,7 @@ where fn new() -> Self; fn describe() -> String; + fn describe_opt() -> String { Self::describe() } fn pow_assign(&mut self, exponent: i32); fn floor_mut(&mut self, dps: usize); diff --git a/src/numbers/rational_num.rs b/src/numbers/rational_num.rs index a7b4e5d..95e4638 100644 --- a/src/numbers/rational_num.rs +++ b/src/numbers/rational_num.rs @@ -33,6 +33,7 @@ impl Number for Rational { fn new() -> Self { Self(RatioType::zero()) } fn describe() -> String { "--numbers rational".to_string() } + fn describe_opt() -> String { String::new() } fn pow_assign(&mut self, exponent: i32) { self.0 = self.0.pow(exponent); diff --git a/src/numbers/rational_rug.rs b/src/numbers/rational_rug.rs index 9cfa977..d59570c 100644 --- a/src/numbers/rational_rug.rs +++ b/src/numbers/rational_rug.rs @@ -32,6 +32,7 @@ impl Number for Rational { fn new() -> Self { Self(rug::Rational::new()) } fn describe() -> String { "--numbers rational".to_string() } + fn describe_opt() -> String { String::new() } fn pow_assign(&mut self, exponent: i32) { self.0.pow_assign(exponent); diff --git a/src/stv/mod.rs b/src/stv/mod.rs index 668669b..4a0a270 100644 --- a/src/stv/mod.rs +++ b/src/stv/mod.rs @@ -38,6 +38,7 @@ pub struct STVOptions { pub round_votes: Option, pub round_quota: Option, pub sum_surplus_transfers: SumSurplusTransfersMode, + pub normalise_ballots: bool, pub quota: QuotaType, pub quota_criterion: QuotaCriterion, pub quota_mode: QuotaMode, @@ -57,7 +58,8 @@ impl STVOptions { round_weights: Option, round_votes: Option, round_quota: Option, - sum_transfers: &str, + sum_surplus_transfers: &str, + normalise_ballots: bool, quota: &str, quota_criterion: &str, quota_mode: &str, @@ -74,12 +76,13 @@ impl STVOptions { round_weights, round_votes, round_quota, - sum_surplus_transfers: match sum_transfers { + sum_surplus_transfers: match sum_surplus_transfers { "single_step" => SumSurplusTransfersMode::SingleStep, "by_value" => SumSurplusTransfersMode::ByValue, "per_ballot" => SumSurplusTransfersMode::PerBallot, _ => panic!("Invalid --sum-transfers"), }, + normalise_ballots, quota: match quota { "droop" => QuotaType::Droop, "hare" => QuotaType::Hare, @@ -127,11 +130,13 @@ impl STVOptions { // Not exported to WebAssembly pub fn describe(&self) -> String { let mut flags = Vec::new(); - flags.push(N::describe()); + let n_str = N::describe_opt(); if n_str.len() > 0 { flags.push(N::describe_opt()) }; if let Some(dps) = self.round_tvs { flags.push(format!("--round-tvs {}", dps)); } if let Some(dps) = self.round_weights { flags.push(format!("--round-weights {}", dps)); } if let Some(dps) = self.round_votes { flags.push(format!("--round-votes {}", dps)); } if let Some(dps) = self.round_quota { flags.push(format!("--round-quota {}", dps)); } + if self.sum_surplus_transfers != SumSurplusTransfersMode::SingleStep { flags.push(self.sum_surplus_transfers.describe()); } + if self.normalise_ballots { flags.push("--normalise-ballots".to_string()); } if self.quota != QuotaType::DroopExact { 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()); } @@ -139,6 +144,8 @@ impl STVOptions { if self.surplus_order != SurplusOrder::BySize { flags.push(self.surplus_order.describe()); } if self.transferable_only { flags.push("--transferable-only".to_string()); } if self.exclusion != ExclusionMethod::SingleStage { flags.push(self.exclusion.describe()); } + if self.bulk_exclude { flags.push("--bulk-exclude".to_string()); } + if self.defer_surpluses { flags.push("--defer-surpluses".to_string()); } if self.pp_decimals != 2 { flags.push(format!("--pp-decimals {}", self.pp_decimals)); } return flags.join(" "); } @@ -153,6 +160,16 @@ pub enum SumSurplusTransfersMode { PerBallot, } +impl SumSurplusTransfersMode { + fn describe(self) -> String { + match self { + SumSurplusTransfersMode::SingleStep => "--sum-surplus-transfers single_step", + SumSurplusTransfersMode::ByValue => "--sum-surplus-transfers by_value", + SumSurplusTransfersMode::PerBallot => "--sum-surplus-transfers per_ballot", + }.to_string() + } +} + #[wasm_bindgen] #[derive(Clone, Copy)] #[derive(PartialEq)] diff --git a/src/stv/wasm.rs b/src/stv/wasm.rs index d9213db..3c2aa80 100644 --- a/src/stv/wasm.rs +++ b/src/stv/wasm.rs @@ -157,7 +157,15 @@ fn describe_count(filename: String, election: &Election, opts: &st let mut result = String::from("

Count computed by OpenTally (revision "); result.push_str(crate::VERSION); let total_ballots = election.ballots.iter().fold(N::zero(), |acc, b| { acc + &b.orig_value }); - result.push_str(&format!(r#"). Read {:.0} ballots from ‘{}’ for election ‘{}’. There are {} candidates for {} vacancies. Counting using options {}.

"#, total_ballots, filename, election.name, election.candidates.len(), election.seats, opts.describe::())); + result.push_str(&format!(r#"). Read {:.0} ballots from ‘{}’ for election ‘{}’. There are {} candidates for {} vacancies. "#, total_ballots, filename, election.name, election.candidates.len(), election.seats)); + + let opts_str = opts.describe::(); + if opts_str.len() > 0 { + result.push_str(&format!(r#"Counting using options {}.

"#, opts_str)) + } else { + result.push_str(r#"Counting using default options.

"#); + } + return result; }