Beispiel #1
0
        private static (List <(int candidate, ulong?preferred)> Candidates, ulong Bogeyman) GetApprovedCandidates(CoalitionBeatMatrix beatMatrix, RankedBallot ballot)
        {
            var candidates = new List <(int candidate, ulong?preferred)>();
            var ranking    = ballot.Ranking;

            // Approve of the each candidate `c` which is a first choice.
            foreach (var c in ranking[0])
            {
                candidates.Add((c, null));
            }

            // With fewer than three ranks, no bogeymen can chance one's preferences.
            if (ranking.Count < 3)
            {
                return(candidates, 0ul);
            }

            // Then, for each candidate `b` (the "bogeyman") ranked third or below,
            // compute the smallest "coalition" of candidates `c` which can beat each potential "bogeyman" `b`,
            // or includes all candidates one likes better than `b`, whichever comes first.
            // Approve of each member of the smallest coalition to beat all bogeymen.
            var coalition         = GetCoalition(ranking[0]);
            var potentialBogeymen = ranking
                                    .Skip(2)
                                    .SelectMany(b => b)
                                    .Where(b => beatMatrix.Beats(coalition, b) != true)
                                    .ToList();

            if (!potentialBogeymen.Any())
            {
                return(candidates, 0ul);
            }

            foreach (var tier in ranking.Skip(1).Take(ranking.Count - 2))
            {
                var greaterBogeymen = potentialBogeymen.Where(b => !tier.Contains(b)).ToList();

                // If this tier contains all the bogeymen, the previous tier is where our approval stops.
                if (!greaterBogeymen.Any())
                {
                    break;
                }

                // Otherwise, enlist the help of the lesser bogeymen to beat the greater bogeymen.
                foreach (var c in tier)
                {
                    candidates.Add((c, coalition));
                }

                coalition |= GetCoalition(tier);

                var remainingBogeymen = greaterBogeymen
                                        .Where(b => beatMatrix.Beats(coalition, b))
                                        .ToList();

                // Huzzah! We have beaten all the bogeymen!
                if (!remainingBogeymen.Any())
                {
                    break;
                }

                // Otherwise, check the next teir for potential coalition-mates.
                potentialBogeymen = remainingBogeymen;
            }

            return(candidates, GetCoalition(potentialBogeymen));
        }
Beispiel #2
0
        public override ElectionResults GetElectionResults(CandidateComparerCollection <RankedBallot> ballots)
        {
            var approvalCount = new int[ballots.CandidateCount];
            var firstChoices  = new int[ballots.CandidateCount];
            var compromises   = new CountedList <(int Compromise, ulong Preferred, ulong Bogeymen)>();

            // First, compute "coalition" beat matrix
            var beatMatrix = new CoalitionBeatMatrix(ballots);

            // Then, use it to determine which candidates each ballot approves of.
            foreach (var(ballot, count) in ballots.Comparers)
            {
                var(approvedCandidates, bogeymen) = GetApprovedCandidates(beatMatrix, ballot);
                foreach (var(candidate, preferred) in approvedCandidates)
                {
                    approvalCount[candidate] += count;

                    if (preferred.HasValue)
                    {
                        compromises.Add((candidate, preferred.Value, bogeymen), count);
                    }
                    else
                    {
                        firstChoices[candidate] += count;
                    }
                }
            }

            var results = new ElectionResults(approvalCount.IndexRanking());

            results.AddHeading("Votes");
            results.AddTable(
                approvalCount.IndexOrderByDescending()
                .Select(c => new ElectionResults.Value[] {
                (ElectionResults.Candidate)c,
                approvalCount[c],
                firstChoices[c],
                approvalCount[c] - firstChoices[c],
            }),
                "Total",
                "First",
                "Comp.");

            results.AddHeading("Compromises");
            results.AddTable(
                compromises.Select(c => new ElectionResults.Value[] {
                (ElectionResults.Candidate)c.Item.Compromise,
                c.Item.Preferred,
                c.Item.Bogeymen,
                c.Count
            }),
                "Comp.",
                "Pref.",
                "Bogey",
                "Count"
                );

            beatMatrix.AddDetails(results);

            return(results);
        }