''' File: voting_methods.py Author: Wes Holliday (wesholliday@berkeley.edu) and Eric Pacuit (epacuit@umd.edu) Date: June 3, 2023 Implementations of probabilistic voting methods.'''frompref_voting.prob_voting_methodimport*frompref_voting.weighted_majority_graphsimportMajorityGraph,MarginGraphimportrandomimportnashpyasnash
[docs]@pvm(name="Random Dictator")defrandom_dictator(profile,curr_cands=None):'''Returns lottery over the candidates that is proportional to the Plurality scores. Args: profile (Profile): A Profile object. curr_cands (list): A list of candidates to restrict the ranking to. If ``None``, then the ranking is over the entire domain of the profile. Returns: dict: A dictionary mapping candidates to probabilities. '''plurality_scores=profile.plurality_scores(curr_cands=curr_cands)total_plurality_scores=sum(list(plurality_scores.values()))return{c:plurality_scores[c]/total_plurality_scoresforcinplurality_scores.keys()}
[docs]@pvm(name="Proportional Borda")defpr_borda(profile,curr_cands=None):'''Returns lottery over the candidates that is proportional to the Borda scores. Args: profile (Profile): A Profile object. curr_cands (list): A list of candidates to restrict the ranking to. If ``None``, then the ranking is over the entire domain of the profile. Returns: dict: A dictionary mapping candidates to probabilities. '''borda_scores=profile.borda_scores(curr_cands=curr_cands)total_borda_scores=sum(list(borda_scores.values()))return{c:borda_scores[c]/total_borda_scoresforcinborda_scores.keys()}
def_maximal_lottery(edata,curr_cands=None,margin_transformation=lambdax:x):'''Implementation of maximal lotteries. See http://dss.in.tum.de/files/brandt-research/fishburn_slides.pdf Returns a randomly chosen maximal lottery. '''candidates=edata.candidatesifcurr_candsisNoneelsecurr_candsm_matrix,cand_to_cidx=edata.strength_matrix(curr_cands=candidates)A=np.array([[margin_transformation(m)forminrow]forrowinm_matrix])# Create the gamegame=nash.Game(A)# Find the Nash Equilibrium with Vertex Enumerationequilibria=list(game.vertex_enumeration())iflen(equilibria)==0:return{c:1/len(candidates)forcincandidates}else:eq=random.choice(equilibria)return{c:eq[0][cand_to_cidx(c)]forcincandidates}
[docs]@pvm(name="C1 Maximal Lottery")defc1_maximal_lottery(edata,curr_cands=None):'''Returns the C1 maximal lottery over the candidates. See http://dss.in.tum.de/files/brandt-research/fishburn_slides.pdf. Args: edata (Profile, MarginGraph): A Profile object. curr_cands (list): A list of candidates to restrict the ranking to. If ``None``, then the ranking is over the entire domain of the profile. Returns: dict: A dictionary mapping candidates to probabilities. '''iftype(edata)==MajorityGraph:# if edata is a MajorityGraph, we need to add margins for the following code to work. The margins do not matter when finding the c1 maximal lottery.candidates=edata.candidatesifcurr_candsisNoneelsecurr_candsedata=MarginGraph(candidates,[(c1,c2,1)forc1,c2inedata.edgesif(c1incandidatesandc2incandidates)])return_maximal_lottery(edata,curr_cands=curr_cands,margin_transformation=np.sign)
[docs]@pvm(name="Maximal Lottery")defmaximal_lottery(edata,curr_cands=None):'''Returns the maximal lottery over the candidates. See http://dss.in.tum.de/files/brandt-research/fishburn_slides.pdf. Args: edata (Profile, MarginGraph): A Profile object. curr_cands (list): A list of candidates to restrict the ranking to. If ``None``, then the ranking is over the entire domain of the profile. Returns: dict: A dictionary mapping candidates to probabilities. '''return_maximal_lottery(edata,curr_cands=curr_cands,margin_transformation=lambdax:x)