Other Methods

Absolute Majority

pref_voting.other_methods.absolute_majority(profile, curr_cands=None)[source]

The absolute majority winner is the candidate with a strict majority of first place votes. Returns an empty list if there is no candidate with a strict majority of first place votes. Otherwise returns the absolute majority winner in the profile restricted to curr_cands.

..note:

The term ‘absolute majority’ for this voting method comes from Charles Dodgson’s famous pamplet of 1873, “A Discussion of the Various Methods of Procedure in Conducting Elections” (see I. McLean and A. Urken, Classics of Social Choice, 1995, p. 281, or A. D. Taylor, “Social Choice and the Mathematics of Manipulation,” 2005, p. 11).

Parameters:
  • profile (Profile) – An anonymous profile of linear orders on a set of candidates

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

Returns:

A sorted list of candidates

Important

Formally, this is not a voting method since the function might return an empty list (when there is no candidate with a strict majority of first place votes). Also, if there is an absolute majority winner, then that winner is unique.

Example:
from pref_voting.profiles import Profile
from pref_voting.other_methods import absolute_majority

prof1 = Profile([[0, 1, 2], [1, 0, 2], [2, 1, 0]], [3, 1, 2])
prof1.display()
absolute_majority.display(prof1)

prof2 = Profile([[0, 1, 2], [1, 0, 2], [1, 2, 0]], [5, 1, 2])
prof2.display()
absolute_majority.display(prof2)
+---+---+---+
| 3 | 1 | 2 |
+---+---+---+
| 0 | 1 | 2 |
| 1 | 0 | 1 |
| 2 | 2 | 0 |
+---+---+---+
Absolute Majority winners are {}
+---+---+---+
| 5 | 1 | 2 |
+---+---+---+
| 0 | 1 | 1 |
| 1 | 0 | 2 |
| 2 | 2 | 0 |
+---+---+---+
Absolute Majority winner is {0}

Kemeny-Young

pref_voting.other_methods.kemeny_young(edata, curr_cands=None, algorithm='marginal')[source]

A Kemeny-Young ranking is a ranking that maximizes the sum of the margins of pairs of candidates in the ranking. Equivalently, a Kemeny-Young ranking is a ranking that minimizes the sum of the Kendall tau distances to the voters’ rankings. The Kemeny-Young winners are the candidates that are ranked first by some Kemeny-Young ranking.

Parameters:
  • edata (Profile, ProfileWithTies, MarginGraph) – Any election data that has a margin method.

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

  • algorithm (str, optional) – The algorithm to use. Options are “marginal” and “Kendall tau”. If “marginal” is used, then the Kemeny-Young rankings are computed by finding the sum of the margins of each pair of candidates in the ranking. If “Kendall tau” is used, then the Kemeny-Young rankings are computed by summing the Kendall tau distances to the voters’ rankings. Default is “marginal”.

Returns:

A sorted list of candidates

Example:
from pref_voting.profiles import Profile
from pref_voting.other_methods import kemeny_young, kemeny_young_rankings

prof1 = Profile([[0, 1, 2], [1, 0, 2], [2, 1, 0]], [3, 1, 2])
prof1.display()
kyrs, d = kemeny_young_rankings(prof1)
print(f"Minimal distance: {d}")
for kyr in kyrs:
    print(f"ranking: {kyr}")
kemeny_young.display(prof1)

prof2 = Profile([[0, 1, 2], [1, 0, 2], [1, 2, 0]], [5, 1, 2])
prof2.display()
kyrs, d = kemeny_young_rankings(prof2)
print(f"Minimal distance: {d}")
for kyr in kyrs:
    print(f"ranking: {kyr}")
kemeny_young.display(prof2)
+---+---+---+
| 3 | 1 | 2 |
+---+---+---+
| 0 | 1 | 2 |
| 1 | 0 | 1 |
| 2 | 2 | 0 |
+---+---+---+
Minimal distance: 7
ranking: (0, 1, 2)
ranking: (1, 0, 2)
Kemeny-Young winners are {0, 1}
+---+---+---+
| 5 | 1 | 2 |
+---+---+---+
| 0 | 1 | 1 |
| 1 | 0 | 2 |
| 2 | 2 | 0 |
+---+---+---+
Minimal distance: 5
ranking: (0, 1, 2)
Kemeny-Young winner is {0}

Kemeny-Young Rankings

pref_voting.other_methods.kemeny_young_rankings(profile, curr_cands=None)[source]

A Kemeny-Young ranking is a ranking that minimizes the sum of the Kendall tau distances to the voters’ rankings.

Parameters:
  • profile (Profile) – An anonymous profile of linear orders on a set of candidates

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

Returns:

A list of Kemeny-Young rankings.

dist: The minimum distance of the Kemeny-Young rankings.

Return type:

rankings

Example:
from pref_voting.profiles import Profile
from pref_voting.other_methods import kemeny_young, kemeny_young_rankings

prof1 = Profile([[0, 1, 2], [1, 0, 2], [2, 1, 0]], [3, 1, 2])
prof1.display()
kyrs, d = kemeny_young_rankings(prof1)
print(f"Minimal distance: {d}")
for kyr in kyrs:
    print(f"ranking: {kyr}")

prof2 = Profile([[0, 1, 2], [1, 0, 2], [1, 2, 0]], [5, 1, 2])
prof2.display()
kyrs, d = kemeny_young_rankings(prof2)
print(f"Minimal distance: {d}")
for kyr in kyrs:
    print(f"ranking: {kyr}")
+---+---+---+
| 3 | 1 | 2 |
+---+---+---+
| 0 | 1 | 2 |
| 1 | 0 | 1 |
| 2 | 2 | 0 |
+---+---+---+
Minimal distance: 7
ranking: (0, 1, 2)
ranking: (1, 0, 2)
+---+---+---+
| 5 | 1 | 2 |
+---+---+---+
| 0 | 1 | 1 |
| 1 | 0 | 2 |
| 2 | 2 | 0 |
+---+---+---+
Minimal distance: 5
ranking: (0, 1, 2)

Preliminary Weighted Condorcet

pref_voting.other_methods.preliminary_weighted_condorcet(prof, curr_cands=None, show_orders=False, require_positive_plurality_score=False)[source]

The preliminary version of the Weighted Condorcet Rule in Tideman’s book, Collective Decisions and Voting (p. 223). The winners are the candidates ranked first by some linear order of the candidates with highest score, where the score of an order (c_1,…,c_n) is the sum over all i<j of the margin of c_i vs. c_j multiplied by the plurality scores of c_i and c_j.

The multiplication by plurality scores is what distinguishes this method from the Kemeny-Young method.

Tideman (p. 224) defines a more complicated Weighted Condorcet rule that is intended to be used when some candidates receive zero first-place votes.

Parameters:
  • prof (Profile) – An anonymous profile of linear orders on a set of candidates

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

  • show_orders (bool) – If True, then print the set of best orders.

  • require_positive_plurality_score (bool) – If True, then require that all candidates have a positive plurality score.

Returns:

A sorted list of candidates

Bucklin

pref_voting.other_methods.bucklin(profile, curr_cands=None)[source]

If a candidate has a strict majority of first-place votes, then that candidate is the winner. If no such candidate exists, then check the candidates that are ranked first or second. If a candidate has a strict majority of first- or second-place voters, then that candidate is the winner. If no such winner is found move on to the 3rd, 4th, etc. place votes. Return the candidates with the greatest overall score.

Parameters:
  • profile (Profile) – An anonymous profile of linear orders on a set of candidates

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

Returns:

A sorted list of candidates

Example:

from pref_voting.profiles import Profile
from pref_voting.other_methods import bucklin

prof = Profile([[1, 0, 2], [0, 2, 1], [0, 1, 2]], [2, 1, 1])

prof.display()
bucklin.display(prof)
+---+---+---+
| 2 | 1 | 1 |
+---+---+---+
| 1 | 0 | 0 |
| 0 | 2 | 1 |
| 2 | 1 | 2 |
+---+---+---+
Bucklin winner is {0}

Bucklin with Explanation

pref_voting.other_methods.bucklin_with_explanation(profile, curr_cands=None)[source]

Return the Bucklin winners and the score for each candidate.

Parameters:
  • profile (Profile) – An anonymous profile of linear orders on a set of candidates

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

Returns:

A sorted list of candidates

A dictionary assigning the score for each candidate.

Example:

from pref_voting.profiles import Profile
from pref_voting.other_methods import bucklin_with_explanation

prof = Profile([[1, 0, 2], [0, 2, 1], [0, 1, 2]], [2, 1, 1])

prof.display()
sb_ws, scores = bucklin_with_explanation(prof)

print(f"The winners are {sb_ws}")
print(f"The candidate scores are {scores}")
+---+---+---+
| 2 | 1 | 1 |
+---+---+---+
| 1 | 0 | 0 |
| 0 | 2 | 1 |
| 2 | 1 | 2 |
+---+---+---+
The winners are [0]
The candidate scores are {0: 4, 1: 3, 2: 1}

Simplified Bucklin

pref_voting.other_methods.simplified_bucklin(profile, curr_cands=None)[source]

If a candidate has a strict majority of first-place votes, then that candidate is the winner. If no such candidate exists, then check the candidates that are ranked first or second. If a candidate has a strict majority of first- or second-place voters, then that candidate is the winner. If no such winner is found move on to the 3rd, 4th, etc. place votes.

Parameters:
  • profile (Profile) – An anonymous profile of linear orders on a set of candidates

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

Returns:

A sorted list of candidates

Example:

from pref_voting.profiles import Profile
from pref_voting.other_methods import simplified_bucklin

prof = Profile([[1, 0, 2], [0, 2, 1], [0, 1, 2]], [2, 1, 1])

prof.display()
simplified_bucklin.display(prof)
+---+---+---+
| 2 | 1 | 1 |
+---+---+---+
| 1 | 0 | 0 |
| 0 | 2 | 1 |
| 2 | 1 | 2 |
+---+---+---+
Simplified Bucklin winners are {0, 1}

Simplified Bucklin with Explanation

pref_voting.other_methods.simplified_bucklin_with_explanation(profile, curr_cands=None)[source]

Return the Simplified Bucklin winners and the score for each candidate.

Parameters:
  • profile (Profile) – An anonymous profile of linear orders on a set of candidates

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

Returns:

A sorted list of candidates

A dictionary assigning the score for each candidate.

Example:

from pref_voting.profiles import Profile
from pref_voting.other_methods import simplified_bucklin_with_explanation

prof = Profile([[1, 0, 2], [0, 2, 1], [0, 1, 2]], [2, 1, 1])

prof.display()
sb_ws, scores = simplified_bucklin_with_explanation(prof)

print(f"The winners are {sb_ws}")
print(f"The candidate scores are {scores}")
+---+---+---+
| 2 | 1 | 1 |
+---+---+---+
| 1 | 0 | 0 |
| 0 | 2 | 1 |
| 2 | 1 | 2 |
+---+---+---+
The winners are [0, 1]
The candidate scores are {0: 4, 1: 3, 2: 1}

Weighted Bucklin

pref_voting.other_methods.weighted_bucklin(profile, curr_cands=None, strict_threshold=False, score=<function <lambda>>)[source]

The Weighted Bucklin procedure, studied by D. Marc Kilgour, Jean-Charles Grégoire, and Angèle Foley. The k-th Weighted Bucklin score of a candidate c is the sum for j leq k of the product of score(num_cands,j) and the number of voters who rank c in j-th place. Compute higher-order Weighted Bucklin scores until reaching a k such that some candidate’s k-th Weighted Bucklin score is at least half the number of voters (or the strict majority size if strict_threshold = True). Then return the candidates with maximal k-th Weighted Bucklin score. Bucklin is the special case where strict_threshold = True and score = lambda num_cands, rank: 1.

Parameters:
  • profile (Profile) – An anonymous profile of linear orders on a set of candidates

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

  • strict_threshold – If True, makes the threshold for the Bucklin procedure the strict majority size; otherwise threshold is half the number of voters, following Kilgour et al.

  • score (function) – A function that accepts two parameters num_cands (the number of candidates) and rank (a rank of a candidate) used to calculate the score of a candidate. The default score function is the normalized version of the classic Borda score vector.

Returns:

A sorted list of candidates

Example:

from pref_voting.profiles import Profile
from pref_voting.other_methods import weighted_bucklin

prof = Profile([[1, 0, 2], [0, 2, 1], [0, 1, 2]], [2, 1, 1])

prof.display()
weighted_bucklin.display(prof)
+---+---+---+
| 2 | 1 | 1 |
+---+---+---+
| 1 | 0 | 0 |
| 0 | 2 | 1 |
| 2 | 1 | 2 |
+---+---+---+
Weighted Bucklin winners are {0, 1}

Bracket Voting

pref_voting.other_methods.bracket_voting(profile, curr_cands=None, seed=None)[source]

The candidates with the top four plurality scores are seeded into a bracket: the candidate with the highest plurality score is seeded 1st, the candidate with the second highest plurality score is seeded 2nd, etc. The 1st seed faces the 4th seed in a head-to-head match decided by majority rule, and the 2nd seed faces the 3rd seed in a head-to-head match decided by majority rule. The winners of these two matches face each other in a final head-to-head match decided by majority rule. The winner of the final is the winner of the election.

Note

A version of bracket voting as proposed by Edward B. Foley. This is a probabilistic method that always returns a unique winner. Ties are broken using a random tie breaking ordering of the candidates.

Parameters:
  • profile (Profile) – An anonymous profile of linear orders on a set of candidates

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

  • seed (int, optional) – The seed for the random tie breaking ordering of the candidates.

Returns:

A sorted list of candidates

Superior Voting

pref_voting.other_methods.superior_voting(profile, curr_cands=None)[source]

One candidate is superior to another if more ballots rank the first candidate above the second than vice versa. A candidate earns a point from a ballot if they are ranked first on that ballot or they are superior to the candidate ranked first on that ballot. The candidate with the most points wins.

Note

Devised by Wesley H. Holliday as a simple Condorcet-compliant method for political elections. Always elects a Condorcet winner if one exists and elects only the Condorcet winner provided the Condorcet winner receives at least one first-place vote. Edward B. Foley suggested the name ‘Superior Voting’ because the method is based on the idea that if A is superior to B, then A should get B’s first-place votes added to their own.

Parameters:
  • profile (Profile) – An anonymous profile of linear orders on a set of candidates

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

Returns:

A sorted list of candidates

Bradley-Terry

pref_voting.other_methods.bradley_terry(prof, curr_cands=None, threshold=1e-05)[source]

The Bradley-Terry model is a probabilistic model for pairwise comparisons. In this model, the probability that a voter prefers candidate i to candidate j is given by p_{i,j} = v_i / (v_i + v_j), where v_i is the strength of candidate i. Given a profile, we take p_{i,j} to be the proportion of voters who prefer candidate i to candidate j. We then estimate the strength of each candidate using maximum likelihood estimation. The winning candidates are those whose estimated strength is within +/- threshold of the maximum strength.

Note

For profiles of linear ballots, this is equivalent to Borda (see Theorem 3.1 of https://arxiv.org/abs/2312.08358).

Parameters:
  • profile (Profile) – An anonymous profile of linear orders on a set of candidates

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

  • threshold (float, optional) – The threshold for determining the winners. The winners are those whose estimated strength is within +/- threshold of the maximum strength.

Returns:

A sorted list of candidates

pref_voting.other_methods.bradley_terry_ranking(prof, curr_cands=None, threshold=1e-05)[source]

The Bradley-Terry model is a probabilistic model for pairwise comparisons. In this model, the probability that a voter prefers candidate i to candidate j is given by p_{i,j} = v_i / (v_i + v_j), where v_i is the strength of candidate i. Given a profile, we take p_{i,j} to be the proportion of voters who prefer candidate i to candidate j. We then estimate the strength of each candidate using maximum likelihood estimation. Finally, the candidates are ranked in decreasing order of their estimated strength (where candidates whose estimated strength is within +/- threshold of each other are considered tied).

Note

For profiles of linear ballots, this is equivalent to Borda (see Theorem 3.1 of https://arxiv.org/abs/2312.08358).

Parameters:
  • profile (Profile) – An anonymous profile of linear orders on a set of candidates

  • curr_cands (List[int], optional) – If set, then find the winners for the profile restricted to the candidates in curr_cands

  • threshold (float, optional) – The threshold for equivalence classes of candidates.

Returns:

A Ranking object.