/// <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(); }