With --sample-per-ballot, terminate immediately on electing the required number

This commit is contained in:
RunasSudo 2021-08-05 20:18:10 +10:00
parent 33594c110e
commit 429191dc81
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
6 changed files with 61 additions and 105 deletions

View File

@ -63,6 +63,8 @@ pub fn distribute_first_preferences<N: Number>(state: &mut CountState<N>) {
} }
/// Distribute the largest surplus according to the Gregory or random subset method, based on [STVOptions::surplus] /// Distribute the largest surplus according to the Gregory or random subset method, based on [STVOptions::surplus]
///
/// Returns `true` if any surpluses were distributed.
pub fn distribute_surpluses<N: Number>(state: &mut CountState<N>, opts: &STVOptions) -> Result<bool, STVError> pub fn distribute_surpluses<N: Number>(state: &mut CountState<N>, opts: &STVOptions) -> Result<bool, STVError>
where where
for<'r> &'r N: ops::Sub<&'r N, Output=N>, for<'r> &'r N: ops::Sub<&'r N, Output=N>,
@ -117,7 +119,7 @@ where
/// Return the denominator of the surplus fraction /// Return the denominator of the surplus fraction
/// ///
/// Returns `None` if the value of transferable votes <= surplus (i.e. all transferable votes are transferred at values received) /// Returns `None` if the value of transferable votes <= surplus (i.e. all transferable votes are transferred at values received).
fn calculate_surplus_denom<N: Number>(surplus: &N, result: &NextPreferencesResult<N>, transferable_votes: &N, weighted: bool, transferable_only: bool) -> Option<N> fn calculate_surplus_denom<N: Number>(surplus: &N, result: &NextPreferencesResult<N>, transferable_votes: &N, weighted: bool, transferable_only: bool) -> Option<N>
where where
for<'r> &'r N: ops::Sub<&'r N, Output=N> for<'r> &'r N: ops::Sub<&'r N, Output=N>

View File

@ -572,7 +572,7 @@ impl fmt::Display for STVError {
} }
/// Distribute first preferences, and initialise other states such as the random number generator and tie-breaking rules /// Distribute first preferences, and initialise other states such as the random number generator and tie-breaking rules
pub fn count_init<'a, N: Number>(state: &mut CountState<'a, N>, opts: &'a STVOptions) -> Result<bool, STVError> pub fn count_init<'a, N: Number>(state: &mut CountState<'a, N>, opts: &'a STVOptions) -> Result<(), STVError>
where where
for<'r> &'r N: ops::Sub<&'r N, Output=N>, for<'r> &'r N: ops::Sub<&'r N, Output=N>,
for<'r> &'r N: ops::Mul<&'r N, Output=N>, for<'r> &'r N: ops::Mul<&'r N, Output=N>,
@ -591,10 +591,12 @@ where
elect_hopefuls(state, opts)?; elect_hopefuls(state, opts)?;
init_tiebreaks(state, opts); init_tiebreaks(state, opts);
return Ok(true); return Ok(());
} }
/// Perform a single stage of the STV count /// Perform a single stage of the STV count
///
/// Returns `true` if the count is complete, otherwise `false`.
pub fn count_one_stage<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptions) -> Result<bool, STVError> pub fn count_one_stage<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptions) -> Result<bool, STVError>
where where
for<'r> &'r N: ops::Sub<&'r N, Output=N>, for<'r> &'r N: ops::Sub<&'r N, Output=N>,
@ -891,6 +893,8 @@ fn meets_vre<N: Number>(state: &CountState<N>, count_card: &CountCard<N>, opts:
} }
/// Declare elected the continuing candidates leading for remaining vacancies if they cannot be overtaken /// Declare elected the continuing candidates leading for remaining vacancies if they cannot be overtaken
///
/// Returns `true` if any candidates were elected.
fn elect_sure_winners<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptions) -> Result<bool, STVError> { fn elect_sure_winners<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptions) -> Result<bool, STVError> {
let num_vacancies = state.election.seats - state.num_elected; let num_vacancies = state.election.seats - state.num_elected;
if num_vacancies == 0 { if num_vacancies == 0 {
@ -965,6 +969,8 @@ fn elect_sure_winners<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOp
} }
/// Declare elected all candidates meeting the quota, and (if enabled) any candidates who can be early bulk elected because they have sufficiently many votes /// Declare elected all candidates meeting the quota, and (if enabled) any candidates who can be early bulk elected because they have sufficiently many votes
///
/// Returns `true` if any candidates were elected.
fn elect_hopefuls<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptions) -> Result<bool, STVError> { fn elect_hopefuls<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptions) -> Result<bool, STVError> {
let mut cands_meeting_quota: Vec<(&Candidate, &CountCard<N>)> = state.election.candidates.iter() // Present in order in case of tie let mut cands_meeting_quota: Vec<(&Candidate, &CountCard<N>)> = state.election.candidates.iter() // Present in order in case of tie
.map(|c| (c, &state.candidates[c])) .map(|c| (c, &state.candidates[c]))
@ -1043,7 +1049,7 @@ fn elect_hopefuls<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOption
/// Determine whether the transfer of all surpluses can be deferred /// Determine whether the transfer of all surpluses can be deferred
/// ///
/// The value of [STVOptions::defer_surpluses] is not taken into account and must be handled by the caller /// The value of [STVOptions::defer_surpluses] is not taken into account and must be handled by the caller.
fn can_defer_surpluses<N: Number>(state: &CountState<N>, opts: &STVOptions, total_surpluses: &N) -> bool fn can_defer_surpluses<N: Number>(state: &CountState<N>, opts: &STVOptions, total_surpluses: &N) -> bool
where where
for<'r> &'r N: ops::Sub<&'r N, Output=N> for<'r> &'r N: ops::Sub<&'r N, Output=N>
@ -1073,6 +1079,8 @@ where
} }
/// Distribute surpluses according to [STVOptions::surplus] /// Distribute surpluses according to [STVOptions::surplus]
///
/// Returns `true` if any surpluses were distributed.
fn distribute_surpluses<N: Number>(state: &mut CountState<N>, opts: &STVOptions) -> Result<bool, STVError> fn distribute_surpluses<N: Number>(state: &mut CountState<N>, opts: &STVOptions) -> Result<bool, STVError>
where where
for<'r> &'r N: ops::Sub<&'r N, Output=N>, for<'r> &'r N: ops::Sub<&'r N, Output=N>,
@ -1152,6 +1160,8 @@ fn do_bulk_elect<N: Number>(state: &mut CountState<N>, opts: &STVOptions, templa
} }
/// Declare all continuing candidates elected, if the number equals the number of remaining vacancies /// Declare all continuing candidates elected, if the number equals the number of remaining vacancies
///
/// Returns `true` if any candidates were elected.
fn bulk_elect<N: Number>(state: &mut CountState<N>, opts: &STVOptions) -> Result<bool, STVError> { fn bulk_elect<N: Number>(state: &mut CountState<N>, opts: &STVOptions) -> Result<bool, STVError> {
if can_bulk_elect(state, 0) { if can_bulk_elect(state, 0) {
state.kind = None; state.kind = None;
@ -1163,6 +1173,9 @@ fn bulk_elect<N: Number>(state: &mut CountState<N>, opts: &STVOptions) -> Result
return Ok(false); return Ok(false);
} }
/// Declare all doomed candidates excluded
///
/// Returns `true` if any candidates were excluded.
fn exclude_doomed<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptions) -> Result<bool, STVError> fn exclude_doomed<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptions) -> Result<bool, STVError>
where where
for<'r> &'r N: ops::Sub<&'r N, Output=N>, for<'r> &'r N: ops::Sub<&'r N, Output=N>,
@ -1243,7 +1256,7 @@ fn hopefuls_below_threshold<'a, N: Number>(state: &CountState<'a, N>, opts: &STV
/// Determine which continuing candidates could be excluded in a bulk exclusion /// Determine which continuing candidates could be excluded in a bulk exclusion
/// ///
/// The value of [STVOptions::bulk_exclude] is not taken into account and must be handled by the caller /// The value of [STVOptions::bulk_exclude] is not taken into account and must be handled by the caller.
fn hopefuls_to_bulk_exclude<'a, N: Number>(state: &CountState<'a, N>, _opts: &STVOptions) -> Vec<&'a Candidate> { fn hopefuls_to_bulk_exclude<'a, N: Number>(state: &CountState<'a, N>, _opts: &STVOptions) -> Vec<&'a Candidate> {
let mut excluded_candidates = Vec::new(); let mut excluded_candidates = Vec::new();
@ -1358,6 +1371,8 @@ where
} }
/// Continue the exclusion of a candidate who is being excluded /// Continue the exclusion of a candidate who is being excluded
///
/// Returns `true` if an exclusion was continued.
fn continue_exclusion<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptions) -> Result<bool, STVError> fn continue_exclusion<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptions) -> Result<bool, STVError>
where where
for<'r> &'r N: ops::Sub<&'r N, Output=N>, for<'r> &'r N: ops::Sub<&'r N, Output=N>,
@ -1437,7 +1452,7 @@ fn finished_before_stage<N: Number>(state: &CountState<N>) -> bool {
/// Break a tie between the given candidates according to [STVOptions::ties], selecting the highest candidate /// Break a tie between the given candidates according to [STVOptions::ties], selecting the highest candidate
/// ///
/// The given candidates are assumed to be tied in this round /// The given candidates are assumed to be tied in this round.
fn choose_highest<'c, N: Number>(state: &mut CountState<N>, opts: &STVOptions, candidates: Vec<&'c Candidate>, prompt_text: &str) -> Result<&'c Candidate, STVError> { fn choose_highest<'c, N: Number>(state: &mut CountState<N>, opts: &STVOptions, candidates: Vec<&'c Candidate>, prompt_text: &str) -> Result<&'c Candidate, STVError> {
for strategy in opts.ties.iter() { for strategy in opts.ties.iter() {
match strategy.choose_highest(state, opts, &candidates, prompt_text) { match strategy.choose_highest(state, opts, &candidates, prompt_text) {
@ -1458,7 +1473,7 @@ fn choose_highest<'c, N: Number>(state: &mut CountState<N>, opts: &STVOptions, c
/// Break a tie between the given candidates according to [STVOptions::ties], selecting the lowest candidate /// Break a tie between the given candidates according to [STVOptions::ties], selecting the lowest candidate
/// ///
/// The given candidates are assumed to be tied in this round /// The given candidates are assumed to be tied in this round.
fn choose_lowest<'c, N: Number>(state: &mut CountState<N>, opts: &STVOptions, candidates: Vec<&'c Candidate>, prompt_text: &str) -> Result<&'c Candidate, STVError> { fn choose_lowest<'c, N: Number>(state: &mut CountState<N>, opts: &STVOptions, candidates: Vec<&'c Candidate>, prompt_text: &str) -> Result<&'c Candidate, STVError> {
for strategy in opts.ties.iter() { for strategy in opts.ties.iter() {
match strategy.choose_lowest(state, opts, &candidates, prompt_text) { match strategy.choose_lowest(state, opts, &candidates, prompt_text) {

View File

@ -28,7 +28,7 @@ use super::{NextPreferencesResult, STVError};
/// Return the denominator of the surplus fraction /// Return the denominator of the surplus fraction
/// ///
/// Returns `None` if transferable ballots <= surplus (i.e. all transferable ballots are transferred at full value) /// Returns `None` if transferable ballots <= surplus (i.e. all transferable ballots are transferred at full value).
fn calculate_surplus_denom<N: Number>(surplus: &N, result: &NextPreferencesResult<N>, transferable_ballots: &N, transferable_only: bool) -> Option<N> fn calculate_surplus_denom<N: Number>(surplus: &N, result: &NextPreferencesResult<N>, transferable_ballots: &N, transferable_only: bool) -> Option<N>
where where
for<'r> &'r N: ops::Sub<&'r N, Output=N> for<'r> &'r N: ops::Sub<&'r N, Output=N>
@ -197,7 +197,10 @@ where
match votes.pop() { match votes.pop() {
Some(vote) => { Some(vote) => {
// Transfer to next preference // Transfer to next preference
transfer_ballot(state, opts, elected_candidate, vote)?; transfer_ballot(state, opts, elected_candidate, vote, opts.transferable_only)?;
if state.num_elected == state.election.seats {
return Ok(());
}
} }
None => { None => {
// We have run out of ballot papers // We have run out of ballot papers
@ -234,7 +237,10 @@ where
while &state.candidates[elected_candidate].votes > state.quota.as_ref().unwrap() { while &state.candidates[elected_candidate].votes > state.quota.as_ref().unwrap() {
// Transfer one vote to next available preference // Transfer one vote to next available preference
let vote = numbered_votes.remove(&index).unwrap(); let vote = numbered_votes.remove(&index).unwrap();
transfer_ballot(state, opts, elected_candidate, vote)?; transfer_ballot(state, opts, elected_candidate, vote, opts.transferable_only)?;
if state.num_elected == state.election.seats {
return Ok(());
}
index += skip_value; index += skip_value;
if index >= total_ballots { if index >= total_ballots {
@ -260,8 +266,8 @@ where
/// Transfer the given ballot paper to its next available preference, and check for candidates meeting the quota if --sample-per-ballot /// Transfer the given ballot paper to its next available preference, and check for candidates meeting the quota if --sample-per-ballot
/// ///
/// Does nothing if --transferable-only and the ballot is nontransferable. /// If `ignore_nontransferable`, does nothing if --transferable-only and the ballot is nontransferable.
fn transfer_ballot<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptions, elected_candidate: &Candidate, mut vote: Vote<'a, N>) -> Result<(), STVError> { fn transfer_ballot<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptions, source_candidate: &Candidate, mut vote: Vote<'a, N>, ignore_nontransferable: bool) -> Result<(), STVError> {
// Get next preference // Get next preference
let mut next_candidate = None; let mut next_candidate = None;
for (i, preference) in vote.ballot.preferences.iter().enumerate().skip(vote.up_to_pref) { for (i, preference) in vote.ballot.preferences.iter().enumerate().skip(vote.up_to_pref) {
@ -278,7 +284,7 @@ fn transfer_ballot<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptio
// Have to structure like this to satisfy Rust's borrow checker // Have to structure like this to satisfy Rust's borrow checker
if let Some(candidate) = next_candidate { if let Some(candidate) = next_candidate {
// Available preference // Available preference
state.candidates.get_mut(elected_candidate).unwrap().transfer(&-vote.value.clone()); state.candidates.get_mut(source_candidate).unwrap().transfer(&-vote.value.clone());
let count_card = state.candidates.get_mut(candidate).unwrap(); let count_card = state.candidates.get_mut(candidate).unwrap();
count_card.transfer(&vote.value); count_card.transfer(&vote.value);
@ -309,10 +315,10 @@ fn transfer_ballot<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOptio
} }
} else { } else {
// Exhausted // Exhausted
if opts.transferable_only { if opts.transferable_only && ignore_nontransferable {
// Another ballot paper required // Another ballot paper required
} else { } else {
state.candidates.get_mut(elected_candidate).unwrap().transfer(&-vote.value.clone()); state.candidates.get_mut(source_candidate).unwrap().transfer(&-vote.value.clone());
state.exhausted.transfer(&vote.value); state.exhausted.transfer(&vote.value);
match state.exhausted.parcels.last_mut() { match state.exhausted.parcels.last_mut() {
@ -362,97 +368,30 @@ where
} }
} }
// Determine votes to transfer // Count votes
let mut votes = Vec::new(); let mut total_ballots: usize = 0;
for excluded_candidate in excluded_candidates.iter() { for excluded_candidate in excluded_candidates.iter() {
let count_card = state.candidates.get_mut(excluded_candidate).unwrap(); let count_card = state.candidates.get_mut(excluded_candidate).unwrap();
votes.append(&mut count_card.concat_parcels()); total_ballots = count_card.parcels.iter()
count_card.parcels.clear(); .fold(total_ballots, |acc, p| acc + p.votes.len());
} }
let total_ballots = votes.len();
if !votes.is_empty() {
if total_ballots == 1 { if total_ballots == 1 {
state.logger.log_literal("Transferring 1 ballot.".to_string()); state.logger.log_literal("Transferring 1 ballot.".to_string());
} else { } else {
state.logger.log_literal(format!("Transferring {:.0} ballots.", total_ballots)); state.logger.log_literal(format!("Transferring {:.0} ballots.", total_ballots));
} }
// Transfer vote by vote // Transfer votes
for mut vote in votes { for excluded_candidate in excluded_candidates.iter() {
// Subtract votes from excluded candidate let count_card = state.candidates.get_mut(excluded_candidate).unwrap();
let count_card = state.candidates.get_mut(&state.election.candidates[vote.ballot.preferences[vote.up_to_pref - 1]]).unwrap(); let votes = count_card.concat_parcels();
count_card.transfer(&-vote.value.clone()); count_card.parcels.clear();
// Transfer to next preference for vote in votes {
let mut next_candidate = None; transfer_ballot(state, opts, excluded_candidate, vote, false)?;
for (i, preference) in vote.ballot.preferences.iter().enumerate().skip(vote.up_to_pref) { if state.num_elected == state.election.seats {
let candidate = &state.election.candidates[*preference]; return Ok(());
let count_card = &state.candidates[candidate];
if let CandidateState::Hopeful | CandidateState::Guarded = count_card.state {
next_candidate = Some(candidate);
vote.up_to_pref = i + 1;
break;
}
}
// Have to structure like this to satisfy Rust's borrow checker
if let Some(candidate) = next_candidate {
// Available preference
let count_card = state.candidates.get_mut(candidate).unwrap();
count_card.transfer(&vote.value);
match count_card.parcels.last_mut() {
Some(parcel) => {
if parcel.source_order == state.num_elected + state.num_excluded {
parcel.votes.push(vote);
} else {
let parcel = Parcel {
votes: vec![vote],
source_order: state.num_elected + state.num_excluded,
};
count_card.parcels.push(parcel);
}
}
None => {
let parcel = Parcel {
votes: vec![vote],
source_order: state.num_elected + state.num_excluded,
};
count_card.parcels.push(parcel);
}
}
if opts.sample_per_ballot {
super::elect_hopefuls(state, opts)?;
}
} else {
// Exhausted
state.exhausted.transfer(&vote.value);
match state.exhausted.parcels.last_mut() {
Some(parcel) => {
if parcel.source_order == state.num_elected + state.num_excluded {
parcel.votes.push(vote);
} else {
let parcel = Parcel {
votes: vec![vote],
source_order: state.num_elected + state.num_excluded,
};
state.exhausted.parcels.push(parcel);
}
}
None => {
let parcel = Parcel {
votes: vec![vote],
source_order: state.num_elected + state.num_excluded,
};
state.exhausted.parcels.push(parcel);
}
}
} }
} }
} }

View File

@ -96,9 +96,9 @@ macro_rules! impl_type {
/// Wrapper for [stv::count_init] /// Wrapper for [stv::count_init]
#[wasm_bindgen] #[wasm_bindgen]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn [<count_init_$type>](state: &mut [<CountState$type>], opts: &STVOptions) -> bool { pub fn [<count_init_$type>](state: &mut [<CountState$type>], opts: &STVOptions) {
match stv::count_init(&mut state.0, opts.as_static()) { match stv::count_init(&mut state.0, opts.as_static()) {
Ok(v) => v, Ok(_) => (),
Err(err) => wasm_error!("Error", err), Err(err) => wasm_error!("Error", err),
} }
} }
@ -369,7 +369,7 @@ fn update_results_table<N: Number>(stage_num: usize, state: &CountState<N>, opts
} }
CandidateState::Excluded => { CandidateState::Excluded => {
result.push(&format!(r#"<td class="{}count excluded">{}</td>"#, tdclasses2, pp(&count_card.transfers, opts.pp_decimals)).into()); result.push(&format!(r#"<td class="{}count excluded">{}</td>"#, tdclasses2, pp(&count_card.transfers, opts.pp_decimals)).into());
if count_card.parcels.iter().all(|p| p.votes.is_empty()) { if count_card.votes.is_zero() && count_card.parcels.iter().all(|p| p.votes.is_empty()) {
result.push(&format!(r#"<td class="{}count excluded">Ex</td>"#, tdclasses2).into()); result.push(&format!(r#"<td class="{}count excluded">Ex</td>"#, tdclasses2).into());
} else { } else {
result.push(&format!(r#"<td class="{}count excluded">{}</td>"#, tdclasses2, pp(&count_card.votes, opts.pp_decimals)).into()); result.push(&format!(r#"<td class="{}count excluded">{}</td>"#, tdclasses2, pp(&count_card.votes, opts.pp_decimals)).into());

View File

@ -2,7 +2,7 @@ Stage:,1,,2,,3,,4,,5,,6,,7,,8,,9,,10,,11,,12,,13,
Comment:,First preferences,,"Surplus of Galluccio, Anthony D.",,,,"Exclusion of Dixon, Vincent Lawrence",,"Exclusion of Hall, Robert L., Sr.",,"Exclusion of LaTremouille, Robert J.",,"Exclusion of Taymorberry, Laurie",,"Exclusion of King, Ethridge A., Jr.",,"Exclusion of Smith, Aimee Louise",,"Exclusion of Bellew, Carole K.",,"Exclusion of Kelley, Craig A.",,"Exclusion of Pitkin, John",,"Exclusion of DeBergalis, Matt S.", Comment:,First preferences,,"Surplus of Galluccio, Anthony D.",,,,"Exclusion of Dixon, Vincent Lawrence",,"Exclusion of Hall, Robert L., Sr.",,"Exclusion of LaTremouille, Robert J.",,"Exclusion of Taymorberry, Laurie",,"Exclusion of King, Ethridge A., Jr.",,"Exclusion of Smith, Aimee Louise",,"Exclusion of Bellew, Carole K.",,"Exclusion of Kelley, Craig A.",,"Exclusion of Pitkin, John",,"Exclusion of DeBergalis, Matt S.",
"Bellew, Carole K.",735,H,759,H,761,H,762,H,767,H,771,H,788,H,811,H,861,H,0,EX,0,EX,0,EX,0,EX "Bellew, Carole K.",735,H,759,H,761,H,762,H,767,H,771,H,788,H,811,H,861,H,0,EX,0,EX,0,EX,0,EX
"Davis, Henrietta",1846,H,1896,H,1901,H,1904,H,1909,H,1920,H,1950,H,1977,H,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL "Davis, Henrietta",1846,H,1896,H,1901,H,1904,H,1909,H,1920,H,1950,H,1977,H,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL
"DeBergalis, Matt S.",1206,H,1216,H,1220,H,1227,H,1229,H,1233,H,1242,H,1283,H,1342,H,1441,H,1494,H,1640,H,0,EX "DeBergalis, Matt S.",1206,H,1216,H,1220,H,1227,H,1229,H,1233,H,1242,H,1283,H,1342,H,1441,H,1494,H,1640,H,,EX
"Decker, Marjorie C.",1378,H,1425,H,1428,H,1432,H,1437,H,1442,H,1463,H,1486,H,1528,H,1641,H,1787,H,2009,EL,2009,EL "Decker, Marjorie C.",1378,H,1425,H,1428,H,1432,H,1437,H,1442,H,1463,H,1486,H,1528,H,1641,H,1787,H,2009,EL,2009,EL
"Dixon, Vincent Lawrence",64,H,64,H,65,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX "Dixon, Vincent Lawrence",64,H,64,H,65,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
"Galluccio, Anthony D.",2994,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL "Galluccio, Anthony D.",2994,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL,2009,EL
@ -29,4 +29,4 @@ Write-In 6,0,H,0,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
Write-In 7,0,H,0,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX Write-In 7,0,H,0,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
Write-In 8,0,H,0,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX Write-In 8,0,H,0,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
Write-In 9,0,H,0,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX Write-In 9,0,H,0,H,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX,0,EX
Exhausted,0,,0,,21,,23,,40,,59,,88,,148,,215,,326,,542,,872,,1999, Exhausted,0,,0,,21,,23,,40,,59,,88,,148,,215,,326,,542,,872,,,

1 Stage: 1 2 3 4 5 6 7 8 9 10 11 12 13
2 Comment: First preferences Surplus of Galluccio, Anthony D. Exclusion of Dixon, Vincent Lawrence Exclusion of Hall, Robert L., Sr. Exclusion of LaTremouille, Robert J. Exclusion of Taymorberry, Laurie Exclusion of King, Ethridge A., Jr. Exclusion of Smith, Aimee Louise Exclusion of Bellew, Carole K. Exclusion of Kelley, Craig A. Exclusion of Pitkin, John Exclusion of DeBergalis, Matt S.
3 Bellew, Carole K. 735 H 759 H 761 H 762 H 767 H 771 H 788 H 811 H 861 H 0 EX 0 EX 0 EX 0 EX
4 Davis, Henrietta 1846 H 1896 H 1901 H 1904 H 1909 H 1920 H 1950 H 1977 H 2009 EL 2009 EL 2009 EL 2009 EL 2009 EL
5 DeBergalis, Matt S. 1206 H 1216 H 1220 H 1227 H 1229 H 1233 H 1242 H 1283 H 1342 H 1441 H 1494 H 1640 H 0 EX
6 Decker, Marjorie C. 1378 H 1425 H 1428 H 1432 H 1437 H 1442 H 1463 H 1486 H 1528 H 1641 H 1787 H 2009 EL 2009 EL
7 Dixon, Vincent Lawrence 64 H 64 H 65 H 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX
8 Galluccio, Anthony D. 2994 EL 2009 EL 2009 EL 2009 EL 2009 EL 2009 EL 2009 EL 2009 EL 2009 EL 2009 EL 2009 EL 2009 EL 2009 EL
29 Write-In 7 0 H 0 H 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX
30 Write-In 8 0 H 0 H 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX
31 Write-In 9 0 H 0 H 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX 0 EX
32 Exhausted 0 0 21 23 40 59 88 148 215 326 542 872 1999

Binary file not shown.