From c9b189fefedbcbfb93bb0f59e4a8c390563c8521 Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Fri, 10 Sep 2021 01:42:42 +1000 Subject: [PATCH] Update quota/VRE in certain rare cases --- src/stv/mod.rs | 89 +++++++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/src/stv/mod.rs b/src/stv/mod.rs index bc16897..ba958ca 100644 --- a/src/stv/mod.rs +++ b/src/stv/mod.rs @@ -840,6 +840,44 @@ fn update_vre_ers(state: &mut CountState, opts: &STVOptions) { } } +/// Update vote required for election if only one candidate remains, used in early bulk election +/// +/// Assumes early bulk election is enabled. +fn update_vre_bulk(state: &mut CountState, _opts: &STVOptions) { + // If --early-bulk-elect and one candidate remains, VRE is half of the active vote + // For display purposes only + + if state.election.seats - state.num_elected == 1 { + //let mut log = String::new(); + + // Calculate active vote + let active_vote = state.candidates.values().fold(N::zero(), |acc, cc| { + match cc.state { + CandidateState::Elected => { if !cc.finalised && &cc.votes > state.quota.as_ref().unwrap() { acc + &cc.votes - state.quota.as_ref().unwrap() } else { acc } } + _ => { acc + &cc.votes } + } + }); + //log.push_str(format!("Active vote is {:.dps$}, so the vote required for election is ", active_vote, dps=opts.pp_decimals).as_str()); + + let vote_req = active_vote / N::from(state.election.seats - state.num_elected + 1); + + if &vote_req < state.quota.as_ref().unwrap() { + // VRE is less than the quota + //if let Some(v) = &state.vote_required_election { + // if &vote_req != v { + //log.push_str(format!("{:.dps$}.", vote_req, dps=opts.pp_decimals).as_str()); + state.vote_required_election = Some(vote_req); + //state.logger.log_literal(log); + // } + //} else { + //log.push_str(format!("{:.dps$}.", vote_req, dps=opts.pp_decimals).as_str()); + // state.vote_required_election = Some(vote_req); + //state.logger.log_literal(log); + //} + } + } +} + /// Calculate the quota according to [STVOptions::quota] fn calculate_quota(state: &mut CountState, opts: &STVOptions) { if state.quota.is_none() || opts.quota_mode == QuotaMode::DynamicByTotal { @@ -910,36 +948,8 @@ fn calculate_quota(state: &mut CountState, opts: &STVOptions) { } else { // No ERS97/ERS76 rules - // If --early-bulk-elect and one candidate remains, VRE is half of the active vote - // For display purposes only - if opts.early_bulk_elect && (state.election.seats - state.num_elected) == 1 { - //let mut log = String::new(); - - // Calculate active vote - let active_vote = state.candidates.values().fold(N::zero(), |acc, cc| { - match cc.state { - CandidateState::Elected => { if !cc.finalised && &cc.votes > state.quota.as_ref().unwrap() { acc + &cc.votes - state.quota.as_ref().unwrap() } else { acc } } - _ => { acc + &cc.votes } - } - }); - //log.push_str(format!("Active vote is {:.dps$}, so the vote required for election is ", active_vote, dps=opts.pp_decimals).as_str()); - - let vote_req = active_vote / N::from(state.election.seats - state.num_elected + 1); - - if &vote_req < state.quota.as_ref().unwrap() { - // VRE is less than the quota - //if let Some(v) = &state.vote_required_election { - // if &vote_req != v { - //log.push_str(format!("{:.dps$}.", vote_req, dps=opts.pp_decimals).as_str()); - state.vote_required_election = Some(vote_req); - //state.logger.log_literal(log); - // } - //} else { - //log.push_str(format!("{:.dps$}.", vote_req, dps=opts.pp_decimals).as_str()); - // state.vote_required_election = Some(vote_req); - //state.logger.log_literal(log); - //} - } + if opts.early_bulk_elect { + update_vre_bulk(state, opts); } } } @@ -1119,17 +1129,22 @@ fn elect_hopefuls<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOption cands_meeting_quota.remove(cands_meeting_quota.iter().position(|c| *c == candidate).unwrap()); } - if opts.quota_mode == QuotaMode::ERS97 || (opts.quota_mode == QuotaMode::ERS76 && elected_on_quota) { + if opts.quota_mode == QuotaMode::ERS97 || opts.quota_mode == QuotaMode::ERS76 || opts.quota_mode == QuotaMode::DynamicByActive { // Vote required for election may have changed // ERS97: Check this after every elected candidate (cf. model election) // ERS76: Check this after every candidate elected on a quota, but all at once for candidates elected on VRE (cf. model election) - calculate_quota(state, opts); - - // Repeat in case vote required for election has changed - match elect_hopefuls(state, opts, true) { - Ok(_) => { break; } - Err(e) => { return Err(e); } + if opts.quota_mode == QuotaMode::ERS97 || (opts.quota_mode == QuotaMode::ERS76 && elected_on_quota) || opts.quota_mode == QuotaMode::DynamicByActive { + calculate_quota(state, opts); + + // Repeat in case vote required for election has changed + match elect_hopefuls(state, opts, true) { + Ok(_) => { break; } + Err(e) => { return Err(e); } + } } + } else if opts.early_bulk_elect { + // Vote required for election may have changed for display purposes + update_vre_bulk(state, opts); } }