Esempio n. 1
0
            // A ballot supports a bogeyman over a coalition if there are any candidates in the coalition one likes worse than the bogeyman.
            // A ballot remains neutral between a bogeyman and a coalition if:
            //  (a) it considers the bogeyman equivalent to any of the coalition-membmers, or
            //  (b) There exists a smaller coalition consisting solely of candidates one prefers to those of the coalition which beats the bogeyman.
            // Oterwise, the ballot supports the coalition over the bogeyman.
            private int GetSupportForCoalition(RankedBallot ballot, ulong coalition, int bogeyman)
            {
                var ranking      = ballot.Ranking;
                var bogeymanTier = ranking.IndexesWhere(tier => tier.Contains(bogeyman)).Single();

                // Detract support for any coalition containing someone we like less than the bogeyman.
                if ((GetCoalition(ranking.Skip(bogeymanTier + 1).SelectMany(tier => tier)) & coalition) > 0ul)
                {
                    return(-1);
                }

                // Remain neutral on any coalition containing someone we like the same as the bogeyman.
                if ((GetCoalition(ranking[bogeymanTier]) & coalition) > 0ul)
                {
                    return(0);
                }

                var preferredCoalition = 0ul;

                foreach (var tier in ranking.Take(bogeymanTier))
                {
                    // Support each coalition which is a subset of our preferred candidates.
                    preferredCoalition |= GetCoalition(tier);
                    if ((preferredCoalition | coalition) == preferredCoalition)
                    {
                        return(1);
                    }

                    // Remain neutral on the coalition if there exists a sub-coalition (without cycles) consisting of only preferred candidates which will work as well
                    if (Beats(preferredCoalition, bogeyman))
                    {
                        return(0);
                    }
                }

                throw new InvalidOperationException("There is a bug: We ought to have found a coalition which is a subset by now.");
            }
Esempio n. 2
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));
        }