diff --git a/docs/source/scoring_methods.md b/docs/source/scoring_methods.md index 89396fb..b3d026e 100644 --- a/docs/source/scoring_methods.md +++ b/docs/source/scoring_methods.md @@ -120,7 +120,15 @@ One problem with the above code is that the name of the scoring rule is "Scoring ```{eval-rst} -.. autofunction:: pref_voting.scoring_methods.anti_plurality(profile, curr_cands = None) +.. autofunction:: pref_voting.scoring_methods.anti_plurality + +``` + +## Dowdall + +```{eval-rst} + +.. autofunction:: pref_voting.scoring_methods.dowdall ``` diff --git a/pref_voting/c1_methods.py b/pref_voting/c1_methods.py index 6603edc..d0093fa 100644 --- a/pref_voting/c1_methods.py +++ b/pref_voting/c1_methods.py @@ -23,7 +23,9 @@ condorcet_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=False, - pareto_dominance=False,) + pareto_dominance=False, + positive_involvement=False, + ) @vm(name = "Condorcet", properties = condorcet_properties, input_types = [ElectionTypes.PROFILE, ElectionTypes.PROFILE_WITH_TIES, ElectionTypes.MAJORITY_GRAPH, ElectionTypes.MARGIN_GRAPH]) @@ -75,7 +77,9 @@ def condorcet(edata, curr_cands = None): copeland_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name = "Copeland", properties = copeland_properties, input_types = [ElectionTypes.PROFILE, ElectionTypes.PROFILE_WITH_TIES, ElectionTypes.MAJORITY_GRAPH, ElectionTypes.MARGIN_GRAPH]) @@ -162,7 +166,9 @@ def copeland_ranking(edata, curr_cands=None, local=True, tie_breaking=None): llull_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name = "Llull", properties = llull_properties, input_types = [ElectionTypes.PROFILE, ElectionTypes.PROFILE_WITH_TIES, ElectionTypes.MAJORITY_GRAPH, ElectionTypes.MARGIN_GRAPH]) @@ -228,6 +234,7 @@ def right_covers(dom, c1, c2): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True,) + @vm(name = "Uncovered Set", properties = uc_gill_properties, input_types = [ElectionTypes.PROFILE, ElectionTypes.PROFILE_WITH_TIES, ElectionTypes.MAJORITY_GRAPH, ElectionTypes.MARGIN_GRAPH]) @@ -544,7 +551,9 @@ def uc_mckelvey(edata, curr_cands = None): top_cycle_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name = "Top Cycle", properties = top_cycle_properties, input_types = [ElectionTypes.PROFILE, ElectionTypes.PROFILE_WITH_TIES, ElectionTypes.MAJORITY_GRAPH, ElectionTypes.MARGIN_GRAPH]) @@ -645,7 +654,9 @@ def top_cycle_defeat(edata, curr_cands = None): gocha_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name = "GOCHA", properties = gocha_properties, input_types = [ElectionTypes.PROFILE, ElectionTypes.PROFILE_WITH_TIES, ElectionTypes.MAJORITY_GRAPH, ElectionTypes.MARGIN_GRAPH]) diff --git a/pref_voting/combined_methods.py b/pref_voting/combined_methods.py index 7360269..342d431 100644 --- a/pref_voting/combined_methods.py +++ b/pref_voting/combined_methods.py @@ -21,7 +21,9 @@ daunou_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name = "Daunou", properties = daunou_properties, input_types = [ElectionTypes.PROFILE]) @@ -68,7 +70,9 @@ def daunou(profile, curr_cands=None): blacks_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name = "Blacks", properties = blacks_properties, input_types = [ElectionTypes.PROFILE]) @@ -112,7 +116,9 @@ def blacks(profile, curr_cands=None): smith_irv_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name = "Smith IRV", properties = smith_irv_properties, input_types = [ElectionTypes.PROFILE]) @@ -151,7 +157,9 @@ def smith_irv(profile, curr_cands=None): smith_irv_put_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name = "Smith IRV PUT", properties = smith_irv_put_properties, input_types = [ElectionTypes.PROFILE]) @@ -190,7 +198,10 @@ def smith_irv_put(profile, curr_cands=None): condorcet_irv_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) + @vm(name = "Condorcet IRV", properties = condorcet_irv_properties, input_types = [ElectionTypes.PROFILE]) @@ -231,7 +242,9 @@ def condorcet_irv(profile, curr_cands=None): condorcet_irv_put_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name = "Condorcet IRV PUT", properties = condorcet_irv_put_properties, input_types = [ElectionTypes.PROFILE]) @@ -324,7 +337,9 @@ def _vm(edata, curr_cands=None): condorcet_plurality_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=False, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name = "Condorcet Plurality", properties = condorcet_plurality_properties, input_types = [ElectionTypes.PROFILE]) @@ -343,12 +358,14 @@ def condorcet_plurality(profile, curr_cands = None): return _compose(condorcet, plurality)(profile, curr_cands=curr_cands) -smith_minimax_plurality_properties = VotingMethodProperties( +smith_minimax_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=True, + ) @vm(name="Smith-Minimax", - properties=smith_minimax_plurality_properties, + properties=smith_minimax_properties, input_types=[ElectionTypes.PROFILE, ElectionTypes.PROFILE_WITH_TIES, ElectionTypes.MARGIN_GRAPH]) def smith_minimax(edata, curr_cands = None): """Return the Minimax winner after restricting to the Smith set. @@ -367,7 +384,9 @@ def smith_minimax(edata, curr_cands = None): copeland_local_borda_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name="Copeland-Local-Borda", properties=copeland_local_borda_properties, input_types=[ElectionTypes.PROFILE, ElectionTypes.MARGIN_GRAPH]) @@ -414,7 +433,9 @@ def _vm(profile, curr_cands=None): copeland_global_borda_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name="Copeland-Global-Borda", properties=copeland_global_borda_properties, input_types=[ElectionTypes.PROFILE]) @@ -505,7 +526,9 @@ def _vm(edata, curr_cands=None): borda_minimax_faceoff_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True,) + pareto_dominance=True, + positive_involvement=False, + ) @vm(name="Borda-Minimax Faceoff", properties=borda_minimax_faceoff_properties, input_types=[ElectionTypes.PROFILE]) @@ -524,4 +547,4 @@ def borda_minimax_faceoff(edata, curr_cands=None): """ - return _faceoff(borda, minimax)(edata, curr_cands=curr_cands) + return _faceoff(borda, minimax)(edata, curr_cands=curr_cands) \ No newline at end of file diff --git a/pref_voting/helper.py b/pref_voting/helper.py index 5cb27c6..8775375 100644 --- a/pref_voting/helper.py +++ b/pref_voting/helper.py @@ -204,7 +204,7 @@ def weak_orders(A): yield {} return for k in range(1, len(A) + 1): - for B in itertools.combinations(A, k): + for B in combinations(A, k): for order in weak_orders(set(A) - set(B)): new_order = {cand: rank + 1 for cand, rank in order.items()} yield {**new_order, **{cand: 0 for cand in B}} diff --git a/pref_voting/iterative_methods.py b/pref_voting/iterative_methods.py index d3affab..8184b8b 100644 --- a/pref_voting/iterative_methods.py +++ b/pref_voting/iterative_methods.py @@ -71,6 +71,7 @@ def _instant_runoff_recursive(profile, curr_cands = None): condorcet_winner=False, condorcet_loser=False, pareto_dominance=True, + positive_involvement=True, ) @vm(name = "Instant Runoff", properties=irv_properties, @@ -244,6 +245,7 @@ def instant_runoff_tb(profile, curr_cands = None, tie_breaker = None): condorcet_winner=False, condorcet_loser=None, pareto_dominance=True, + positive_involvement=True, ) @vm(name = "Instant Runoff PUT", properties=irv_put_properties, @@ -512,6 +514,7 @@ def instant_runoff_for_truncated_linear_orders(profile, curr_cands = None, thres condorcet_winner=True, condorcet_loser=False, pareto_dominance=True, + positive_involvement=False, ) @vm(name="Bottom-Two-Runoff Instant Runoff", properties=bottom_two_runoff_properties, @@ -569,6 +572,7 @@ def bottom_two_runoff_instant_runoff(profile, curr_cands = None): condorcet_winner=None, condorcet_loser=False, pareto_dominance=None, + positive_involvement=False, ) @vm(name="Bottom-Two-Runoff Instant Runoff PUT", properties=bottom_two_runoff_put_properties, @@ -620,6 +624,7 @@ def bottom_two_runoff_instant_runoff_put(profile, curr_cands = None): condorcet_winner=False, condorcet_loser=True, pareto_dominance=None, + positive_involvement=True, ) @vm(name = "PluralityWRunoff PUT", properties=pl_w_runoff_properties, @@ -734,6 +739,7 @@ def plurality_with_runoff_put_with_explanation(profile, curr_cands = None): condorcet_winner=False, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Coombs", properties=coombs_properties, @@ -806,6 +812,7 @@ def coombs(profile, curr_cands = None): condorcet_winner=False, condorcet_loser=None, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Coombs TB", properties=coombs_tb_properties, @@ -883,6 +890,7 @@ def coombs_tb(profile, curr_cands = None, tie_breaker=None): condorcet_winner=False, condorcet_loser=None, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Coombs PUT", properties=coombs_put_properties, @@ -1022,6 +1030,7 @@ def coombs_with_explanation(profile, curr_cands = None): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Baldwin", properties=baldwin_properties, @@ -1096,6 +1105,7 @@ def baldwin(profile, curr_cands = None): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Baldwin TB", properties=coombs_tb_properties, @@ -1186,6 +1196,7 @@ def baldwin_tb(profile, curr_cands = None, tie_breaker=None): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Baldwin PUT", properties=baldwin_put_properties, @@ -1333,6 +1344,7 @@ def baldwin_with_explanation(profile, curr_cands = None): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Strict Nanson", properties=strict_nanson_properties, @@ -1483,6 +1495,7 @@ def strict_nanson_with_explanation(profile, curr_cands = None): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Weak Nanson", properties=weak_nanson_properties, @@ -1655,6 +1668,7 @@ def weak_nanson_with_explanation(profile, curr_cands = None): condorcet_winner=False, condorcet_loser=True, pareto_dominance=False, + positive_involvement=False, ) @vm(name = "Iterated Removal Condorcet Loser", properties=it_condorcet_loser_properties, @@ -1757,7 +1771,8 @@ def _remove_worst_losers(edata,curr_cands,score_method): raynaud_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=False, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Raynaud", properties=raynaud_properties, @@ -1783,7 +1798,8 @@ def raynaud(edata, curr_cands=None, score_method = "margins"): benham_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=False, - pareto_dominance=True, + pareto_dominance=True, + benham=False, ) @vm(name = "Benham", properties=benham_properties, @@ -1842,7 +1858,8 @@ def benham(profile, curr_cands = None): benham_tb_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=None, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Benham TB", properties=benham_tb_properties, @@ -1900,7 +1917,8 @@ def benham_tb(profile, curr_cands = None, tie_breaker = None): benham_tb_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=None, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Benham PUT", properties=benham_tb_properties, @@ -1996,6 +2014,7 @@ def _ta(profile, curr_cands = None): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) tideman_alternative_smith = tideman_alternative(top_cycle) tideman_alternative_smith.properties = ta_smith_properties @@ -2005,6 +2024,7 @@ def _ta(profile, curr_cands = None): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) tideman_alternative_schwartz = tideman_alternative(gocha) tideman_alternative_schwartz.properties = ta_schwartz_properties @@ -2049,6 +2069,7 @@ def _ta(profile, curr_cands = None): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) tideman_alternative_smith_put = tideman_alternative_put(top_cycle) tideman_alternative_smith_put.properties = ta_smith_put_properties @@ -2058,6 +2079,7 @@ def _ta(profile, curr_cands = None): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) tideman_alternative_schwartz_put = tideman_alternative_put(gocha) tideman_alternative_schwartz_put.properties = ta_schwartz_put_properties @@ -2068,6 +2090,7 @@ def _ta(profile, curr_cands = None): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Woodall", properties=woodall_properties, @@ -2136,6 +2159,7 @@ def woodall(profile, curr_cands = None): condorcet_winner=None, condorcet_loser=None, pareto_dominance=None, + positive_involvement=False, ) @vm(name = "Knockout Voting", properties=knockout_properties, diff --git a/pref_voting/margin_based_methods.py b/pref_voting/margin_based_methods.py index 04c03e5..1395793 100644 --- a/pref_voting/margin_based_methods.py +++ b/pref_voting/margin_based_methods.py @@ -8,6 +8,7 @@ ''' from pref_voting.voting_method import * +from pref_voting.c1_methods import gocha from pref_voting.weighted_majority_graphs import MajorityGraph, MarginGraph from pref_voting.probabilistic_methods import maximal_lottery, c1_maximal_lottery from pref_voting.helper import get_mg, SPO @@ -19,7 +20,8 @@ minimax_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=False, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=True, ) @vm(name = "Minimax", properties=minimax_properties, @@ -159,7 +161,6 @@ def _beat_path_basic(edata, A sorted list of candidates. """ - candidates = edata.candidates if curr_cands is None else curr_cands strength_function = edata.margin if strength_function is None else strength_function @@ -180,7 +181,6 @@ def _beat_path_basic(edata, winners.append(c) return sorted(list(winners)) - def _beat_path_floyd_warshall( edata, curr_cands = None, @@ -221,11 +221,49 @@ def _beat_path_floyd_warshall( winners[i] = False return sorted([c for c in candidates if winners[c]]) +def _schwartz_sequential_dropping(edata, curr_cands = None, strength_function = None): + + """The Schwartz Sequential Dropping algorithm. See https://en.wikipedia.org/wiki/Schulze_method#Ties_and_alternative_implementations. + + Args: + edata (Profile, ProfileWithTies, MarginGraph): Any election data that has a `margin` method. + curr_cands (List[int], optional): If set, then find the winners for the profile restricted to the candidates in ``curr_cands`` + strength_function (function, optional): The strength function to be used to calculate the strength of a path. The default is the margin method of ``edata``. This only matters when the ballots are not linear orders. + + Returns: + A sorted list of candidates. + """ + + strength_function = edata.margin if strength_function is None else strength_function + + mg = edata if isinstance(edata, MarginGraph) else edata.margin_graph() + schwartz = gocha(mg, curr_cands = curr_cands) + + if len(schwartz) == 1: + return schwartz + + pos_schwartz_strengths = [strength_function(c,d) for c in schwartz for d in schwartz if strength_function(c,d) > 0] + + if len(pos_schwartz_strengths) == 0: + return sorted(schwartz) + + max_schwartz_strength = max(pos_schwartz_strengths) + min_schwartz_strength = min(pos_schwartz_strengths) + + if max_schwartz_strength == min_schwartz_strength: + return sorted(schwartz) + + else: + new_mg = MarginGraph(schwartz,[(c,d, strength_function(c,d)) for c in schwartz for d in schwartz if strength_function(c,d) > min_schwartz_strength]) + return _schwartz_sequential_dropping(new_mg, schwartz) + bp_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) + @vm(name="Beat Path", properties=bp_properties, input_types=[ElectionTypes.PROFILE, ElectionTypes.PROFILE_WITH_TIES, ElectionTypes.MARGIN_GRAPH]) @@ -238,13 +276,13 @@ def beat_path( """For candidates :math:`a` and :math:`b`, a **path** from :math:`a` to :math:`b` is a sequence :math:`x_1, \ldots, x_n` of distinct candidates with :math:`x_1=a` and :math:`x_n=b` such that for :math:`1\leq k\leq n-1`, :math:`x_k` is majority preferred to :math:`x_{k+1}`. The **strength of a path** - is the minimal margin along that path. Say that :math:`a` defeats :math:`b` according to Beat Path if the the strength of the strongest path from :math:`a` to :math:`b` is greater than the strength of the strongest path from :math:`b` to :math:`a`. Then, the candidates that are undefeated according to Beat Path are the winners. Also known as the Schulze Rule. + is the minimal margin along that path. Say that :math:`a` defeats :math:`b` according to Beat Path if the the strength of the strongest path from :math:`a` to :math:`b` is greater than the strength of the strongest path from :math:`b` to :math:`a`. Then the candidates that are undefeated according to Beat Path are the winners. Also known as the Schulze Rule. Args: edata (Profile, ProfileWithTies, MarginGraph): Any election data that has a `margin` method. curr_cands (List[int], optional): If set, then find the winners for the profile restricted to the candidates in ``curr_cands`` strength_function (function, optional): The strength function to be used to calculate the strength of a path. The default is the margin method of ``edata``. This only matters when the ballots are not linear orders. - algorithm (str): Specify which algorithm to use. Options are 'floyd_warshall' (the default) and 'basic'. + algorithm (str): Specify which algorithm to use. Options are 'floyd_warshall' (the default), 'basic', and 'schwartz_sequential_dropping'. Returns: A sorted list of candidates. @@ -284,6 +322,8 @@ def beat_path( return _beat_path_floyd_warshall(edata, curr_cands = curr_cands, strength_function = strength_function) elif algorithm == 'basic': return _beat_path_basic(edata, curr_cands = curr_cands, strength_function = strength_function) + elif algorithm == 'schwartz_sequential_dropping': + return _schwartz_sequential_dropping(edata, curr_cands = curr_cands, strength_function = strength_function) else: raise ValueError("Invalid algorithm specified.") @@ -421,7 +461,8 @@ def _split_cycle_floyd_warshall( sc_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=True, ) @vm(name="Split Cycle", properties=sc_properties, @@ -697,7 +738,8 @@ def _ranked_pairs_basic( rp_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) @vm(name="Ranked Pairs", properties=rp_properties, @@ -903,7 +945,8 @@ def ranked_pairs_defeats(edata, curr_cands = None, strength_function = None): rp_tb_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) @vm(name="Ranked Pairs TB", properties=rp_tb_properties, @@ -980,6 +1023,7 @@ def ranked_pairs_tb( condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) @vm(name="Ranked Pairs ZT", properties=rp_zt_properties, @@ -1026,7 +1070,8 @@ def ranked_pairs_zt( river_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) @vm(name="River", properties=river_properties, @@ -1175,7 +1220,8 @@ def river_with_test(edata, curr_cands = None, strength_function = None): rp_tb_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) @vm(name="River TB", properties=rp_tb_properties, @@ -1226,7 +1272,8 @@ def river_tb(edata, curr_cands = None, tie_breaker = None, strength_function = N river_zt_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) @vm(name="River ZT", properties=river_zt_properties, @@ -1350,7 +1397,8 @@ def _simple_stable_voting_basic(edata, curr_cands = None, strength_function = No ssv_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Simple Stable Voting", properties = ssv_properties, @@ -1507,7 +1555,8 @@ def _stable_voting_basic( sv_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Stable Voting", properties = sv_properties, @@ -1563,7 +1612,8 @@ def stable_voting( essential_set_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) @vm(name="Essential Set", properties=essential_set_properties, @@ -1586,7 +1636,8 @@ def essential(edata, curr_cands = None, threshold = 0.0000001): weighted_covering_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=True, ) @vm(name="Weighted Covering", properties=weighted_covering_properties, @@ -1631,7 +1682,8 @@ def weighted_covering(edata, curr_cands=None): loss_trimmer_properties = VotingMethodProperties( condorcet_winner=True, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Loss-Trimmer Voting", properties = loss_trimmer_properties, diff --git a/pref_voting/other_methods.py b/pref_voting/other_methods.py index 8fca5cc..317b497 100644 --- a/pref_voting/other_methods.py +++ b/pref_voting/other_methods.py @@ -58,6 +58,7 @@ def majority(profile, curr_cands = None): condorcet_winner=False, condorcet_loser=False, pareto_dominance=True, + positive_involvement = True, ) @vm(name = "Pareto", properties = pareto_properties, @@ -167,6 +168,7 @@ def kemeny_young_rankings(profile, curr_cands = None): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Kemeny-Young", properties = kemeny_young_properties, @@ -241,6 +243,7 @@ def kemeny_young(edata, curr_cands = None, algorithm = "marginal"): condorcet_winner=True, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) @vm("Preliminary Weighted Condorcet", properties = preliminary_weighted_condorcet_properties, @@ -296,6 +299,7 @@ def preliminary_weighted_condorcet(prof, curr_cands = None, show_orders = False, condorcet_winner=False, condorcet_loser=False, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Bucklin", properties = bucklin_properties, @@ -406,6 +410,7 @@ def bucklin_with_explanation(profile, curr_cands = None): condorcet_winner=False, condorcet_loser=False, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Simplified Bucklin", properties = simplified_bucklin_properties, @@ -514,6 +519,7 @@ def simplified_bucklin_with_explanation(profile, curr_cands = None): condorcet_winner=False, condorcet_loser=None, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Weighted Bucklin", properties = weighted_bucklin_properties, @@ -575,6 +581,7 @@ def weighted_bucklin(profile, curr_cands = None, strict_threshold = False, score condorcet_winner=False, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Bracket Voting", properties = bracket_voting_properties, @@ -647,6 +654,7 @@ def bracket_voting(profile, curr_cands = None, seed = None): condorcet_winner=False, condorcet_loser=True, pareto_dominance=True, + positive_involvement=False, ) @vm(name = "Superior Voting", properties = superior_voting_properties, diff --git a/pref_voting/scoring_methods.py b/pref_voting/scoring_methods.py index 56f7125..4c11f13 100644 --- a/pref_voting/scoring_methods.py +++ b/pref_voting/scoring_methods.py @@ -17,7 +17,8 @@ pl_properties = VotingMethodProperties( condorcet_winner=False, condorcet_loser=False, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=True, ) @vm(name = "Plurality", properties=pl_properties, @@ -107,7 +108,8 @@ def plurality_ranking(profile, curr_cands=None, local=True, tie_breaking=None): borda_properties = VotingMethodProperties( condorcet_winner=False, condorcet_loser=True, - pareto_dominance=True, + pareto_dominance=True, + positive_involvement=True, ) @vm(name = "Borda", properties=borda_properties, @@ -201,7 +203,8 @@ def borda_ranking(profile, curr_cands=None, local=True, tie_breaking=None): anti_plurality_properties = VotingMethodProperties( condorcet_winner=False, condorcet_loser=False, - pareto_dominance=False, + pareto_dominance=False, + positive_involvement=True, ) @vm(name = "Anti-Plurality", properties=anti_plurality_properties, @@ -344,13 +347,14 @@ def _vm(profile, curr_cands = None): return VotingMethod(_vm, name = name) -dowdal_properties = VotingMethodProperties( +dowdall_properties = VotingMethodProperties( condorcet_winner=False, condorcet_loser=False, pareto_dominance=True, + positive_involvement=True, ) @vm(name = "Dowdall", - properties=dowdal_properties, + properties=dowdall_properties, input_types=[ElectionTypes.PROFILE]) def dowdall(profile, curr_cands = None): """The first-ranked candidate gets 1 point, the second-ranked candidate gets 1/2 point, the third-ranked candidate gets 1/3 point, and so on. The Dowdall winners are the candidates with the greatest overall score in the profile restricted to ``curr_cands``. @@ -372,7 +376,8 @@ def dowdall(profile, curr_cands = None): pos_neg_voting_properties = VotingMethodProperties( condorcet_winner=False, condorcet_loser=False, - pareto_dominance=False, + pareto_dominance=False, + positive_involvement=True, ) @vm(name="Positive-Negative Voting", properties=pos_neg_voting_properties,