Precompute Ballot::has_equal_rankings at parse time
Before: 5.3943 +- 0.0287 After: 5.27661 +- 0.00472
This commit is contained in:
parent
254c04b574
commit
6bb127a124
|
@ -71,6 +71,7 @@ impl<N: Number> Election<N> {
|
|||
let new_ballot = Ballot {
|
||||
orig_value: N::one(),
|
||||
preferences: ballot.preferences.clone(),
|
||||
has_equal_rankings: ballot.has_equal_rankings,
|
||||
};
|
||||
normalised_ballots.push(new_ballot);
|
||||
n += &one;
|
||||
|
@ -81,7 +82,7 @@ impl<N: Number> Election<N> {
|
|||
|
||||
/// Convert ballots with equal rankings to strict-preference "minivoters"
|
||||
pub fn realise_equal_rankings(&mut self) {
|
||||
if !self.ballots.iter().any(|b| b.has_equal_rankings()) {
|
||||
if !self.ballots.iter().any(|b| b.has_equal_rankings) {
|
||||
// No equal rankings
|
||||
return;
|
||||
}
|
||||
|
@ -582,17 +583,14 @@ pub struct Ballot<N> {
|
|||
pub orig_value: N,
|
||||
/// Indexes of candidates preferenced at each level on the ballot
|
||||
pub preferences: Vec<Vec<usize>>,
|
||||
/// Whether multiple candidates are preferenced at the same level
|
||||
pub has_equal_rankings: bool,
|
||||
}
|
||||
|
||||
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"
|
||||
pub fn realise_equal_rankings_into(self, dest: &mut Vec<Ballot<N>>) {
|
||||
if !self.has_equal_rankings() {
|
||||
if !self.has_equal_rankings {
|
||||
dest.push(self);
|
||||
return;
|
||||
}
|
||||
|
@ -631,7 +629,8 @@ impl<N: Number> Ballot<N> {
|
|||
for minivoter in minivoters {
|
||||
dest.push(Ballot {
|
||||
orig_value: weight_each.clone(),
|
||||
preferences: minivoter
|
||||
preferences: minivoter,
|
||||
has_equal_rankings: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,9 @@ pub struct BLTParser<N: Number, I: Iterator<Item=char>> {
|
|||
|
||||
/// Temporary buffer for parsing ballot values
|
||||
ballot_value_buf: String,
|
||||
/// Whether the current ballot has equal preferences
|
||||
ballot_has_equal_rankings: bool,
|
||||
|
||||
/// Current line number
|
||||
line_no: u32,
|
||||
/// Current column number
|
||||
|
@ -139,6 +142,8 @@ impl<N: Number, I: Iterator<Item=char>> BLTParser<N, I> {
|
|||
|
||||
/// Parse a ballot
|
||||
fn ballot(&mut self) -> Result<(), ParseError> {
|
||||
self.ballot_has_equal_rankings = false;
|
||||
|
||||
self.ballot_value()?;
|
||||
|
||||
self.delimiter_not_nl();
|
||||
|
@ -152,6 +157,8 @@ impl<N: Number, I: Iterator<Item=char>> BLTParser<N, I> {
|
|||
break;
|
||||
} else if self.lookahead() == '=' {
|
||||
// Equal preference
|
||||
self.ballot_has_equal_rankings = true;
|
||||
|
||||
self.accept();
|
||||
preferences.last_mut().unwrap().push(self.usize()? - 1);
|
||||
self.delimiter_not_nl();
|
||||
|
@ -167,6 +174,7 @@ impl<N: Number, I: Iterator<Item=char>> BLTParser<N, I> {
|
|||
let ballot = Ballot {
|
||||
orig_value: N::parse(&self.ballot_value_buf),
|
||||
preferences,
|
||||
has_equal_rankings: self.ballot_has_equal_rankings,
|
||||
};
|
||||
self.election.ballots.push(ballot);
|
||||
|
||||
|
@ -376,6 +384,7 @@ impl<N: Number, I: Iterator<Item=char>> BLTParser<N, I> {
|
|||
Self {
|
||||
chars,
|
||||
ballot_value_buf: String::new(),
|
||||
ballot_has_equal_rankings: false,
|
||||
line_no: 1,
|
||||
col_no: 1,
|
||||
num_candidates: 0,
|
||||
|
|
|
@ -95,6 +95,7 @@ pub fn parse_reader<R: Read, N: Number>(reader: R, require_1: bool, require_sequ
|
|||
ballots.push(Ballot {
|
||||
orig_value: value,
|
||||
preferences: vec![],
|
||||
has_equal_rankings: false,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
@ -102,17 +103,20 @@ pub fn parse_reader<R: Read, N: Number>(reader: R, require_1: bool, require_sequ
|
|||
|
||||
let mut sorted_preferences = Vec::with_capacity(preferences.len());
|
||||
let mut last_ranking = None;
|
||||
let mut has_equal_rankings = false;
|
||||
|
||||
for ranking in unique_rankings {
|
||||
// Filter for preferences at this ranking
|
||||
let prefs_this_ranking: Vec<usize> = preferences.iter()
|
||||
.filter_map(|(r, i)| if *r == ranking { Some(**i) } else { None })
|
||||
.collect();
|
||||
|
||||
if require_strict_order {
|
||||
if prefs_this_ranking.len() != 1 {
|
||||
if prefs_this_ranking.len() != 1 {
|
||||
if require_strict_order {
|
||||
// Duplicate rankings
|
||||
break;
|
||||
}
|
||||
has_equal_rankings = true;
|
||||
}
|
||||
|
||||
if require_sequential {
|
||||
|
@ -131,6 +135,7 @@ pub fn parse_reader<R: Read, N: Number>(reader: R, require_1: bool, require_sequ
|
|||
ballots.push(Ballot {
|
||||
orig_value: value,
|
||||
preferences: sorted_preferences,
|
||||
has_equal_rankings,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue