public void ComposeBallots(BallotCompositionMethod method) { FinalBallots = new Dictionary<int, MeetingElectionCandidates>(); QuotedMasterList = GenerateBallot(rawElectionResult, -1, BallotCompositionMethod.Unmixed); if (geographicLists.Count == 0) { GenerateGeographicLists(); } foreach (Geography ballotGeography in BallotGeographies) { FinalBallots[ballotGeography.Identity] = GenerateBallot(geographicLists[ballotGeography.Identity], 22, method); } }
public void ComposeBallots(BallotCompositionMethod method) { FinalBallots = new Dictionary <int, MeetingElectionCandidates>(); QuotedMasterList = GenerateBallot(rawElectionResult, -1, BallotCompositionMethod.Unmixed); if (geographicLists.Count == 0) { GenerateGeographicLists(); } foreach (Geography ballotGeography in BallotGeographies) { FinalBallots[ballotGeography.Identity] = GenerateBallot(geographicLists[ballotGeography.Identity], 22, method); } }
/// <summary> /// Gets the position of the master list to use for this position on the local list. /// </summary> /// <param name="currentPosition">The position of a particular ballot.</param> /// <param name="method">The composition method to use.</param> /// <returns>The position to pick from the master list, or zero if not from the master list.</returns> private int GetMasterListPosition(int currentPosition, BallotCompositionMethod method) { if (method == BallotCompositionMethod.Unmixed) { return(0); // always use local } if (method == BallotCompositionMethod.TopTenNational) { if (currentPosition <= 10) { return(currentPosition); } return(0); } if (method == BallotCompositionMethod.TopFiveNational) { if (currentPosition <= 5) { return(currentPosition); } return(0); } if (method == BallotCompositionMethod.InterleavedTenNational) { if ((currentPosition % 2 == 1) && currentPosition < 20) { return(currentPosition / 2 + 1); } return(0); } throw new NotImplementedException("Unimplemented method"); }
private MeetingElectionCandidates GenerateBallot(MeetingElectionCandidates rawList, int candidateCount, BallotCompositionMethod method) { MeetingElectionCandidates result = new MeetingElectionCandidates(); Dictionary <int, bool> takenCandidates = new Dictionary <int, bool>(); if (candidateCount == -1) { candidateCount = rawList.Count; } // First, cancel out the defected candidates. Expensive op, but don't care. for (int rawIndex = 0; rawIndex < rawList.Count; rawIndex++) { if (CandidatePersonIdDefected(rawList[rawIndex].PersonId)) { takenCandidates[rawIndex] = true; } } if (candidateCount == rawList.Count) { candidateCount -= takenCandidates.Count; } // Assemble list. while (result.Count < candidateCount) { // Add a candidate. // // Should we add a candidate from the raw list or from the quoted master list? int masterPosition = GetMasterListPosition(result.Count + 1, method); if (masterPosition > 0) { // We should add a candidate from the master list, no quota calculations, BUT ONLY if this candidate // hasn't already been added from the district list. int rawListIndex = FindCandidateIndex(QuotedMasterList[masterPosition - 1].InternalPollCandidateId, rawList); if (rawListIndex >= 0 && !takenCandidates.ContainsKey(rawListIndex)) { // The master list candidate is also on the district list, but has not been added. Add // the candidate in the master list position. result.Add(QuotedMasterList[masterPosition - 1]); takenCandidates[rawListIndex] = true; continue; } if (rawListIndex == -1) { // The master list candidate is not on the district list. Add the candidate. result.Add(QuotedMasterList[masterPosition - 1]); continue; } // Getting here, the candidate on the master position had already been placed on the list through his // or her district, so fallthrough to local candidates for this master position } // Add a candidate from the local list. First, try adding the next available candidate. // If this puts us outside of the allowed gender quota, pick the next candidate of the // underrepresented gender instead. int nextCandidateIndex = 0; while (takenCandidates.ContainsKey(nextCandidateIndex)) { nextCandidateIndex++; } PersonGender candidateGender = rawList[nextCandidateIndex].Person.Gender; double currentMaleQuota = CalculateListMaleQuota(result, candidateGender); // Here, we account an extremely rare situation where the correct quota is not even obtainable, e.g. // for position #3 where #1 is male and #2 is female and with a quota of 40%. Either way, it will // fall outside of bounds (33% or 66%). If so, ignore the quota if it is not obtainable. PersonGender oppositeGender = (candidateGender == PersonGender.Male ? PersonGender.Female : PersonGender.Male); double alternateMaleQuota = CalculateListMaleQuota(result, oppositeGender); // If currentMaleQuota is outside of bounds AND the alternate quota IS inside of bounds... if (currentMaleQuota < GenderQuota || currentMaleQuota > (1.0 - GenderQuota)) { if (alternateMaleQuota >= GenderQuota && alternateMaleQuota <= (1.0 - GenderQuota)) { // ...pick the alternate (underrepresented) candidate try { nextCandidateIndex = GetNextSpecificGenderCandidate(rawList, takenCandidates, oppositeGender); } catch (ArgumentOutOfRangeException) { // there isn't any more candidate of the requested gender, so go with what we have } } } result.Add(rawList[nextCandidateIndex]); takenCandidates[nextCandidateIndex] = true; } return(result); }
/// <summary> /// Gets the position of the master list to use for this position on the local list. /// </summary> /// <param name="currentPosition">The position of a particular ballot.</param> /// <param name="method">The composition method to use.</param> /// <returns>The position to pick from the master list, or zero if not from the master list.</returns> private int GetMasterListPosition (int currentPosition, BallotCompositionMethod method) { if (method == BallotCompositionMethod.Unmixed) { return 0; // always use local } if (method == BallotCompositionMethod.TopTenNational) { if (currentPosition <= 10) { return currentPosition; } return 0; } if (method == BallotCompositionMethod.TopFiveNational) { if (currentPosition <= 5) { return currentPosition; } return 0; } if (method == BallotCompositionMethod.InterleavedTenNational) { if ((currentPosition % 2 == 1) && currentPosition < 20) { return (currentPosition/2 + 1); } return 0; } throw new NotImplementedException("Unimplemented method"); }
private MeetingElectionCandidates GenerateBallot (MeetingElectionCandidates rawList, int candidateCount, BallotCompositionMethod method) { MeetingElectionCandidates result = new MeetingElectionCandidates(); Dictionary<int, bool> takenCandidates = new Dictionary<int, bool>(); if (candidateCount == -1) { candidateCount = rawList.Count; } // First, cancel out the defected candidates. Expensive op, but don't care. for (int rawIndex = 0; rawIndex < rawList.Count; rawIndex++) { if (this.CandidatePersonIdDefected(rawList [rawIndex].PersonId)) { takenCandidates[rawIndex] = true; } } if (candidateCount == rawList.Count) { candidateCount -= takenCandidates.Count; } // Assemble list. while (result.Count < candidateCount) { // Add a candidate. // // Should we add a candidate from the raw list or from the quoted master list? int masterPosition = GetMasterListPosition (result.Count + 1, method); if (masterPosition > 0) { // We should add a candidate from the master list, no quota calculations, BUT ONLY if this candidate // hasn't already been added from the district list. int rawListIndex = FindCandidateIndex (QuotedMasterList[masterPosition - 1].InternalPollCandidateId, rawList); if (rawListIndex >= 0 && !takenCandidates.ContainsKey(rawListIndex)) { // The master list candidate is also on the district list, but has not been added. Add // the candidate in the master list position. result.Add(QuotedMasterList[masterPosition - 1]); takenCandidates[rawListIndex] = true; continue; } if (rawListIndex == -1) { // The master list candidate is not on the district list. Add the candidate. result.Add(QuotedMasterList[masterPosition - 1]); continue; } // Getting here, the candidate on the master position had already been placed on the list through his // or her district, so fallthrough to local candidates for this master position } // Add a candidate from the local list. First, try adding the next available candidate. // If this puts us outside of the allowed gender quota, pick the next candidate of the // underrepresented gender instead. int nextCandidateIndex = 0; while (takenCandidates.ContainsKey(nextCandidateIndex)) { nextCandidateIndex++; } PersonGender candidateGender = rawList[nextCandidateIndex].Person.Gender; double currentMaleQuota = CalculateListMaleQuota(result, candidateGender); // Here, we account an extremely rare situation where the correct quota is not even obtainable, e.g. // for position #3 where #1 is male and #2 is female and with a quota of 40%. Either way, it will // fall outside of bounds (33% or 66%). If so, ignore the quota if it is not obtainable. PersonGender oppositeGender = (candidateGender == PersonGender.Male ? PersonGender.Female : PersonGender.Male); double alternateMaleQuota = CalculateListMaleQuota(result, oppositeGender); // If currentMaleQuota is outside of bounds AND the alternate quota IS inside of bounds... if (currentMaleQuota < GenderQuota || currentMaleQuota > (1.0 - GenderQuota)) { if (alternateMaleQuota >= GenderQuota && alternateMaleQuota <= (1.0 - GenderQuota)) { // ...pick the alternate (underrepresented) candidate try { nextCandidateIndex = GetNextSpecificGenderCandidate(rawList, takenCandidates, oppositeGender); } catch (ArgumentOutOfRangeException) { // there isn't any more candidate of the requested gender, so go with what we have } } } result.Add(rawList[nextCandidateIndex]); takenCandidates[nextCandidateIndex] = true; } return result; }