ProfileOrdinal

class poisson_approval.ProfileOrdinal(d_ranking_share, d_weak_order_share=None, normalization_warning=True, well_informed_voters=True, ratio_fanatic=0, voting_rule='Approval', symbolic=False)[source]

An ordinal profile of preference.

Parameters
  • d_ranking_share (dict) – E.g. {'abc': 0.4, 'cab': 0.3}. d_ranking_share['abc'] is the probability that a voter prefers candidate a, then candidate b, then candidate c.

  • d_weak_order_share (dict) – E.g. {'a~b>c': 0.2, 'a>b~c': 0.1}. d_weak_order_share['a~b>c'] is the probability that a voter likes candidates a and b equally and prefer them to candidate c.

  • normalization_warning (bool) – Whether a warning should be issued if the input distribution is not normalized.

  • well_informed_voters (bool) – If True (default), it is the usual model. If False, voters “see” only the candidates’ expected scores and believe that the scores follow independent Poisson distributions. This option has an effect only for Approval (neither for Plurality nor Anti-plurality).

  • ratio_fanatic (Number) – The ratio of fanatic voters, in the interval [0, 1]. This is used for tau().

  • voting_rule (str) – The voting rule. Possible values are APPROVAL, PLURALITY and ANTI_PLURALITY.

  • symbolic (bool) – Whether the computations are symbolic or numeric.

Notes

If the input distribution d_ranking_share is not normalized, the profile will be normalized anyway and a warning will be issued (unless normalization_warning is False).

Examples

>>> from fractions import Fraction
>>> profile = ProfileOrdinal({'abc': Fraction(1, 10), 'bac': Fraction(6, 10), 'cab': Fraction(3, 10)})
>>> profile
ProfileOrdinal({'abc': Fraction(1, 10), 'bac': Fraction(3, 5), 'cab': Fraction(3, 10)})
>>> print(profile)
<abc: 1/10, bac: 3/5, cab: 3/10> (Condorcet winner: b)
>>> profile.abc
Fraction(1, 10)
>>> profile.d_ranking_share['abc']  # Alternate syntax for profile.abc
Fraction(1, 10)
>>> profile.weighted_maj_graph
array([[0, Fraction(-1, 5), Fraction(2, 5)],
       [Fraction(1, 5), 0, Fraction(2, 5)],
       [Fraction(-2, 5), Fraction(-2, 5), 0]], dtype=object)
>>> profile.condorcet_winners
Winners({'b'})
>>> profile.is_profile_condorcet
1.0
>>> profile.has_majority_favorite  # Is one candidate 'top' in a majority of ballots?
True
>>> profile.has_majority_ranking  # Does one ranking represent a majority of ballots?
True
>>> profile.is_single_peaked  # Is the profile single-peaked?
True
>>> profile.support_in_rankings
{'abc', 'bac', 'cab'}
>>> profile.is_generic_in_rankings  # Are all rankings there?
False
>>> profile.analyzed_strategies_ordinal
Equilibria:
<abc: a, bac: b, cab: ac> ==> b (FF)
<abc: a, bac: ab, cab: c> ==> a (D)

Utility-dependent equilibrium:
<abc: ab, bac: b, cab: c> ==> b (FF)

Non-equilibria:
<abc: a, bac: b, cab: c> ==> b (FF)
<abc: a, bac: ab, cab: ac> ==> a (D)
<abc: ab, bac: b, cab: ac> ==> b (FF)
<abc: ab, bac: ab, cab: c> ==> a, b (FF)
<abc: ab, bac: ab, cab: ac> ==> a (D)
>>> print(profile.analyzed_strategies_ordinal.equilibria[0])
<abc: a, bac: b, cab: ac> ==> b
>>> print(profile.analyzed_strategies_ordinal.winners_at_equilibrium)
a, b

The profile can include weak orders:

>>> from fractions import Fraction
>>> profile = ProfileOrdinal({'abc': Fraction(1, 10), 'bac': Fraction(6, 10)},
...                          d_weak_order_share={'c>a~b': Fraction(3, 10)})
>>> profile
ProfileOrdinal({'abc': Fraction(1, 10), 'bac': Fraction(3, 5)}, d_weak_order_share={'c>a~b': Fraction(3, 10)})
>>> print(profile)
<abc: 1/10, bac: 3/5, c>a~b: 3/10> (Condorcet winner: b)
property abc

Share of voters with this ranking.

Type

Number

property acb

Share of voters with this ranking.

Type

Number

analyzed_strategies(strategies)

Analyze a list of strategies for the profile.

Parameters

strategies (iterable) – An iterator of strategies, such as a list of strategies.

Returns

The analyzed strategies of the profile.

Return type

AnalyzedStrategies

Examples

Cf. ProfileOrdinal.analyzed_strategies_ordinal().

property analyzed_strategies_group

Analyzed group strategies.

Cf. analyzed_strategies() and strategies_group. This is implemented only for profiles where we consider that there is a natural notion of group, such as ProfileNoisyDiscrete.

Type

AnalyzedStrategies

property analyzed_strategies_ordinal

Analyzed ordinal strategies.

Cf. analyzed_strategies() and strategies_ordinal.

Type

AnalyzedStrategies

property analyzed_strategies_pure

Analyzed pure strategies.

Cf. analyzed_strategies() and strategies_pure. This is implemented only for discrete profiles such as ProfileTwelve or ProfileDiscrete.

Type

AnalyzedStrategies

property bac

Share of voters with this ranking.

Type

Number

property bca

Share of voters with this ranking.

Type

Number

best_responses_to_strategy(tau, ratio_optimistic=Fraction(1, 2))

Convert best responses to a StrategyThreshold.

Parameters
  • tau (TauVector) – Tau-vector.

  • ratio_optimistic – The value of ratio_optimistic to use. Default: 1/2.

Returns

The conversion of the best responses into a strategy. Only the rankings present in this profile are mentioned in the strategy.

Return type

StrategyThreshold

property cab

Share of voters with this ranking.

Type

Number

property cba

Share of voters with this ranking.

Type

Number

property condorcet_winners

Condorcet winner(s).

Type

Winners

property contains_rankings

Whether the profile contains some rankings.

Type

bool

property contains_weak_orders

Whether the profile contains some weak orders.

Type

bool

property d_ballot_share_weak_voters_fanatic

Ballot shares due to the weak orders if they vote fanatically.

Voters of type 'a>b~c' (lovers):

  • In Approval or Plurality, they vote for a.

  • In Anti-plurality, half of them vote for ab (i.e. against c) and half of them vote for ac (i.e. against b).

Voters of type 'a~b>c' (haters):

  • In Approval or Plurality, half of them vote for a and half of them vote for b.

  • In Anti-plurality, they vote for ab (i.e. against c).

Type

dict

property d_ballot_share_weak_voters_sincere

Ballot shares due to the weak orders if they vote sincerely.

Voters of type 'a>b~c' (lovers):

  • In Approval or Plurality, they vote for a.

  • In Anti-plurality, half of them vote for ab (i.e. against c) and half of them vote for ac (i.e. against b).

Voters of type 'a~b>c' (haters):

  • In Approval or Anti-plurality, they vote for ab (i.e. against c).

  • In Plurality, half of them vote for a and half of them vote for b.

Type

dict

d_ballot_share_weak_voters_strategic(strategy)

dict : Ballot shares due to the weak orders if they vote strategically.

For voters with a weak order, strategic voting is the same as sincere voting, except in two cases:

  • For voters of type 'a~b>c' (haters)`in Plurality, who have two dominant strategies: vote for a or b.

  • For voters of type 'a>b~c' (lovers) in Anti-Plurality, who have two dominant strategies: vote against b or c (i.e. respectively for ac or ab).

property d_candidate_anti_plurality_welfare

Anti-plurality welfare of each candidate, i.e. share of voters with utility > 0.

Type

DictPrintingInOrder

property d_candidate_plurality_welfare

Plurality welfare of each candidate, i.e. share of voters with utility 1.

Type

DictPrintingInOrder

property d_candidate_relative_anti_plurality_welfare

Relative anti-plurality welfare of each candidate. This is similar to d_candidate_anti_plurality_welfare, but renormalized so that the candidate with best welfare has 1 and the one with worst welfare has 0. In math: relative_welfare = (welfare - min_welfare) / (max_welfare - min_welfare). In the case where all candidates have the same welfare, by convention, the relative welfare is 1 for all of them.

Type

DictPrintingInOrder

property d_candidate_relative_plurality_welfare

Relative plurality welfare of each candidate. This is similar to d_candidate_plurality_welfare, but renormalized so that the candidate with best welfare has 1 and the one with worst welfare has 0. In math: relative_welfare = (welfare - min_welfare) / (max_welfare - min_welfare). In the case where all candidates have the same welfare, by convention, the relative welfare is 1 for all of them.

Type

DictPrintingInOrder

property d_ranking_share

Shares of rankings. E.g. 'abc': 0.3 means that a ratio 0.3 of the voters have ranking 'abc'.

Type

dict

property d_weak_order_share

Shares of weak orders. E.g. 'a~b>c': 0.3 means that a ratio 0.3 of the voters have weak order 'a~b>c'.

Type

dict

distribution_equilibria(test=None)[source]

Distribution of numbers of equilibria (depending on the utilities).

Parameters

test (callable) – A function StrategyOrdinal -> bool that gives a condition on the strategy. Default: always True.

Returns

A list that represents an histogram. The distribution of number of equilibria (meeting the test condition).

Return type

list

Notes

The result is exact (not based on a Monte-Carlo estimation).

Examples

>>> from fractions import Fraction
>>> profile = ProfileOrdinal({'abc': Fraction(1, 10), 'bac': Fraction(6, 10), 'cab': Fraction(3, 10)})
>>> profile.distribution_equilibria()
array([0.        , 0.        , 0.86290531, 0.13709469])
distribution_winners(test=None)[source]

Distribution of the number of equilibrium winners (depending on the utilities).

Parameters

test (callable) – A function StrategyOrdinal -> bool that gives a condition on the strategy. Default: always True.

Returns

A list that represents an histogram. The distribution of number of possible equilibrium winner (with strategies that meet the test condition).

Return type

list

Notes

The result is exact (not based on a Monte-Carlo estimation).

Examples

>>> from fractions import Fraction
>>> profile = ProfileOrdinal({'abc': Fraction(1, 10), 'bac': Fraction(6, 10), 'cab': Fraction(3, 10)})
>>> profile.distribution_winners()
array([0, 0, 1, 0])
property has_majority_favorite

Whether there is a majority favorite (a candidate ranked first by strictly more than half of the voters).

Type

bool

property has_majority_ranking

Whether there is a majority ranking (a ranking shared by strictly more than half of the voters).

Type

bool

is_equilibrium(strategy)[source]

Whether a strategy is an equilibrium.

Parameters

strategy (StrategyOrdinal) – A strategy that specifies at least all the rankings that are present in the profile.

Returns

Whether strategy is an equilibrium in this profile.

Return type

EquilibriumStatus

Examples

>>> from fractions import Fraction
>>> profile = ProfileOrdinal({'abc': Fraction(1, 10), 'bac': Fraction(6, 10), 'cab': Fraction(3, 10)})
>>> strategy = StrategyOrdinal({'abc': 'a', 'bac': 'ab', 'cab': 'c'})
>>> profile.is_equilibrium(strategy)
EquilibriumStatus.EQUILIBRIUM
property is_generic_in_rankings

Whether the profile is generic in rankings (contains all rankings).

Type

bool

property is_profile_condorcet

Whether the profile is Condorcet. By convention, 1. means there is a strict Condorcet winner, 0.5 means there are one or more weak Condorcet winner(s), 0. means there is no Condorcet winner.

Type

float

property is_single_peaked

Whether the profile is single-peaked.

Type

bool

property is_standardized

Whether the profile is standardized. Cf. standardized_version().

Type

bool

classmethod order_and_label(t)[source]

Order and label of a discrete type.

Cf. Profile.order_and_label().

Examples

>>> ProfileOrdinal.order_and_label('abc')
('abc', '$r(abc)$')
>>> ProfileOrdinal.order_and_label('a~b>c')
('a~b>c', '$r(a\\sim b>c)$')
classmethod order_and_label_weak(t)

Auxiliary function for order_and_label(), specialized for weak orders.

Parameters

t (object) – A weak order of the form 'a>b~c' or 'a~b>c'.

Returns

  • order (str) – The weak order itself.

  • label (str) – The label to be used for the corner of the triangle.

Examples

>>> Profile.order_and_label_weak('a~b>c')
('a~b>c', '$r(a\\sim b>c)$')
proba_equilibrium(test=None)[source]

Probability that an equilibrium exists (depending on the utilities).

Parameters

test (callable) – A function StrategyOrdinal -> bool that gives a condition on the strategy. Default: always True.

Returns

The probability that an equilibrium strategy exists, that meets the test condition.

Return type

float

Notes

The result is exact (not based on a Monte-Carlo estimation).

Examples

>>> from fractions import Fraction
>>> profile = ProfileOrdinal({'abc': Fraction(1, 10), 'bac': Fraction(6, 10), 'cab': Fraction(3, 10)})
>>> profile.proba_equilibrium()
1
random_tau_undominated()

Random tau based on undominated ballots.

This is used, for example, in iterated_voting().

Returns

A random tau-vector. Independently for each ranking, a proportion uniformly drawn in [0, 1] of voters use one undominated ballot, and the rest use the other undominated ballot. For example, in Approval voting, voters with ranking abc are randomly split between ballots a and ab.

Return type

TauVector

property standardized_version

Standardized version of the profile (makes it unique, up to permutations of the candidates).

Examples

>>> from fractions import Fraction
>>> profile = ProfileOrdinal({'abc': Fraction(1, 10), 'bac': Fraction(6, 10), 'cab': Fraction(3, 10)})
>>> profile.standardized_version
ProfileOrdinal({'abc': Fraction(3, 5), 'bac': Fraction(1, 10), 'cba': Fraction(3, 10)})
>>> profile.is_standardized
False
Type

ProfileOrdinal

property strategies_group

Group strategies of the profile.

Yields

Strategy – All possible group strategies of the profile. This is implemented only for profiles where we consider that there is a natural notion of group, such as ProfileNoisyDiscrete.

Examples

Cf. ProfileNoisyDiscrete.

Type

Iterator

property strategies_ordinal

Ordinal strategies of the profile.

Yields

StrategyOrdinal – All possible ordinal strategies for this profile.

Examples

Cf. ProfileOrdinal.

Type

Iterator

property strategies_pure

Pure strategies of the profile.

Yields

Strategy – All possible pure strategies of the profile. This is implemented only for discrete profiles such as ProfileTwelve or ProfileDiscrete.

Examples

Cf. ProfileDiscrete.

Type

Iterator

property support_in_rankings

Support of the profile (in terms of rankings).

Type

SetPrintingInOrder of str

property support_in_weak_orders

Support of the profile (in terms of weak orders).

Type

SetPrintingInOrder of str

tau(strategy)[source]

Tau-vector associated to a strategy, with partial fanatic voting.

Parameters

strategy – An argument accepted by tau_strategic().

Returns

A share ratio_fanatic of voters vote only for their top candidate, and the rest of the voters vote strategically (in the sense of tau_strategic()). In other words, this tau-vector is the barycenter of tau_fanatic and tau_strategic(strategy), with respective weights self.ratio_fanatic and 1 - self.ratio_fanatic.

Return type

TauVector

Examples

>>> from fractions import Fraction
>>> profile = ProfileOrdinal({'abc': Fraction(1, 10), 'bac': Fraction(6, 10), 'cab': Fraction(3, 10)})
>>> strategy = StrategyOrdinal({'abc': 'a', 'bac': 'ab', 'cab': 'c'})
>>> tau = profile.tau(strategy)
>>> print(tau)
<a: 1/10, ab: 3/5, c: 3/10> ==> a
>>> τ = profile.τ(strategy)  # Alternate syntax
>>> print(τ)
<a: 1/10, ab: 3/5, c: 3/10> ==> a
property tau_fanatic

Tau-vector associated to fanatic voting.

Returns

In Approval or Plurality, all voters approve of their top candidate only. In Anti-Plurality, they all disapprove of their bottom candidate, i.e. they approve their two first candidates.

Return type

TauVector

tau_strategic(strategy)[source]

Tau-vector associated to a strategy.

Parameters

strategy (StrategyOrdinal) – A strategy that specifies at least all the rankings that are present in the profile.

Returns

Tau-vector associated to this profile and strategy strategy.

Return type

TauVector

Examples

>>> from fractions import Fraction
>>> profile = ProfileOrdinal({'abc': Fraction(1, 10), 'bac': Fraction(6, 10), 'cab': Fraction(3, 10)})
>>> strategy = StrategyOrdinal({'abc': 'a', 'bac': 'ab', 'cab': 'c'})
>>> tau_strategic = profile.tau_strategic(strategy)
>>> print(tau_strategic)
<a: 1/10, ab: 3/5, c: 3/10> ==> a

In the case of approval with badly informed voters, we do as if the tau-vector were the vector of scores (up to a renormalization):

>>> from fractions import Fraction
>>> profile = ProfileOrdinal({'abc': Fraction(1, 10), 'bac': Fraction(6, 10), 'cab': Fraction(3, 10)},
...                          well_informed_voters=False)
>>> strategy = StrategyOrdinal({'abc': 'a', 'bac': 'ab', 'cab': 'c'})
>>> tau_strategic = profile.tau_strategic(strategy)
>>> print(tau_strategic)
<a: 7/16, b: 3/8, c: 3/16> ==> a
property weighted_maj_graph

Weighted majority graph.

Type

numpy.ndarray

τ(strategy)

Tau-vector (alternate notation).

Parameters

strategy (Strategy) – A strategy that specifies at least all the rankings that are present in the profile.

Returns

Tau-vector associated to this profile and strategy strategy.

Return type

TauVector