Profiles with Ties

Use the ProfileWithTies class to create a profile in which voters may submit strict weak orderings of the candidates, allowing ties, and/or in which voters do not rank all the candidates. To create a profile, specify a list of rankings, the number of candidates, the list of counts for each ranking, and possibly a candidate map (mapping candidates to their names).

from pref_voting.profiles_with_ties import ProfileWithTies

a = "a"
b = "b"
c = "c"

rankings = [
    {a:1, b:1, c:1},
    {a:1, b:2, c:2},
    {a:1, b:2, c:3},
    {a:1, b:1, c:2},
    {a:1, b:1, c:1},
    {a:1, b:1, c:2},
    {a:1, c:1, b:2},
    {c:1, b:1, a:2}
]
rcounts = [1, 2, 1, 4, 1, 2, 1, 1]
prof = ProfileWithTies(rankings, rcounts=rcounts)

prof.display()

print("")
for r,n in zip(prof.rankings, prof.rcounts):
    print(f"{n} voters have the ranking {r}")

# the support of a over b is the number of voters that rank a strictly above b
print("\n")
print(f"support(a, b) = {prof.support(a, b)}")
print(f"support(a, a) = {prof.support(a, a)}")
print(f"support(b, a) = {prof.support(b, a)}")
print(f"support(a, c) = {prof.support(a, c)}")
print(f"support(c, a) = {prof.support(c, a)}")
print(f"support(b, c) = {prof.support(b, c)}")
print(f"support(c, b) = {prof.support(c, b)}")

# the margin of a over b is the number of voters who rank a strictly above b minus
# the number of voters who rank b strictly above a
print("\n")
print(f"margin(a, b) = {prof.margin(a, b)}")
print(f"margin(a, a) = {prof.margin(a, a)}")
print(f"margin(b, a) = {prof.margin(b, a)}")
print(f"margin(a, c) = {prof.margin(a, c)}")
print(f"margin(c, a) = {prof.margin(c, a)}")
print(f"margin(b, c) = {prof.margin(b, c)}")
print(f"margin(c, b) = {prof.margin(c, b)}")

# the ratio of a over b is the support of a over b divided by the support of b over a
print("\n")
print(f"ratio(a, b) = {prof.ratio(a, b)}")
print(f"ratio(a, a) = {prof.ratio(a, a)}")
print(f"ratio(b, a) = {prof.ratio(b, a)}")
print(f"ratio(a, c) = {prof.ratio(a, c)}")
print(f"ratio(c, a) = {prof.ratio(c, a)}")
print(f"ratio(b, c) = {prof.ratio(b, c)}")
print(f"ratio(c, b) = {prof.ratio(c, b)}")
+-------+-----+---+-----+-------+-----+-----+-----+
|   1   |  2  | 1 |  4  |   1   |  2  |  1  |  1  |
+-------+-----+---+-----+-------+-----+-----+-----+
| a b c |  a  | a | a b | a b c | a b | a c | c b |
|       | b c | b |  c  |       |  c  |  b  |  a  |
|       |     | c |     |       |     |     |     |
+-------+-----+---+-----+-------+-----+-----+-----+

1 voters have the ranking ( a  b  c ) 
2 voters have the ranking a ( b  c ) 
1 voters have the ranking a ( b  c ) 
4 voters have the ranking a b c 
1 voters have the ranking ( a  b ) c 
2 voters have the ranking ( a  b ) c 
1 voters have the ranking ( a  b ) c 
1 voters have the ranking ( a  b ) c 


support(a, b) = 4
support(a, a) = 0
support(b, a) = 1
support(a, c) = 9
support(c, a) = 1
support(b, c) = 7
support(c, b) = 1


margin(a, b) = 3
margin(a, a) = 0
margin(b, a) = -3
margin(a, c) = 8
margin(c, a) = -8
margin(b, c) = 6
margin(c, b) = -6


ratio(a, b) = 4.0
ratio(a, a) = 1
ratio(b, a) = 0.25
ratio(a, c) = 9.0
ratio(c, a) = 0.1111111111111111
ratio(b, c) = 7.0
ratio(c, b) = 0.14285714285714285

ProfileWithTies Class

Note

The Ranking class used to the represent the ballots in a ProfileWithTies is described on the [ballots](ballots) page.

class pref_voting.profiles_with_ties.ProfileWithTies(rankings, rcounts=None, candidates=None, cmap=None)[source]

An anonymous profile of (truncated) strict weak orders of \(n\) candidates.

Parameters:
  • rankings (list[dict[int or str: int]] or list[Ranking]) – List of rankings in the profile, where a ranking is either a Ranking object or a dictionary.

  • rcounts (list[int], optional) – List of the number of voters associated with each ranking. Should be the same length as rankings. If not provided, it is assumed that 1 voters submitted each element of rankings.

  • candidates (list[int] or list[str], optional) – List of candidates in the profile. If not provided, this is the list that is ranked by at least on voter.

  • cmap (dict[int: str], optional) – Dictionary mapping candidates (integers) to candidate names (strings). If not provided, each candidate name is mapped to itself.

Example:

The following code creates a profile in which 2 voters submitted the ranking 0 ranked first, 1 ranked second, and 2 ranked third; 3 voters submitted the ranking 1 and 2 are tied for first place and 0 is ranked second; and 1 voter submitted the ranking in which 2 is ranked first and 0 is ranked second:

prof = ProfileWithTies([{0: 1, 1: 2, 2: 3}, {1:1, 2:1, 0:2}, {2:1, 0:2}], [2, 3, 1])
add_unranked_candidates()[source]

Return a profile in which for each voter, any unranked candidate is added to the bottom of their ranking.

anonymize()[source]

Return a profile which is the anonymized version of this profile.

candidates

The candidates in the profile.

cindex_to_cand

Maps candidates to their index in the list of candidates and vice versa.

cmap

The candidate map is a dictionary associating a candidate with the name used when displaying a candidate.

condorcet_loser(curr_cands=None)[source]

Returns the Condorcet loser in the profile restricted to curr_cands if one exists, otherwise return None.

A candidate \(c\) is a Condorcet loser if every other candidate is majority preferred to \(c\).

condorcet_winner(curr_cands=None)[source]

Returns the Condorcet winner in the profile restricted to curr_cands if one exists, otherwise return None.

The Condorcet winner is the candidate that is majority preferred to every other candidate.

copeland_scores(curr_cands=None, scores=(1, 0, -1))[source]

The Copeland scores in the profile restricted to the candidates in curr_cands.

The Copeland score for candidate \(c\) is calculated as follows: \(c\) receives scores[0] points for every candidate that \(c\) is majority preferred to, scores[1] points for every candidate that is tied with \(c\), and scores[2] points for every candidate that is majority preferred to \(c\). The default scores is (1, 0, -1).

Parameters:
  • curr_cands (list[int], optional) – restrict attention to candidates in this list. Defaults to all candidates in the profile if not provided.

  • scores (tuple[int], optional) – the scores used to calculate the Copeland score of a candidate \(c\): scores[0] is for the candidates that \(c\) is majority preferred to; scores[1] is the number of candidates tied with \(c\); and scores[2] is the number of candidate majority preferred to \(c\). The default value is scores = (1, 0, -1)

Returns:

a dictionary associating each candidate in curr_cands with its Copeland score.

cycles()[source]

Return a list of the cycles in the profile.

description()[source]

Return the Python code needed to create the profile.

display(cmap=None, style='pretty', curr_cands=None)[source]

Display a profile (restricted to curr_cands) as an ascii table (using tabulate).

Parameters:
  • cmap (dict[int,str], optional) – the candidate map (overrides the cmap associated with this profile)

  • style (str --- "pretty" or "fancy_grid" (or any other style option for tabulate)) – the candidate map to use (overrides the cmap associated with this profile)

  • curr_cands (list[int], optional) – list of candidates

Return type:

None

Example:

from pref_voting.profiles_with_ties import ProfileWithTies
prof = ProfileWithTies([{0: 1, 1: 2, 2: 3}, {1:1, 2:1, 0:2}, {2:1, 0:2}], [2, 3, 1])
prof.display()
prof.display(cmap={0:"a", 1:"b", 2:"c"})
+---+-----+---+
| 2 |  3  | 1 |
+---+-----+---+
| 0 | 1 2 | 2 |
| 1 |  0  | 0 |
| 2 |     |   |
+---+-----+---+
+---+-----+---+
| 2 |  3  | 1 |
+---+-----+---+
| a | b c | c |
| b |  a  | a |
| c |     |   |
+---+-----+---+
display_margin_graph(cmap=None, curr_cands=None)[source]

Display the margin graph of the profile (restricted to curr_cands) using the cmap. See MarginGraph.

display_rankings()[source]

Display a list of the rankings in the profile.

display_support_graph(cmap=None, curr_cands=None)[source]

Display the support graph of the profile (restricted to curr_cands) using the cmap. See SupportGraph.

dominates(cand, curr_cands=None)[source]

Returns the list of candidates that cand is majority preferred to in the majority graph restricted to curr_cands.

dominators(cand, curr_cands=None)[source]

Returns the list of candidates that are majority preferred to cand in the profile restricted to the candidates in curr_cands.

classmethod from_preflib(instance_or_preflib_file, include_cmap=False)[source]

Convert an preflib OrdinalInstance or file to a Profile. See pref_voting.io.readers.from_preflib.

is_tied(c1, c2)[source]

Returns True if c1 and c2 are tied (i.e., the margin of c1 over c2 is 0).

property is_truncated_linear

Return True if the profile only contains (truncated) linear orders.

is_uniquely_weighted()[source]

Returns True if the profile is uniquely weighted.

A profile is uniquely weighted when there are no 0 margins and all the margins between any two candidates are unique.

majority_graph()[source]

Returns the majority graph of the profile. See MarginGraph.

Example:

from pref_voting.profiles_with_ties import ProfileWithTies
prof = ProfileWithTies([{0: 1, 1: 2, 2: 3}, {1:1, 2:1, 0:2}, {2:1, 0:2}], [2, 3, 1])

mg = prof.majority_graph()
print(mg.edges)
[(1, 0), (1, 2), (2, 0)]
majority_prefers(c1, c2)[source]

Returns True if c1 is majority preferred to c2.

margin(c1, c2)[source]

Returns the margin of candidate c1 over candidate c2, where the margin is the number of voters that rank c1 strictly above c2 minus the number of voters that rank c2 strictly above c1.

margin_graph()[source]

Returns the margin graph of the profile. See MarginGraph.

Example:

from pref_voting.profiles_with_ties import ProfileWithTies
prof = ProfileWithTies([{0: 1, 1: 2, 2: 3}, {1:1, 2:1, 0:2}, {2:1, 0:2}], [2, 3, 1])

mg = prof.margin_graph()
print(mg.edges)
print(mg.margin_matrix)
[(1, 0, 1), (1, 2, 2), (2, 0, 2)]
[[0, -1, -2], [1, 0, 2], [2, -2, 0]]
property margin_matrix

Returns the margin matrix of the profile, where the entry at row i and column j is the margin of candidate i over candidate j.

num_cands

The number of candidates in the profile.

num_voters

The number of voters in the profile.

plurality_scores(curr_cands=None)[source]

Return the Plurality Scores of the candidates, assuming that each voter ranks a single candidate in first place.

Parameters: - curr_cands: List of current candidates to consider. If None, use all candidates.

Returns: - Dictionary with candidates as keys and their plurality scores as values.

Raises: - ValueError: If any voter ranks multiple candidates in first place.

plurality_scores_ignoring_overvotes(curr_cands=None)[source]

Return the Plurality scores ignoring empty rankings and overvotes.

property ranking_types

Return a list of the types of rankings in the profile.

property rankings

Return a list of all individual rankings in the profile.

property rankings_as_dicts_counts

Returns the rankings represented as dictionaries and the counts of each ranking.

property rankings_as_indifference_list

Return a list of all individual rankings as indifference lists in the profile.

property rankings_counts

Returns the rankings and the counts of each ranking.

ranks

The ranks that are possible in the profile.

ratio(c1, c2)[source]

Returns the ratio of the support of c1 over c2 to the support c2 over c1.

classmethod read(filename, file_format='preflib', csv_format='candidate_columns', cand_type=None, items_to_skip=None)[source]

Read a profile from a file. See pref_voting.io.readers.read.

remove_candidates(cands_to_ignore)[source]

Remove all candidates from cands_to_ignore from the profile.

Parameters:

cands_to_ignore (list[int]) – list of candidates to remove from the profile

Returns:

a profile with candidates from cands_to_ignore removed.

Example:

from pref_voting.profiles_with_ties import ProfileWithTies
prof = ProfileWithTies([{0: 1, 1: 2, 2: 3}, {1:1, 2:1, 0:2}, {2:1, 0:2}], [2, 3, 1])
prof.display()
new_prof = prof.remove_candidates([1])
new_prof.display()
print(new_prof.ranks)
+---+-----+---+
| 2 |  3  | 1 |
+---+-----+---+
| 0 | 1 2 | 2 |
| 1 |  0  | 0 |
| 2 |     |   |
+---+-----+---+
+---+---+---+
| 2 | 3 | 1 |
+---+---+---+
| 0 | 2 | 2 |
| 2 | 0 | 0 |
+---+---+---+
[1, 2]
remove_empty_rankings()[source]

Remove the empty rankings from the profile.

report()[source]

Display a report of the types of rankings in the profile.

strength_matrix(curr_cands=None, strength_function=None)[source]

Return the strength matrix of the profile. The strength matrix is a matrix where the entry in row \(i\) and column \(j\) is the number of voters that rank the candidate with index \(i\) over the candidate with index \(j\). If curr_cands is provided, then the strength matrix is restricted to the candidates in curr_cands. If strength_function is provided, then the strength matrix is computed using the strength function.

strict_maj_size()[source]

Returns the strict majority of the number of voters.

support(c1, c2)[source]

Returns the support of candidate c1 over candidate c2, where the support is the number of voters that rank c1 strictly above c2.

support_graph()[source]

Returns the support graph of the profile. See SupportGraph.

Example:

from pref_voting.profiles_with_ties import ProfileWithTies
prof = ProfileWithTies([{0: 1, 1: 2, 2: 3}, {1:1, 2:1, 0:2}, {2:1, 0:2}], [2, 3, 1])

sg = prof.support_graph()
print(sg.edges)
print(sg.s_matrix)
[(1, 0, (3, 2)), (1, 2, (2, 0)), (2, 0, (4, 2))]
[[0, 2, 2], [3, 0, 2], [4, 0, 0]]
to_linear_profile()[source]

Return a linear profile from the profile with ties. If the profile is not a linear profile, then return None.

Note that the candidates in a Profile must be integers, so the candidates in the linear profile will be the indices of the candidates in the original profile.

to_preflib_instance()[source]

Returns an instance of the OrdinalInstance class from the preflibtools package. See pref_voting.io.writers.to_preflib_instance.

tops_scores(curr_cands=None, score_type='approval')[source]

Return the tops scores of the candidates.

Parameters: - curr_cands: List of current candidates to consider. If None, use all candidates. - score_type: Type of tops score to compute. Options are ‘approval’ or ‘split’.

Returns: - Dictionary with candidates as keys and their tops scores as values.

truncate_overvotes()[source]

Return a new profile in which all rankings with overvotes are truncated.

use_extended_strict_preference()[source]

Redefine the supports so that extended strict preferences are used. Using extended strict preference may change the margins between candidates.

use_strict_preference()[source]

Redefine the supports so that strict preferences are used. Using strict preference may change the margins between candidates.

using_extended_strict_preference

A flag indicating whether the profile is using extended strict preferences when calculating supports, margins, etc.

weak_condorcet_winner(curr_cands=None)[source]

Returns a list of the weak Condorcet winners in the profile restricted to curr_cands (which may be empty).

A candidate \(c\) is a weak Condorcet winner if there is no other candidate that is majority preferred to \(c\).

Note

While the Condorcet winner is unique if it exists, there may be multiple weak Condorcet winners.

write(filename, file_format='preflib', csv_format='candidate_columns')[source]

Write a profile to a file. See pref_voting.io.writers.write.