/// <inheritdoc/> protected override void InitializeTabulation(BallotSet ballots, IEnumerable <Candidate> withdrawn, int seats) { base.InitializeTabulation(ballots, withdrawn, seats); RankedTabulationAnalytics analytics; analytics = new RankedTabulationAnalytics(ballots, seats); batchEliminator = new RunoffBatchEliminator(analytics, seats); }
protected override void InitializeTabulation(BallotSet ballots, IEnumerable <Candidate> withdrawn, int seats) { base.InitializeTabulation(ballots, withdrawn, seats); RankedTabulationAnalytics analytics; analytics = new RankedTabulationAnalytics(ballots, seats); batchEliminator = new TidemansAlternativeBatchEliminator(analytics, seats, condorcetSet, retainSet); }
/// <summary> /// Initialize the tabulation state from a set of bandidates, withdrawn candidates, and a number of seats. /// </summary> /// <param name="ballots">The ballots to tabulate.</param> /// <param name="withdrawn">Candidates excluded from tabulation.</param> /// <param name="seats">The number of seats to elect.</param> protected virtual void InitializeTabulation(BallotSet ballots, IEnumerable <Candidate> withdrawn, int seats) { this.seats = seats; this.ballots = ballots; candidateStates.Clear(); if (!(withdrawn is null)) { InitializeCandidateStates(withdrawn, CandidateState.States.withdrawn); } // Initialize hopefuls InitializeCandidateStates(ballots.SelectMany(x => x.Votes.Select(y => y.Candidate)).Distinct().Except(candidateStates.Keys)); tiebreaker = tiebreakerFactory.CreateTiebreaker(mediator); }
/// <summary> /// Performs a complete tabulation of given ballots. /// </summary> /// <param name="ballots">The ballots to tabulate.</param> /// <param name="withdrawn">Candidates withdrawn from the election. Any votes for these candidates are ignored.</param> /// <param name="seats">The number of winners to elect.</param> public void Tabulate(BallotSet ballots, IEnumerable <Candidate> withdrawn = null, int seats = 1) { TabulationStateEventArgs state; TabulationDetailsEventArgs tabulationDetails; if (seats < 1) { throw new ArgumentOutOfRangeException("seats", "seats must be at least one."); } // Count() throws ArgumentNullException when ballots is null if (ballots.TotalCount() < 1) { throw new ArgumentOutOfRangeException("ballots", "Require at least one ballot"); } InitializeTabulation(ballots, withdrawn, seats); tabulationDetails = new TabulationDetailsEventArgs { Ballots = ballots, CandidateStates = CandidateStatesCopy, Note = null, Seats = seats }; mediator.BeginTabulation(tabulationDetails); do { CountBallots(); state = TabulateRound(); // Make copies of candidateStates to prevent errors if written to by client code mediator.CompleteRound(state); // The check is at the end so we can fill our candidate roster } while (!IsComplete()); // Perform a final count CountBallots(); mediator.CompleteTabulation(CandidateStatesCopy); }
static void Main(string[] args) { AbstractBallotStorage s = new DavidHillFormat(); FileStream file; List <string> winners = new List <string>(); HashSet <Candidate> candidates = new HashSet <Candidate>(); TopCycle t; BallotSet bset = null; int smithSetCount = 0; for (int j = 0; j < 1000; j++) { winners.Clear(); candidates.Clear(); bset = null; List <BallotSet> bsets = new List <BallotSet>(); bsets.Clear(); if (bset is null) { using (file = new FileStream(args[0], FileMode.Open)) { bset = s.LoadBallots(file); } } for (int i = 0; i < 1000; i++) { bsets.Add(bset); //GC.Collect(2, GCCollectionMode.Forced, true, true); } bset = s.ballotFactory.MergeBallotSets(bsets); PairwiseGraph g = new PairwiseGraph(bset); t = new TopCycle(g); foreach (Ballot b in bset) { foreach (Vote v in b.Votes) { candidates.Add(v.Candidate); } } foreach (Candidate c in t.GetTopCycle(new List <Candidate>(), TopCycle.TopCycleSets.smith)) { winners.Add(c.Name); } Console.Write(@"""{0}"" ""smith set"" {1}", args[0], winners.Count()); foreach (string w in winners) { Console.Write(@" ""{0}""", w); } Console.Write("\n"); smithSetCount = winners.Count(); winners.Clear(); foreach (Candidate c in t.GetTopCycle(new List <Candidate>(), TopCycle.TopCycleSets.schwartz)) { winners.Add(c.Name); } if (winners.Count() != smithSetCount) { Console.Write(@"""{0}"" ""schwartz set"" {1}", args[0], winners.Count()); foreach (string w in winners) { Console.Write(@" ""{0}""", w); } Console.Write("\n"); } foreach (Candidate c in candidates) { break; foreach (var v in g.Losses(c)) { Console.WriteLine("{0} defeated by {1}\t{2}:{3}", c.Name, v.Name, g.GetVoteCount(c, v).v1, g.GetVoteCount(c, v).v2); } foreach (var v in g.Ties(c)) { Console.WriteLine("{0} ties with {1}\t{2}:{3}", c.Name, v.Name, g.GetVoteCount(c, v).v1, g.GetVoteCount(c, v).v2); } } } }
// Reference rule A: Initialize candidate states protected override void InitializeTabulation(BallotSet ballots, IEnumerable <Candidate> withdrawn, int seats) { base.InitializeTabulation(ballots, withdrawn, seats); }
public RankedTabulationAnalytics(BallotSet ballots, int seats = 1) : base(ballots, seats) { topCycle = new TopCycle(ballots); pairwiseGraph = null; }
/// <summary> /// Converts a set of candidates and ballots to a graph of wins and ties. /// </summary> /// <param name="ballots">Ranked ballots in the election.</param> public PairwiseGraph(BallotSet ballots) { // Initialize candidate graph HashSet <Candidate> candidates = (ballots as IEnumerable <CountedBallot>).SelectMany(x => x.Votes.Select(y => y.Candidate)).ToHashSet(); foreach (Candidate c in candidates) { nodes[c] = new Dictionary <Candidate, decimal>(); foreach (Candidate d in candidates.Except(new[] { c })) { nodes[c][d] = 0.0m; } } void BuildGraph() { List <CountedBallot> bList = ballots.ToList(); int threadCount = Environment.ProcessorCount; PairwiseGraph[] subsets = new PairwiseGraph[threadCount]; PairwiseGraph CountSubsets(int start, int end) { PairwiseGraph g = new PairwiseGraph(); foreach (Candidate c in candidates) { g.nodes[c] = new Dictionary <Candidate, decimal>(); foreach (Candidate d in candidates.Except(new[] { c })) { g.nodes[c][d] = 0.0m; } } // Iterate each ballot and count who wins and who ties. // This can support tied ranks and each ballot is O(SUM(1..n)) and o(n). //foreach (CountedBallot b in ballots) for (int i = start; i <= end; i++) { CountedBallot b = bList[i]; HashSet <Candidate> ranked = b.Votes.Select(x => x.Candidate).ToHashSet(); HashSet <Candidate> unranked = candidates.Except(ranked).ToHashSet(); // Iterate to compare each pair. Stack <Vote> votes = new Stack <Vote>(b.Votes); while (votes.Count > 0) { Vote v = votes.Pop(); foreach (Vote u in votes) { // Who is ranked first? No action if a tie. if (v.Beats(u)) { g.nodes[v.Candidate][u.Candidate] += b.Count; } else if (u.Beats(v)) { g.nodes[u.Candidate][v.Candidate] += b.Count; } } // Defeat all unranked candidates foreach (Candidate c in unranked) { g.nodes[v.Candidate][c] += b.Count; } } } return(g); } // First divide all the processes up for background run Parallel.For(0, threadCount, (i, state) => subsets[i] = CountSubsets(bList.Count() * i / threadCount, (bList.Count() * (i + 1) / threadCount) - 1)); // Add them all together foreach (PairwiseGraph g in subsets) { AddGraph(g); } } BuildGraph(); }
public AbstractTabulationAnalytics(BallotSet ballots, int seats = 1) { }
public TopCycle(BallotSet ballots, TopCycleSets set = TopCycleSets.smith) : this(new PairwiseGraph(ballots)) { }