Single-Peakedness¶
Functions to analyze single-peakedness of preference profiles.
A preference profile is single-peaked with respect to an axis (linear order over the candidates) if every voter has a unique most-preferred candidate (peak) and the voter’s preferences decrease monotonically in both directions from the peak along the axis.
A profile is k-maverick single-peaked with respect to an axis if all but k voters are single-peaked with respect to that axis. The minimum k over all axes measures how far the profile is from being single-peaked.
Reference: Faliszewski, Hemaspaandra & Hemaspaandra (2014), “The complexity of manipulative attacks in nearly single-peaked electorates”, Artificial Intelligence 207, 69-99. DOI
Checking Single-Peakedness of Individual Rankings¶
- pref_voting.single_peakedness.is_single_peaked(ranking, axis, num_cands=None, treat_truncated_as_maverick=False, tied_ranking_handling='maverick')[source]¶
Check if a ranking is single-peaked with respect to the given axis.
This function accepts either a list (a linear ranking, as used with
Profile) or aRankingobject (as used withProfileWithTies), and automatically handles complete, truncated, and tied rankings.- Parameters:
ranking (list or Ranking) – The voter’s ranking. If a list, it should contain candidates from most preferred to least preferred (a linear order, possibly truncated). If a
Rankingobject, ties and truncation are detected automatically.axis (list or tuple) – Candidates in the left-to-right axis order.
num_cands (int or None) – Total number of candidates in the election. Required when
rankingis aRankingobject, to detect whether the ranking is truncated. Ignored whenrankingis a list (in which caselen(axis)is used).treat_truncated_as_maverick (bool) – If True, voters who don’t rank all candidates are counted as mavericks. If False (default), truncated rankings are checked for compatibility with single-peakedness (ranked candidates must form a contiguous segment of the axis and be single-peaked on that segment).
tied_ranking_handling (str) – How to handle rankings with ties (only relevant when
rankingis aRankingobject with ties). One of'maverick'(default),'possibly_sp','single_plateaued','black_sp'. See module docstring for details.
- Returns:
True if the ranking is single-peaked-compatible with respect to the axis.
- Return type:
bool
Examples:
With a list (linear ranking from a
Profile):>>> from pref_voting.single_peakedness import is_single_peaked >>> is_single_peaked([1, 0, 2], [0, 1, 2]) True >>> is_single_peaked([0, 2, 1], [0, 1, 2]) False
With a
Rankingobject (from aProfileWithTies):>>> from pref_voting.rankings import Ranking >>> from pref_voting.single_peakedness import is_single_peaked >>> # Linear ranking: 0 > 1 > 2 >>> is_single_peaked(Ranking({0: 1, 1: 2, 2: 3}), [0, 1, 2], num_cands=3) True >>> # Weak order with tie: {0, 1} > 2 >>> is_single_peaked(Ranking({0: 1, 1: 1, 2: 2}), [0, 1, 2], num_cands=3, ... tied_ranking_handling='possibly_sp') True
Profile-Level Analysis¶
Counting Mavericks¶
- pref_voting.single_peakedness.num_mavericks(profile, axis, treat_truncated_as_maverick=False, tied_ranking_handling='maverick')[source]¶
Count the number of voters whose rankings are NOT single-peaked with respect to the given axis.
- Parameters:
profile (Profile or ProfileWithTies) – The preference profile.
axis (list or tuple) – Candidates in the left-to-right axis order.
treat_truncated_as_maverick (bool) – If True, voters who don’t rank all candidates are counted as mavericks. If False (default), truncated rankings are checked for compatibility with single-peakedness (ranked candidates must form a contiguous segment of the axis and be single-peaked on that segment).
tied_ranking_handling (str) – How to handle rankings with ties. One of
'maverick'(default),'possibly_sp','single_plateaued','black_sp'. See module docstring for details.
- Returns:
The number of maverick voters.
- Return type:
int
Example:
from pref_voting.profiles import Profile from pref_voting.single_peakedness import num_mavericks prof = Profile([[0, 1, 2], [1, 0, 2], [1, 2, 0], [2, 1, 0], [0, 2, 1]]) # 0 > 2 > 1 is not single-peaked on axis [0, 1, 2] num_mavericks(prof, [0, 1, 2]) # returns 1
Finding the Minimum k¶
- pref_voting.single_peakedness.min_k_maverick_single_peaked(profile, treat_truncated_as_maverick=False, tied_ranking_handling='maverick')[source]¶
Find the minimum k such that the profile is k-maverick single-peaked with respect to some ordering of the candidates.
This function iterates over all possible axes (permutations of candidates) and returns the axis that minimizes the number of maverick voters. An axis and its reverse are equivalent for single-peakedness, so only half of the permutations are checked.
Suitable for small numbers of candidates (up to about 8).
- Parameters:
profile (Profile or ProfileWithTies) – The preference profile.
treat_truncated_as_maverick (bool) – If True, voters who don’t rank all candidates are counted as mavericks. If False (default), truncated rankings are checked for compatibility.
tied_ranking_handling (str) – How to handle rankings with ties. One of
'maverick'(default),'possibly_sp','single_plateaued','black_sp'. See module docstring for details.
- Returns:
(min_k, best_axis, sp_profile)wheremin_k(int) is the minimum number of mavericks,best_axis(list) is an axis achieving it, andsp_profileis the anonymized sub-profile of non-maverick voters (aProfileif the input is aProfile, aProfileWithTiesif the input is aProfileWithTies, orNoneif all voters are mavericks).- Return type:
tuple
Example:
from pref_voting.profiles import Profile from pref_voting.single_peakedness import min_k_maverick_single_peaked prof = Profile([[0, 1, 2], [1, 0, 2], [1, 2, 0], [2, 1, 0], [0, 2, 1]]) min_k, best_axis, sp_prof = min_k_maverick_single_peaked(prof) # min_k = 1, best_axis = [0, 1, 2], sp_prof has 4 voters
References
Faliszewski, Hemaspaandra & Hemaspaandra (2014), “The complexity of manipulative attacks in nearly single-peaked electorates”, Artificial Intelligence 207, 69-99. https://doi.org/10.1016/j.artint.2013.11.004