Report vote required for election in relation to early bulk election
This commit is contained in:
parent
473c8bcb39
commit
de19324d2c
|
@ -801,7 +801,7 @@ fn total_to_quota<N: Number>(mut total: N, seats: usize, opts: &STVOptions) -> N
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update vote required for election according to ERS97/ERS76 rules
|
/// Update vote required for election according to ERS97/ERS76 rules
|
||||||
fn update_vre<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
|
fn update_vre_ers<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
|
||||||
if opts.quota_mode == QuotaMode::ERS76 && state.num_excluded == 0 && (state.num_elected == 0 || state.candidates.values().all(|cc| !cc.finalised)) {
|
if opts.quota_mode == QuotaMode::ERS76 && state.num_excluded == 0 && (state.num_elected == 0 || state.candidates.values().all(|cc| !cc.finalised)) {
|
||||||
// ERS76 rules: Do not update VRE until a surplus is distributed or candidate is excluded
|
// ERS76 rules: Do not update VRE until a surplus is distributed or candidate is excluded
|
||||||
state.vote_required_election = state.quota.clone();
|
state.vote_required_election = state.quota.clone();
|
||||||
|
@ -819,7 +819,6 @@ fn update_vre<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
|
||||||
});
|
});
|
||||||
log.push_str(format!("Active vote is {:.dps$}, so the vote required for election is ", active_vote, dps=opts.pp_decimals).as_str());
|
log.push_str(format!("Active vote is {:.dps$}, so the vote required for election is ", active_vote, dps=opts.pp_decimals).as_str());
|
||||||
|
|
||||||
// TODO: Calculate according to --quota ?
|
|
||||||
let vote_req = active_vote / N::from(state.election.seats - state.num_elected + 1);
|
let vote_req = active_vote / N::from(state.election.seats - state.num_elected + 1);
|
||||||
|
|
||||||
if &vote_req < state.quota.as_ref().unwrap() {
|
if &vote_req < state.quota.as_ref().unwrap() {
|
||||||
|
@ -906,10 +905,42 @@ fn calculate_quota<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
|
||||||
// Calculate vote required for election
|
// Calculate vote required for election
|
||||||
|
|
||||||
if state.num_elected < state.election.seats {
|
if state.num_elected < state.election.seats {
|
||||||
update_vre(state, opts);
|
update_vre_ers(state, opts);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No ERS97/ERS76 rules, so no use of VRE
|
// 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);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -927,10 +958,11 @@ fn cmp_quota_criterion<N: Number>(quota: &N, count_card: &CountCard<N>, opts: &S
|
||||||
|
|
||||||
/// Determine if the given candidate meets the vote required to be elected, according to [STVOptions::quota_criterion] and [STVOptions::quota_mode]
|
/// Determine if the given candidate meets the vote required to be elected, according to [STVOptions::quota_criterion] and [STVOptions::quota_mode]
|
||||||
fn meets_vre<N: Number>(state: &CountState<N>, count_card: &CountCard<N>, opts: &STVOptions) -> bool {
|
fn meets_vre<N: Number>(state: &CountState<N>, count_card: &CountCard<N>, opts: &STVOptions) -> bool {
|
||||||
if let Some(vre) = &state.vote_required_election {
|
if opts.quota_mode == QuotaMode::ERS97 || opts.quota_mode == QuotaMode::ERS76 {
|
||||||
// VRE is set because ERS97/ERS76 rules
|
// VRE is set because ERS97/ERS76 rules
|
||||||
return cmp_quota_criterion(vre, count_card, opts);
|
return cmp_quota_criterion(state.vote_required_election.as_ref().unwrap(), count_card, opts);
|
||||||
} else {
|
} else {
|
||||||
|
// VRE is set (if at all) for display purposes only so ignore it here
|
||||||
return cmp_quota_criterion(state.quota.as_ref().unwrap(), count_card, opts);
|
return cmp_quota_criterion(state.quota.as_ref().unwrap(), count_card, opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -986,7 +1018,15 @@ fn elect_sure_winners<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOp
|
||||||
Err(_) => { return Ok(false); } // Bulk election conflicts with constraints
|
Err(_) => { return Ok(false); } // Bulk election conflicts with constraints
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bulk elect all leading candidates
|
// Bulk election is possible!
|
||||||
|
// Elect all leading candidates
|
||||||
|
|
||||||
|
if num_vacancies > 1 {
|
||||||
|
// Update VRE
|
||||||
|
// (If num_vacancies == 1, this has already been done in calculate_quota)
|
||||||
|
state.vote_required_election = Some(total_trailing);
|
||||||
|
}
|
||||||
|
|
||||||
while !leading_hopefuls.is_empty() && state.num_elected < state.election.seats {
|
while !leading_hopefuls.is_empty() && state.num_elected < state.election.seats {
|
||||||
let max_cands = ties::multiple_max_by(&leading_hopefuls, |c| &state.candidates[c].votes);
|
let max_cands = ties::multiple_max_by(&leading_hopefuls, |c| &state.candidates[c].votes);
|
||||||
let candidate = if max_cands.len() > 1 {
|
let candidate = if max_cands.len() > 1 {
|
||||||
|
|
|
@ -318,8 +318,7 @@ fn describe_count<N: Number>(filename: String, election: &Election<N>, opts: &st
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn should_show_vre(opts: &stv::STVOptions) -> bool {
|
fn should_show_vre(opts: &stv::STVOptions) -> bool {
|
||||||
//return opts.quota_mode == stv::QuotaMode::ERS97 || opts.quota_mode == stv::QuotaMode::ERS76 || opts.early_bulk_elect;
|
return opts.quota_mode == stv::QuotaMode::ERS97 || opts.quota_mode == stv::QuotaMode::ERS76 || opts.early_bulk_elect;
|
||||||
return opts.quota_mode == stv::QuotaMode::ERS97 || opts.quota_mode == stv::QuotaMode::ERS76;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate the first column of the HTML results table
|
/// Generate the first column of the HTML results table
|
||||||
|
|
Loading…
Reference in New Issue