Improve performance of realise_equal_rankings

This commit is contained in:
RunasSudo 2022-08-18 00:15:44 +10:00
parent e825ca1491
commit ee7ac064c7
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A

View File

@ -80,13 +80,18 @@ impl<N: Number> Election<N> {
/// Convert ballots with equal rankings to strict-preference "minivoters" /// Convert ballots with equal rankings to strict-preference "minivoters"
pub fn realise_equal_rankings(&mut self) { pub fn realise_equal_rankings(&mut self) {
// Record total_votes so loss by fraction can be calculated if !self.ballots.iter().any(|b| b.has_equal_rankings()) {
self.total_votes = Some(self.ballots.iter().fold(N::new(), |acc, b| acc + &b.orig_value)); // No equal rankings
return;
}
let mut realised_ballots = Vec::new(); // Record total_votes so loss by fraction can be calculated
for ballot in self.ballots.iter() { // See crate::stv::gregory::distribute_first_preferences, etc.
let mut b = ballot.realise_equal_rankings(); self.total_votes = Some(self.ballots.iter().fold(N::new(), |mut acc, b| { acc += &b.orig_value; acc }));
realised_ballots.append(&mut b);
let mut realised_ballots = Vec::with_capacity(self.ballots.len());
for ballot in self.ballots.drain(..) {
ballot.realise_equal_rankings_into(&mut realised_ballots);
} }
self.ballots = realised_ballots; self.ballots = realised_ballots;
} }
@ -509,8 +514,18 @@ pub struct Ballot<N> {
} }
impl<N: Number> Ballot<N> { impl<N: Number> Ballot<N> {
/// Check if this ballot has any equal rankings
pub fn has_equal_rankings(&self) -> bool {
return self.preferences.iter().any(|p| p.len() > 1);
}
/// Convert ballot with equal rankings to strict-preference "minivoters" /// Convert ballot with equal rankings to strict-preference "minivoters"
pub fn realise_equal_rankings(&self) -> Vec<Ballot<N>> { pub fn realise_equal_rankings_into(self, dest: &mut Vec<Ballot<N>>) {
if !self.has_equal_rankings() {
dest.push(self);
return;
}
// Preferences for each minivoter // Preferences for each minivoter
let mut minivoters = vec![Vec::new()]; let mut minivoters = vec![Vec::new()];
@ -541,10 +556,13 @@ impl<N: Number> Ballot<N> {
} }
let weight_each = self.orig_value.clone() / N::from(minivoters.len()); let weight_each = self.orig_value.clone() / N::from(minivoters.len());
let ballots = minivoters.into_iter()
.map(|p| Ballot { orig_value: weight_each.clone(), preferences: p }) for minivoter in minivoters {
.collect(); dest.push(Ballot {
return ballots; orig_value: weight_each.clone(),
preferences: minivoter
});
}
} }
} }