Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

weighted voting #22

Open
antviro opened this issue Oct 22, 2014 · 1 comment
Open

weighted voting #22

antviro opened this issue Oct 22, 2014 · 1 comment

Comments

@antviro
Copy link

antviro commented Oct 22, 2014

I introduced a function for weighted voting with a St. Lagüe weight function given by 1/(1+2(n-1))
http://www.uv.es/~pla/sistelec/propabga.htm

ponderado.py:
from abstract_classes import MultipleWinnerVotingSystem
from common_functions import matching_keys
import types
import copy

class ponderado(MultipleWinnerVotingSystem):

def __init__(self, ballots, tie_breaker=None, required_winners=1):
    super(Ponderado, self).__init__(ballots, tie_breaker=tie_breaker, required_winners=required_winners)

def calculate_results(self):

    # Standardize the ballot format and extract the candidates
    self.candidates = set()
    for ballot in self.ballots:

        # Convert single candidate ballots into ballot lists
        if not isinstance(ballot["ballot"], types.ListType):
            ballot["ballot"] = [ballot["ballot"]]

        # Ensure no ballot has an excess of votes
        if len(ballot["ballot"]) > self.required_winners:
            raise Exception("A ballot contained too many candidates")

        # Add all candidates on the ballot to the set
        self.candidates.update(set(ballot["ballot"]))

    # Sum up all votes for each candidate with weight!!
    self.tallies = dict.fromkeys(self.candidates, 0)
    for ballot in self.ballots:
        for icand in range(0,len(ballot["ballot"])):
            candidate = ballot["ballot"][icand]
            peso = 1./(1+2*icand)
            self.tallies[candidate] += ballot["count"]*peso
    tallies = copy.deepcopy(self.tallies)

    # Determine which candidates win
    winning_candidates = set()
    while len(winning_candidates) < self.required_winners:

        # Find the remaining candidates with the most votes
        largest_tally = max(tallies.values())
        top_candidates = matching_keys(tallies, largest_tally)

        # Reduce the found candidates if there are too many
        if len(top_candidates | winning_candidates) > self.required_winners:
            self.tied_winners = top_candidates.copy()
            while len(top_candidates | winning_candidates) > self.required_winners:
                top_candidates.remove(self.break_ties(top_candidates, True))

        # Move the top candidates into the winning pile
        winning_candidates |= top_candidates
        for candidate in top_candidates:
            del tallies[candidate]

    self.winners = winning_candidates

def as_dict(self):
    data = super(Ponderado, self).as_dict()
    data["tallies"] = self.tallies
    return data
@antviro
Copy link
Author

antviro commented Oct 28, 2014

Perhaps, it could be added to this suggested new method a selector for different weighting functions. For instance the above included St. Lague weighting function given by 1/(1+2(n-1)) as default and another extra option like a Hont based weighting function 1/(1+n-1)=1/n

Where n is the position on the preferential vote from n=1 for the first selection to the last one

@antviro antviro closed this as completed Oct 28, 2014
@antviro antviro reopened this Oct 28, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant