pub fn deduce<Tally>(ballots:&BallotChanges<Tally>, data:&ElectionData, ballot_types_considered_unverifiable:&HashSet<String>, outcome: &DeltasInCandidateLists) -> Self {
        let mut res = ChangeTypes{
            changed_first_preference: false,
            changed_atl: false,
            added_ballots: false,
            removed_ballots: false,
            changed_ballots: false,
            affected_verifiable_ballots: false,
            directly_benefited_new_winner: false,
            directly_hurt_new_loser: false
        };
        let num_atl = data.atl.len();
        for bcs in &ballots.changes {
            if bcs.from.is_none() { res.added_ballots=true; }
            if bcs.candidate_to.is_none() { res.removed_ballots=true; }
            if bcs.from.is_some() && bcs.candidate_to.is_some() { res.changed_ballots=true; }
            let mut found_atl_this_batch = false; // only check party equivalence if relevent. An optimization for from, necessary for to.
            if let Some(from) = bcs.from.as_ref() {
                let from_party = data.metadata.candidate(from.candidate).party;
                for b in &from.ballots {
                    if b.from.0<num_atl { // it is an ATL vote
                        res.changed_atl=true;
                        if from_party.unwrap()==data.atl[b.from.0].parties[0] { res.changed_first_preference=true; }
                        if !ballot_types_considered_unverifiable.is_empty() {
                            if data.is_atl_verifiable(b.from.0,ballot_types_considered_unverifiable) { res.affected_verifiable_ballots =true; }
                        }
                        found_atl_this_batch=true;
                    } else { // it is a BTL vote
                        if from.candidate==data.btl[b.from.0-num_atl].candidates[0] { res.changed_first_preference=true; }
                        if !ballot_types_considered_unverifiable.is_empty() {
                            if data.is_btl_verifiable(b.from.0-num_atl,ballot_types_considered_unverifiable) { res.affected_verifiable_ballots =true; }
                        }
                    }
                }
                if outcome.list2only.contains(&from.candidate) { res.directly_hurt_new_loser=true; }
                if found_atl_this_batch {
                    if outcome.list2only.iter().any(|&c|data.metadata.candidate(c).party==from_party) { res.directly_hurt_new_loser=true; }
                }
            }
            if let Some(to) = bcs.candidate_to {
                if outcome.list1only.contains(&to) { res.directly_benefited_new_winner=true; }
                if found_atl_this_batch {
                    let to_party = data.metadata.candidate(to).party;
                    if outcome.list1only.iter().any(|&c|data.metadata.candidate(c).party==to_party) { res.directly_benefited_new_winner=true; }
                }
            }
        }
        res
    }
/// Deduce what properties the ballots have.
/// If not empty, ballot_types_considered_unverifiable contains the vote types deemed to be unverifiable.
Deduce what properties the ballots have.
If not empty, ballot_types_considered_unverifiable contains the vote types deemed to be unverifiable.
Deduce what properties the ballots have . If not empty ballot_types_considered_unverifiable contains the vote types deemed to be unverifiable .
pub fn deduce<Tally>(ballots:&BallotChanges<Tally>, data:&ElectionData, ballot_types_considered_unverifiable:&HashSet<String>, outcome: &DeltasInCandidateLists) -> Self {
        let mut res = ChangeTypes{
            changed_first_preference: false,
            changed_atl: false,
            added_ballots: false,
            removed_ballots: false,
            changed_ballots: false,
            affected_verifiable_ballots: false,
            directly_benefited_new_winner: false,
            directly_hurt_new_loser: false
        };
        let num_atl = data.atl.len();
        for bcs in &ballots.changes {
            if bcs.from.is_none() { res.added_ballots=true; }
            if bcs.candidate_to.is_none() { res.removed_ballots=true; }
            if bcs.from.is_some() && bcs.candidate_to.is_some() { res.changed_ballots=true; }
            let mut found_atl_this_batch = false; // only check party equivalence if relevent. An optimization for from, necessary for to.
            if let Some(from) = bcs.from.as_ref() {
                let from_party = data.metadata.candidate(from.candidate).party;
                for b in &from.ballots {
                    if b.from.0<num_atl { // it is an ATL vote
                        res.changed_atl=true;
                        if from_party.unwrap()==data.atl[b.from.0].parties[0] { res.changed_first_preference=true; }
                        if !ballot_types_considered_unverifiable.is_empty() {
                            if data.is_atl_verifiable(b.from.0,ballot_types_considered_unverifiable) { res.affected_verifiable_ballots =true; }
                        }
                        found_atl_this_batch=true;
                    } else { // it is a BTL vote
                        if from.candidate==data.btl[b.from.0-num_atl].candidates[0] { res.changed_first_preference=true; }
                        if !ballot_types_considered_unverifiable.is_empty() {
                            if data.is_btl_verifiable(b.from.0-num_atl,ballot_types_considered_unverifiable) { res.affected_verifiable_ballots =true; }
                        }
                    }
                }
                if outcome.list2only.contains(&from.candidate) { res.directly_hurt_new_loser=true; }
                if found_atl_this_batch {
                    if outcome.list2only.iter().any(|&c|data.metadata.candidate(c).party==from_party) { res.directly_hurt_new_loser=true; }
                }
            }
            if let Some(to) = bcs.candidate_to {
                if outcome.list1only.contains(&to) { res.directly_benefited_new_winner=true; }
                if found_atl_this_batch {
                    let to_party = data.metadata.candidate(to).party;
                    if outcome.list1only.iter().any(|&c|data.metadata.candidate(c).party==to_party) { res.directly_benefited_new_winner=true; }
                }
            }
        }
        res
    }
pub fn deduce < Tally > ( ballots : & BallotChanges < Tally > , data : & ElectionData , ballot_types_considered_unverifiable : & HashSet < String > , outcome : & DeltasInCandidateLists ) -> Self { let mut res = ChangeTypes { changed_first_preference : false , changed_atl : false , added_ballots : false , removed_ballots : false , changed_ballots : false , affected_verifiable_ballots : false , directly_benefited_new_winner : false , directly_hurt_new_loser : false } ; let num_atl = data . atl . len ( ) ; for bcs in & ballots . changes { if bcs . from . is_none ( ) { res . added_ballots = true ; } if bcs . candidate_to . is_none ( ) { res . removed_ballots = true ; } if bcs . from . is_some ( ) && bcs . candidate_to . is_some ( ) { res . changed_ballots = true ; } let mut found_atl_this_batch = false ; // only check party equivalence if relevent. An optimization for from, necessary for to. if let Some ( from ) = bcs . from . as_ref ( ) { let from_party = data . metadata . candidate ( from . candidate ) . party ; for b in & from . ballots { if b . from . 0 < num_atl { // it is an ATL vote res . changed_atl = true ; if from_party . unwrap ( ) == data . atl [ b . from . 0 ] . parties [ 0 ] { res . changed_first_preference = true ; } if ! ballot_types_considered_unverifiable . is_empty ( ) { if data . is_atl_verifiable ( b . from . 0 , ballot_types_considered_unverifiable ) { res . affected_verifiable_ballots = true ; } } found_atl_this_batch = true ; } else { // it is a BTL vote if from . candidate == data . btl [ b . from . 0 - num_atl ] . candidates [ 0 ] { res . changed_first_preference = true ; } if ! ballot_types_considered_unverifiable . is_empty ( ) { if data . is_btl_verifiable ( b . from . 0 - num_atl , ballot_types_considered_unverifiable ) { res . affected_verifiable_ballots = true ; } } } } if outcome . list2only . contains ( & from . candidate ) { res . directly_hurt_new_loser = true ; } if found_atl_this_batch { if outcome . list2only . iter ( ) . any ( | & c | data . metadata . candidate ( c ) . party == from_party ) { res . directly_hurt_new_loser = true ; } } } if let Some ( to ) = bcs . candidate_to { if outcome . list1only . contains ( & to ) { res . directly_benefited_new_winner = true ; } if found_atl_this_batch { let to_party = data . metadata . candidate ( to ) . party ; if outcome . list1only . iter ( ) . any ( | & c | data . metadata . candidate ( c ) . party == to_party ) { res . directly_benefited_new_winner = true ; } } } } res }
Deduce what properties the ballots have.
Deduce what properties the ballots have .
ballots
&BallotChanges<Tally>
data
&ElectionData
ballot_types_considered_unverifiable
&HashSet<String>
outcome
&DeltasInCandidateLists
ballots
&BallotChanges<Tally>
data
&ElectionData
ballot_types_considered_unverifiable
&HashSet<String>
outcome
&DeltasInCandidateLists