// Not thread safe: writes to nodes. // Only called during constructor. private void AddGraph(PairwiseGraph graph) { foreach (Candidate c in graph.Candidates) { if (!nodes.ContainsKey(c)) { nodes[c] = new Dictionary <Candidate, decimal>(); } } Parallel.ForEach(graph.Candidates, c => { // Merge the graph nodes for this candidate foreach (Candidate d in graph.Candidates) { nodes[c].TryAdd(d, 0.0m); if (graph.nodes[c].ContainsKey(d)) { nodes[c][d] += graph.nodes[c][d]; } } }); // This merger may disturb the graph, so fill in any gaps foreach (Candidate c in Candidates) { if (!nodes.ContainsKey(c)) { nodes[c] = new Dictionary <Candidate, decimal>(); } foreach (Candidate d in Candidates) { if (!nodes[c].Keys.Contains(d)) { nodes[c][d] = 0.0m; } } } }
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 PairwiseGraph(PairwiseGraph graph) { AddGraph(graph); }
/// <summary> /// Merge two PairwiseGraphs. /// </summary> /// <param name="g1">Graph 1</param> /// <param name="g2">Graph 2</param> public PairwiseGraph(PairwiseGraph g1, PairwiseGraph g2) { AddGraph(g1); AddGraph(g2); }
public TopCycle(PairwiseGraph graph, TopCycleSets set = TopCycleSets.smith) { defaultSet = set; this.graph = graph; }