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 candidatea
, then candidateb
, then candidatec
.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 candidatesa
andb
equally and prefer them to candidatec
.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
andANTI_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
Examples
- property analyzed_strategies_group
Analyzed group strategies.
Cf.
analyzed_strategies()
andstrategies_group
. This is implemented only for profiles where we consider that there is a natural notion of group, such asProfileNoisyDiscrete
.- Type
- property analyzed_strategies_ordinal
Analyzed ordinal strategies.
Cf.
analyzed_strategies()
andstrategies_ordinal
.- Type
- property analyzed_strategies_pure
Analyzed pure strategies.
Cf.
analyzed_strategies()
andstrategies_pure
. This is implemented only for discrete profiles such asProfileTwelve
orProfileDiscrete
.- Type
- 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
- property cab
Share of voters with this ranking.
- Type
Number
- property cba
Share of voters with this ranking.
- Type
Number
- property contains_rankings
Whether the profile contains some rankings.
- Type
bool
- property contains_weak_orders
Whether the profile contains some weak orders.
- Type
bool
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
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
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
- property d_candidate_plurality_welfare
Plurality welfare of each candidate, i.e. share of voters with utility 1.
- Type
- 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
- 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
Shares of rankings. E.g.
'abc': 0.3
means that a ratio 0.3 of the voters have ranking'abc'
.- Type
dict
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
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
- 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
- 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 asProfileNoisyDiscrete
.
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 asProfileTwelve
orProfileDiscrete
.
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
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
- 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
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