Avoid excess allocations during fold operations

This commit is contained in:
RunasSudo 2022-08-18 23:55:39 +10:00
parent ee7ac064c7
commit 35104055d9
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
6 changed files with 30 additions and 21 deletions

View File

@ -450,7 +450,7 @@ impl<'a, N: Number> CountCard<'a, N> {
/// Return the number of ballots across all parcels /// Return the number of ballots across all parcels
pub fn num_ballots(&self) -> N { pub fn num_ballots(&self) -> N {
return self.parcels.iter().fold(N::new(), |acc, p| acc + p.num_ballots()); return self.parcels.iter().fold(N::new(), |mut acc, p| { acc += p.num_ballots(); acc });
} }
} }
@ -468,7 +468,7 @@ pub struct Parcel<'a, N> {
impl<'a, N: Number> Parcel<'a, N> { impl<'a, N: Number> Parcel<'a, N> {
/// Return the number of ballots in this parcel /// Return the number of ballots in this parcel
pub fn num_ballots(&self) -> N { pub fn num_ballots(&self) -> N {
return self.votes.iter().fold(N::new(), |acc, v| acc + &v.ballot.orig_value); return self.votes.iter().fold(N::new(), |mut acc, v| { acc += &v.ballot.orig_value; acc });
} }
/// Return the value of the votes in this parcel /// Return the value of the votes in this parcel

View File

@ -82,7 +82,7 @@ where
// Calculate loss by fraction - if minivoters used // Calculate loss by fraction - if minivoters used
if let Some(orig_total) = &state.election.total_votes { if let Some(orig_total) = &state.election.total_votes {
let mut total_votes = state.candidates.values().fold(N::new(), |acc, cc| acc + &cc.votes); let mut total_votes = state.candidates.values().fold(N::new(), |mut acc, cc| { acc += &cc.votes; acc });
total_votes += &state.exhausted.votes; total_votes += &state.exhausted.votes;
let lbf = orig_total - &total_votes; let lbf = orig_total - &total_votes;
@ -115,7 +115,7 @@ where
if !has_surplus.is_empty() { if !has_surplus.is_empty() {
let total_surpluses = has_surplus.iter() let total_surpluses = has_surplus.iter()
.fold(N::new(), |acc, c| acc + &state.candidates[c].votes - quota); .fold(N::new(), |mut acc, c| { acc += &state.candidates[c].votes; acc -= quota; acc });
// Determine if surplues can be deferred // Determine if surplues can be deferred
if opts.defer_surpluses { if opts.defer_surpluses {

View File

@ -254,11 +254,16 @@ impl<'e, N: Number> TransferTable<'e, N> {
// Sum total votes_out per candidate // Sum total votes_out per candidate
for (candidate, cell) in self.total.cells.iter_mut() { for (candidate, cell) in self.total.cells.iter_mut() {
cell.votes_out = self.columns.iter().fold(N::new(), |acc, col| if let Some(cell) = col.cells.get(candidate) { acc + &cell.votes_out } else { acc }); cell.votes_out = self.columns.iter().fold(N::new(), |mut acc, col| {
if let Some(cell) = col.cells.get(candidate) {
acc += &cell.votes_out
}
acc
});
} }
// Sum total exhausted votes // Sum total exhausted votes
self.total.exhausted.votes_out = self.columns.iter().fold(N::new(), |acc, col| acc + &col.exhausted.votes_out); self.total.exhausted.votes_out = self.columns.iter().fold(N::new(), |mut acc, col| { acc += &col.exhausted.votes_out; acc });
} }
RoundSubtransfersMode::PerBallot => { RoundSubtransfersMode::PerBallot => {
// Calculate votes_out for each column // Calculate votes_out for each column
@ -316,11 +321,16 @@ impl<'e, N: Number> TransferTable<'e, N> {
// Sum total votes_out per candidate // Sum total votes_out per candidate
for (candidate, cell) in self.total.cells.iter_mut() { for (candidate, cell) in self.total.cells.iter_mut() {
cell.votes_out = self.columns.iter().fold(N::new(), |acc, col| if let Some(cell) = col.cells.get(candidate) { acc + &cell.votes_out } else { acc }); cell.votes_out = self.columns.iter().fold(N::new(), |mut acc, col| {
if let Some(cell) = col.cells.get(candidate) {
acc += &cell.votes_out;
}
acc
});
} }
// Sum total exhausted votes // Sum total exhausted votes
self.total.exhausted.votes_out = self.columns.iter().fold(N::new(), |acc, col| acc + &col.exhausted.votes_out); self.total.exhausted.votes_out = self.columns.iter().fold(N::new(), |mut acc, col| { acc += &col.exhausted.votes_out; acc });
} }
} }
} }

View File

@ -130,7 +130,7 @@ where
// Calculate loss by fraction - if minivoters used // Calculate loss by fraction - if minivoters used
if let Some(orig_total) = &state.election.total_votes { if let Some(orig_total) = &state.election.total_votes {
let mut total_votes = state.candidates.values().fold(N::new(), |acc, cc| acc + &cc.votes); let mut total_votes = state.candidates.values().fold(N::new(), |mut acc, cc| { acc += &cc.votes; acc });
total_votes += &state.exhausted.votes; total_votes += &state.exhausted.votes;
let lbf = orig_total - &total_votes; let lbf = orig_total - &total_votes;
@ -241,7 +241,7 @@ where
// Distribute if the total surplus exceeds the tolerance // Distribute if the total surplus exceeds the tolerance
let quota_tolerance = N::parse(&opts.meek_surplus_tolerance); let quota_tolerance = N::parse(&opts.meek_surplus_tolerance);
let total_surpluses = has_surplus.iter() let total_surpluses = has_surplus.iter()
.fold(N::new(), |acc, c| acc + &state.candidates[c].votes - state.quota.as_ref().unwrap()); .fold(N::new(), |mut acc, c| { acc += &state.candidates[c].votes; acc -= state.quota.as_ref().unwrap(); acc });
return total_surpluses > quota_tolerance; return total_surpluses > quota_tolerance;
} }
} }
@ -266,7 +266,7 @@ where
// Determine if surplues can be deferred // Determine if surplues can be deferred
if opts.defer_surpluses { if opts.defer_surpluses {
let total_surpluses = has_surplus.iter() let total_surpluses = has_surplus.iter()
.fold(N::new(), |acc, c| acc + &state.candidates[c].votes - quota); .fold(N::new(), |mut acc, c| { acc += &state.candidates[c].votes; acc -= quota; acc });
if super::can_defer_surpluses(state, opts, &total_surpluses) { if super::can_defer_surpluses(state, opts, &total_surpluses) {
state.logger.log_literal(format!("Distribution of surpluses totalling {:.dps$} votes will be deferred.", total_surpluses, dps=opts.pp_decimals)); state.logger.log_literal(format!("Distribution of surpluses totalling {:.dps$} votes will be deferred.", total_surpluses, dps=opts.pp_decimals));
return Ok(false); return Ok(false);
@ -314,7 +314,7 @@ where
// Determine if surplues can be deferred // Determine if surplues can be deferred
if should_distribute && opts.defer_surpluses { if should_distribute && opts.defer_surpluses {
let total_surpluses = has_surplus.iter() let total_surpluses = has_surplus.iter()
.fold(N::new(), |acc, c| acc + &state.candidates[c].votes - quota); .fold(N::new(), |mut acc, c| { acc += &state.candidates[c].votes; acc -= quota; acc });
if super::can_defer_surpluses(state, opts, &total_surpluses) { if super::can_defer_surpluses(state, opts, &total_surpluses) {
surpluses_deferred = Some(total_surpluses); surpluses_deferred = Some(total_surpluses);
break; break;

View File

@ -1093,15 +1093,14 @@ fn elect_sure_winners<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOp
let mut total_trailing = N::new(); let mut total_trailing = N::new();
// For leading candidates, count only untransferred surpluses // For leading candidates, count only untransferred surpluses
total_trailing += hopefuls.iter().take(num_vacancies).fold(N::new(), |acc, (_, cc)| { total_trailing += hopefuls.iter().take(num_vacancies).fold(N::new(), |mut acc, (_, cc)| {
if &cc.votes > state.quota.as_ref().unwrap() { if &cc.votes > state.quota.as_ref().unwrap() {
acc + &cc.votes - state.quota.as_ref().unwrap() acc += &cc.votes; acc -= state.quota.as_ref().unwrap();
} else {
acc
} }
acc
}); });
// For trailing candidates, count all votes // For trailing candidates, count all votes
total_trailing += hopefuls.iter().skip(num_vacancies).fold(N::new(), |acc, (_, cc)| acc + &cc.votes); total_trailing += hopefuls.iter().skip(num_vacancies).fold(N::new(), |mut acc, (_, cc)| { acc += &cc.votes; acc });
// Add finally any votes awaiting transfer // Add finally any votes awaiting transfer
total_trailing += state.candidates.values().fold(N::zero(), |acc, cc| { total_trailing += state.candidates.values().fold(N::zero(), |acc, cc| {
match cc.state { match cc.state {
@ -1298,7 +1297,7 @@ where
let num_to_exclude = to_exclude.len(); let num_to_exclude = to_exclude.len();
if num_to_exclude > 0 { if num_to_exclude > 0 {
let total_excluded = to_exclude.into_iter() let total_excluded = to_exclude.into_iter()
.fold(N::new(), |acc, c| acc + &state.candidates[c].votes); .fold(N::new(), |mut acc, c| { acc += &state.candidates[c].votes; acc });
if total_surpluses >= &(&hopefuls[num_to_exclude].1.votes - &total_excluded) { if total_surpluses >= &(&hopefuls[num_to_exclude].1.votes - &total_excluded) {
return false; return false;
} }
@ -1497,7 +1496,7 @@ fn hopefuls_to_bulk_exclude<'a, N: Number>(state: &CountState<'a, N>, _opts: &ST
let total_surpluses = state.candidates.iter() let total_surpluses = state.candidates.iter()
.filter(|(_, cc)| !cc.finalised && &cc.votes > state.quota.as_ref().unwrap()) .filter(|(_, cc)| !cc.finalised && &cc.votes > state.quota.as_ref().unwrap())
.fold(N::new(), |agg, (_, cc)| agg + &cc.votes - state.quota.as_ref().unwrap()); .fold(N::new(), |mut acc, (_, cc)| { acc += &cc.votes; acc -= state.quota.as_ref().unwrap(); acc });
// Attempt to exclude as many candidates as possible // Attempt to exclude as many candidates as possible
for i in 0..hopefuls.len() { for i in 0..hopefuls.len() {
@ -1509,7 +1508,7 @@ fn hopefuls_to_bulk_exclude<'a, N: Number>(state: &CountState<'a, N>, _opts: &ST
} }
// Do not exclude if this could change the order of exclusion // Do not exclude if this could change the order of exclusion
let total_votes = try_exclude.iter().fold(N::new(), |agg, (_, cc)| agg + &cc.votes); let total_votes = try_exclude.iter().fold(N::new(), |mut acc, (_, cc)| { acc += &cc.votes; acc });
if i != 0 && total_votes + &total_surpluses >= hopefuls[hopefuls.len()-i].1.votes { if i != 0 && total_votes + &total_surpluses >= hopefuls[hopefuls.len()-i].1.votes {
continue; continue;
} }

View File

@ -186,7 +186,7 @@ where
if opts.sample == SampleMethod::StratifyLR { if opts.sample == SampleMethod::StratifyLR {
// Round remainders to remove loss by fraction // Round remainders to remove loss by fraction
let transferred = candidate_transfers_remainders.values().fold(N::new(), |acc, (t, _)| acc + t); let transferred = candidate_transfers_remainders.values().fold(N::new(), |mut acc, (t, _)| { acc += t; acc });
let loss_fraction = &surplus - &transferred; let loss_fraction = &surplus - &transferred;
if !loss_fraction.is_zero() && surplus_fraction.is_some() { if !loss_fraction.is_zero() && surplus_fraction.is_some() {
let n_to_round: usize = format!("{:.0}", loss_fraction).parse().expect("Loss by fraction overflows usize"); let n_to_round: usize = format!("{:.0}", loss_fraction).parse().expect("Loss by fraction overflows usize");