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 Antiplurality).
 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 is 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 singlepeaked? 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) <BLANKLINE> Utilitydependent equilibrium: <abc: ab, bac: b, cab: c> ==> b (FF) <BLANKLINE> Nonequilibria: <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)

abc
¶ Share of voters with this ranking.
Type: Number

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

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: AnalyzedStrategies

analyzed_strategies_ordinal
¶ Analyzed ordinal strategies.
Cf.
analyzed_strategies()
andstrategies_ordinal
.Type: AnalyzedStrategies

analyzed_strategies_pure
¶ Analyzed pure strategies.
Cf.
analyzed_strategies()
andstrategies_pure
. This is implemented only for discrete profiles such asProfileTwelve
orProfileDiscrete
.Type: AnalyzedStrategies

bac
¶ Share of voters with this ranking.
Type: Number

bca
¶ Share of voters with this ranking.
Type: Number

best_responses_to_strategy
(d_ranking_best_response)¶ Convert best responses to a
StrategyThreshold
.Parameters: d_ranking_best_response (dict) – Key: ranking. Value: BestResponse
.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

cab
¶ Share of voters with this ranking.
Type: Number

cba
¶ Share of voters with this ranking.
Type: Number

contains_rankings
¶ Whether the profile contains some rankings.
Type: bool

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 the type
'a>b~c'
: In Approval or Plurality, they vote for a.
 In Antiplurality, half of them vote for ab (i.e. against c) and half of them vote for ac (i.e. against b).
Voters of the type
'a~b>c'
: In Approval or Plurality, half of them vote for a and half of them vote for b.
 In Antiplurality, they vote for ab (i.e. against c).
Type: dict
Ballot shares due to the weak orders if they vote sincerely
Voters of the type
'a>b~c'
: In Approval or Plurality, they vote for a.
 In Antiplurality, half of them vote for ab (i.e. against c) and half of them vote for ac (i.e. against b).
Voters of the type
'a~b>c'
: In Approval or Antiplurality, 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

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 MonteCarlo 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 MonteCarlo 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])

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

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

is_generic_in_rankings
¶ Whether the profile is generic in rankings (contains all rankings).
Type: bool

is_profile_condorcet
¶ Whether the profile is Condorcet. 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

is_single_peaked
¶ Whether the profile is singlepeaked.
Type: bool

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 MonteCarlo 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
ProfileCardinal.iterated_voting()
.Returns: A random tauvector. 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

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

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

strategies_ordinal
¶ ordinal strategies of the profile.
Yields: StrategyOrdinal – All possible ordinal strategies for this profile. Examples
Cf.
ProfileOrdinal
.Type: Iterator

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
orProfileDiscrete
.Examples
Cf.
ProfileDiscrete
.Type: Iterator

support_in_rankings
¶ Support of the profile (in terms of rankings).
Type: SetPrintingInOrder
of str

support_in_weak_orders
¶ Support of the profile (in terms of weak orders).
Type: SetPrintingInOrder
of str

tau
(strategy)[source]¶ Tauvector 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 oftau_strategic()
). In other words, this tauvector is the barycenter oftau_fanatic
andtau_strategic(strategy)
, with respective weightsself.ratio_fanatic
and1  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

tau_fanatic
¶ Tauvector associated to fanatic voting.
Returns: In Approval or Plurality, all voters approve of their top candidate only. In AntiPlurality, they all disapprove of their bottom candidate, i.e. they approve their two first candidates. Return type: TauVector

tau_strategic
(strategy)[source]¶ Tauvector associated to a strategy.
Parameters: strategy (StrategyOrdinal) – A strategy that specifies at least all the rankings that are present in the profile. Returns: Tauvector 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 tauvector 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

weighted_maj_graph
¶ Weighted majority graph.
Type: np.ndarray
 d_ranking_share (dict) – E.g.