Reduce unnecessary verbosity when only 1 vacancy

This commit is contained in:
RunasSudo 2023-02-01 18:06:22 +11:00
parent ab0ec44049
commit cece60dd69
No known key found for this signature in database
GPG Key ID: 7234E476BF21C61A
4 changed files with 67 additions and 22 deletions

View File

@ -1,5 +1,5 @@
/* OpenTally: Open-source election vote counting /* OpenTally: Open-source election vote counting
* Copyright © 20212022 Lee Yingtong Li (RunasSudo) * Copyright © 20212023 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
@ -326,7 +326,11 @@ impl<'a, N: Number> CountState<'a, N> {
total_vote += &self.loss_fraction.votes; total_vote += &self.loss_fraction.votes;
result.push_str(&format!("Total votes: {:.dps$}\n", total_vote, dps=opts.pp_decimals)); result.push_str(&format!("Total votes: {:.dps$}\n", total_vote, dps=opts.pp_decimals));
result.push_str(&format!("Quota: {:.dps$}\n", self.quota.as_ref().unwrap(), dps=opts.pp_decimals)); if self.election.seats == 1 {
result.push_str(&format!("Majority: {:.dps$}\n", self.quota.as_ref().unwrap(), dps=opts.pp_decimals));
} else {
result.push_str(&format!("Quota: {:.dps$}\n", self.quota.as_ref().unwrap(), dps=opts.pp_decimals));
}
if stv::should_show_vre(opts) { if stv::should_show_vre(opts) {
if let Some(vre) = &self.vote_required_election { if let Some(vre) = &self.vote_required_election {
result.push_str(&format!("Vote required for election: {:.dps$}\n", vre, dps=opts.pp_decimals)); result.push_str(&format!("Vote required for election: {:.dps$}\n", vre, dps=opts.pp_decimals));

View File

@ -1,5 +1,5 @@
/* OpenTally: Open-source election vote counting /* OpenTally: Open-source election vote counting
* Copyright © 20212022 Lee Yingtong Li (RunasSudo) * Copyright © 20212023 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
@ -645,13 +645,18 @@ where
} }
if let ExclusionMethod::SingleStage = opts.exclusion { if let ExclusionMethod::SingleStage = opts.exclusion {
if total_ballots == N::one() { if state.election.seats == 1 {
// Ballots can never have nonzero value with a single winner
state.logger.log_literal(format!("Transferring {:.dps$} votes.", total_votes, dps=opts.pp_decimals));
} else if total_ballots == N::one() {
state.logger.log_literal(format!("Transferring 1 ballot, totalling {:.dps$} votes.", total_votes, dps=opts.pp_decimals)); state.logger.log_literal(format!("Transferring 1 ballot, totalling {:.dps$} votes.", total_votes, dps=opts.pp_decimals));
} else { } else {
state.logger.log_literal(format!("Transferring {:.0} ballots, totalling {:.dps$} votes.", total_ballots, total_votes, dps=opts.pp_decimals)); state.logger.log_literal(format!("Transferring {:.0} ballots, totalling {:.dps$} votes.", total_ballots, total_votes, dps=opts.pp_decimals));
} }
} else { } else {
if total_ballots.is_zero() { if state.election.seats == 1 {
state.logger.log_literal(format!("Transferring {:.dps$} votes, received at value {:.dps2$}.", total_votes, value.unwrap(), dps=opts.pp_decimals, dps2=max(opts.pp_decimals, 2)));
} else if total_ballots.is_zero() {
state.logger.log_literal(format!("Transferring 0 ballots, totalling {:.dps$} votes.", 0, dps=opts.pp_decimals)); state.logger.log_literal(format!("Transferring 0 ballots, totalling {:.dps$} votes.", 0, dps=opts.pp_decimals));
} else if total_ballots == N::one() { } else if total_ballots == N::one() {
state.logger.log_literal(format!("Transferring 1 ballot, totalling {:.dps$} votes, received at value {:.dps2$}.", total_votes, value.unwrap(), dps=opts.pp_decimals, dps2=max(opts.pp_decimals, 2))); state.logger.log_literal(format!("Transferring 1 ballot, totalling {:.dps$} votes, received at value {:.dps2$}.", total_votes, value.unwrap(), dps=opts.pp_decimals, dps2=max(opts.pp_decimals, 2)));

View File

@ -1,5 +1,5 @@
/* OpenTally: Open-source election vote counting /* OpenTally: Open-source election vote counting
* Copyright © 20212022 Lee Yingtong Li (RunasSudo) * Copyright © 20212023 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
@ -73,12 +73,20 @@ pub fn init_results_table<N: Number>(election: &Election<N>, opts: &stv::STVOpti
if report_style == "votes_transposed" { if report_style == "votes_transposed" {
result.push(String::from(r#"<tr class="info transfers"><td>Loss by fraction</td></tr>"#)); result.push(String::from(r#"<tr class="info transfers"><td>Loss by fraction</td></tr>"#));
result.push(String::from(r#"<tr class="info transfers"><td>Total</td></tr>"#)); result.push(String::from(r#"<tr class="info transfers"><td>Total</td></tr>"#));
result.push(String::from(r#"<tr class="info transfers"><td>Quota</td></tr>"#)); if election.seats == 1 {
result.push(String::from(r#"<tr class="info transfers"><td>Majority</td></tr>"#));
} else {
result.push(String::from(r#"<tr class="info transfers"><td>Quota</td></tr>"#));
}
} else { } else {
result.push(String::from(r#"<tr class="info transfers"><td rowspan="2">Loss by fraction</td></tr>"#)); result.push(String::from(r#"<tr class="info transfers"><td rowspan="2">Loss by fraction</td></tr>"#));
result.push(String::from(r#"<tr class="info votes"></tr>"#)); result.push(String::from(r#"<tr class="info votes"></tr>"#));
result.push(String::from(r#"<tr class="info transfers"><td>Total</td></tr>"#)); result.push(String::from(r#"<tr class="info transfers"><td>Total</td></tr>"#));
result.push(String::from(r#"<tr class="info transfers"><td>Quota</td></tr>"#)); if election.seats == 1 {
result.push(String::from(r#"<tr class="info transfers"><td>Majority</td></tr>"#));
} else {
result.push(String::from(r#"<tr class="info transfers"><td>Quota</td></tr>"#));
}
} }
if stv::should_show_vre(opts) { if stv::should_show_vre(opts) {

View File

@ -1,5 +1,5 @@
/* OpenTally: Open-source election vote counting /* OpenTally: Open-source election vote counting
* Copyright © 20212022 Lee Yingtong Li (RunasSudo) * Copyright © 20212023 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
@ -378,7 +378,11 @@ fn calculate_quota<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
// Calculate the total vote // Calculate the total vote
let total_vote = state.total_vote(); let total_vote = state.total_vote();
log.push_str(format!("{:.dps$} usable votes, so the quota is ", total_vote, dps=opts.pp_decimals).as_str()); if state.election.seats == 1 {
log.push_str(format!("{:.dps$} usable votes, so a majority is ", total_vote, dps=opts.pp_decimals).as_str());
} else {
log.push_str(format!("{:.dps$} usable votes, so the quota is ", total_vote, dps=opts.pp_decimals).as_str());
}
let quota = total_to_quota(total_vote, state.election.seats, opts); let quota = total_to_quota(total_vote, state.election.seats, opts);
@ -393,7 +397,11 @@ fn calculate_quota<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
// Calculate the active vote // Calculate the active vote
let active_vote = state.active_vote(); let active_vote = state.active_vote();
log.push_str(format!("Active vote is {:.dps$}, so the quota is is ", active_vote, dps=opts.pp_decimals).as_str()); if state.election.seats == 1 {
log.push_str(format!("Active vote is {:.dps$}, so a majority is ", active_vote, dps=opts.pp_decimals).as_str());
} else {
log.push_str(format!("Active vote is {:.dps$}, so the quota is ", active_vote, dps=opts.pp_decimals).as_str());
}
// TODO: Calculate according to --quota ? // TODO: Calculate according to --quota ?
let quota = active_vote / N::from(state.election.seats - state.num_elected + 1); let quota = active_vote / N::from(state.election.seats - state.num_elected + 1);
@ -414,7 +422,11 @@ fn calculate_quota<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
// Calculate the total vote // Calculate the total vote
let total_vote = state.total_vote(); let total_vote = state.total_vote();
log.push_str(format!("{:.dps$} usable votes, so the quota is reduced to ", total_vote, dps=opts.pp_decimals).as_str()); if state.election.seats == 1 {
log.push_str(format!("{:.dps$} usable votes, so a majority is ", total_vote, dps=opts.pp_decimals).as_str());
} else {
log.push_str(format!("{:.dps$} usable votes, so the quota is reduced to ", total_vote, dps=opts.pp_decimals).as_str());
}
let quota = total_to_quota(total_vote, state.election.seats, opts); let quota = total_to_quota(total_vote, state.election.seats, opts);
@ -612,11 +624,19 @@ fn elect_hopefuls<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOption
if cmp_quota_criterion(state.quota.as_ref().unwrap(), count_card, opts) { if cmp_quota_criterion(state.quota.as_ref().unwrap(), count_card, opts) {
// Elected with a quota // Elected with a quota
elected_on_quota = true; elected_on_quota = true;
state.logger.log_smart( if state.election.seats == 1 {
"{} meets the quota and is elected.", state.logger.log_smart(
"{} meet the quota and are elected.", "{} reaches a majority and is elected.",
vec![candidate.name.as_str()] "{} reach a majority and are elected.", // This one is impossible
); vec![candidate.name.as_str()]
);
} else {
state.logger.log_smart(
"{} meets the quota and is elected.",
"{} meet the quota and are elected.",
vec![candidate.name.as_str()]
);
}
} else { } else {
// Elected with vote required // Elected with vote required
elected_on_quota = false; elected_on_quota = false;
@ -966,11 +986,19 @@ where
let names: Vec<&str> = excluded_candidates.iter().map(|c| c.name.as_str()).sorted().collect(); let names: Vec<&str> = excluded_candidates.iter().map(|c| c.name.as_str()).sorted().collect();
state.title = StageKind::ExclusionOf(excluded_candidates.clone()); state.title = StageKind::ExclusionOf(excluded_candidates.clone());
state.logger.log_smart( if state.election.seats == 1 {
"No surpluses to distribute, so {} is excluded.", state.logger.log_smart(
"No surpluses to distribute, so {} are excluded.", "No candidate has a majority, so {} is excluded.",
names "No candidate has a majority, so {} are excluded.",
); names
);
} else {
state.logger.log_smart(
"No surpluses to distribute, so {} is excluded.",
"No surpluses to distribute, so {} are excluded.",
names
);
}
if opts.early_bulk_elect { if opts.early_bulk_elect {
// Determine if the proposed exclusion would enable a bulk election // Determine if the proposed exclusion would enable a bulk election