def test_tuple_ballots(self): # Generate data input_tuple = [ { "count": 1, "ballot": (("A"), ("B", "C")) }, { "count": 1, "ballot": (("B"), ("A"), ("C")) }, ] input_list = [ { "count": 1, "ballot": [["A"], ["B", "C"]] }, { "count": 1, "ballot": [["B"], ["A"], ["C"]] }, ] output_tuple = SchulzeMethod( input_tuple, ballot_notation=SchulzeMethod.BALLOT_NOTATION_GROUPING).as_dict() output_list = SchulzeMethod( input_list, ballot_notation=SchulzeMethod.BALLOT_NOTATION_GROUPING).as_dict() # Run tests self.assertEqual(output_tuple, output_list)
def vote(ballots): output = "" if (choice == 1): output = SchulzeMethod(ballots, ballot_notation=CondorcetHelper. BALLOT_NOTATION_GROUPING).as_dict() if (choice == 2): output = RankedPairs( ballots, ballot_notation=RankedPairs.BALLOT_NOTATION_GROUPING).as_dict() if 'tied_winners' in output.keys(): #print(output['tied_winners']) return output['tied_winners'] return output['winner']
def test_rating_format(self): # Generate data input = [ {"count": 12, "ballot": {"Andrea": 10, "Brad": 5, "Carter": 3}}, {"count": 26, "ballot": {"Andrea": 10, "Carter": 5, "Brad": 3}}, {"count": 12, "ballot": {"Andrea": 10, "Carter": 5, "Brad": 3}}, {"count": 13, "ballot": {"Carter": 10, "Andrea": 5, "Brad": 3}}, {"count": 27, "ballot": {"Brad": 10}} ] output = SchulzeMethod(input, ballot_notation=SchulzeMethod.BALLOT_NOTATION_RATING).as_dict() # Run tests self.assertEqual(output, { "candidates": set(['Carter', 'Brad', 'Andrea']), "pairs": { ('Andrea', 'Brad'): 63, ('Brad', 'Carter'): 39, ('Carter', 'Andrea'): 13, ('Andrea', 'Carter'): 50, ('Brad', 'Andrea'): 27, ('Carter', 'Brad'): 51 }, "strong_pairs": { ('Andrea', 'Brad'): 63, ('Carter', 'Brad'): 51, ('Andrea', 'Carter'): 50 }, "winner": 'Andrea' })
def test_tiebreaker_bug(self): # Generate data input = [ { "count": 1, "ballot": [["A"], ["B", "C"]] }, { "count": 1, "ballot": [["B"], ["A"], ["C"]] }, ] output = SchulzeMethod( input, ballot_notation=SchulzeMethod.BALLOT_NOTATION_GROUPING).as_dict() # Run tests self.assertEqual(output['candidates'], set(['A', 'B', 'C'])) self.assertEqual( output['pairs'], { ('A', 'B'): 1, ('A', 'C'): 2, ('B', 'A'): 1, ('B', 'C'): 1, ('C', 'A'): 0, ('C', 'B'): 0, }) self.assertEqual(output['strong_pairs'], { ('A', 'C'): 2, ('B', 'C'): 1, }) self.assertEqual(output['tied_winners'], set(['A', 'B']))
def test_grouping_format(self): # Generate data input = [ { "count": 12, "ballot": [["Andrea"], ["Brad"], ["Carter"]] }, { "count": 26, "ballot": [["Andrea"], ["Carter"], ["Brad"]] }, { "count": 12, "ballot": [["Andrea"], ["Carter"], ["Brad"]] }, { "count": 13, "ballot": [["Carter"], ["Andrea"], ["Brad"]] }, { "count": 27, "ballot": [["Brad"]] }, ] output = SchulzeMethod( input, ballot_notation=SchulzeMethod.BALLOT_NOTATION_GROUPING).as_dict() # Run tests self.assertEqual( output, { "candidates": {"Carter", "Brad", "Andrea"}, "pairs": { ("Andrea", "Brad"): 63, ("Brad", "Carter"): 39, ("Carter", "Andrea"): 13, ("Andrea", "Carter"): 50, ("Brad", "Andrea"): 27, ("Carter", "Brad"): 51, }, "strong_pairs": { ("Andrea", "Brad"): 63, ("Carter", "Brad"): 51, ("Andrea", "Carter"): 50, }, "winner": "Andrea", 'placements': [{ 'candidates': {'Andrea'} }, { 'candidates': {'Carter'}, 'points': 51 }, { 'candidates': {'Brad'}, 'points': 0 }], }, )
def run_schulze(self): # Only attempt if there are ballots if self.has_ballots(): results = SchulzeMethod( self.get_ballots(), ballot_notation=CondorcetHelper.BALLOT_NOTATION_GROUPING ).as_dict() else: results = None return results
def get_winning_movie(self): user_attendences = self.get_registered_userattend() # Avoid rekursion error if not user_attendences: winning_movie = None vote_result = None runtime = 0 else: pref_orderings = get_pref_lists(user_attendences) input_dict = prepare_voting_dict(pref_orderings) vote_result = SchulzeMethod(input_dict, ballot_notation=CondorcetHelper. BALLOT_NOTATION_GROUPING).as_dict() # check for tied winners try: # take tied movies if exist winner_movies_ids = vote_result["tied_winners"] tied_winners = True except KeyError: winner_movies_id = vote_result["winner"] tied_winners = False if tied_winners: # we now randomly select one of the tied winners \ # by using a hashed random number # convert set to list winner_movies_ids = list(winner_movies_ids) # order list in order to remove \ # ambiguity in set to list conversion winner_movies_ids.sort() num_ties = len(winner_movies_ids) # seeding random with the movienight id ensures randomness \ # between movienights and \ # consistent winner for a single movienight random.seed(a=self.id, version=2) winning_index = random.randint(0, num_ties - 1) winner_movies_id = winner_movies_ids[winning_index] winning_movie = Movie.objects.get(pk=winner_movies_id) runtime = winning_movie.get_runtime_int() return winning_movie, vote_result, runtime
def test_tiebreaker_bug(self): # Generate data input = [ { "count": 1, "ballot": [["A"], ["B", "C"]] }, { "count": 1, "ballot": [["B"], ["A"], ["C"]] }, ] input_copy = [ { "count": 1, "ballot": [["A"], ["B", "C"]] }, { "count": 1, "ballot": [["B"], ["A"], ["C"]] }, ] output = SchulzeMethod( input, ballot_notation=SchulzeMethod.BALLOT_NOTATION_GROUPING).as_dict() # Run tests self.assertEqual(output["candidates"], {"A", "B", "C"}) self.assertEqual( output["pairs"], { ("A", "B"): 1, ("A", "C"): 2, ("B", "A"): 1, ("B", "C"): 1, ("C", "A"): 0, ("C", "B"): 0, }, ) self.assertEqual(output["strong_pairs"], { ("A", "C"): 2, ("B", "C"): 1 }) self.assertEqual(output["tied_winners"], {"A", "B"}) self.assertEqual(input, input_copy)
def get_results(self, poll, save=False): """ Compute Schulze ballot results :param poll: Poll instance :param save: Save results :return: Results """ votes = {} for vote in Vote.select().where(Vote.poll == poll): votes.setdefault(vote.choices, 0) votes[vote.choices] += 1 inputs = [] for choices, count in votes.items(): inputs.append( dict(count=count, ballot=[[choice] for choice in choices.split()])) if poll.winners == 1: from py3votecore.schulze_method import SchulzeMethod outputs = SchulzeMethod(inputs, ballot_notation=SchulzeMethod. BALLOT_NOTATION_GROUPING).as_dict() if save: winner = outputs['winner'] Candidate.update(winner=True).where( Candidate.poll == poll, Candidate.indice == winner).execute() else: from py3votecore.schulze_stv import SchulzeSTV outputs = SchulzeSTV( inputs, required_winners=poll.winners, ballot_notation=SchulzeSTV.BALLOT_NOTATION_GROUPING).as_dict() if save: winners = outputs['winners'] Candidate.update(winner=True).where( Candidate.poll == poll, Candidate.indice.in_(winners)).execute() return outputs
''' from py3votecore.schulze_method import SchulzeMethod from py3votecore.condorcet import CondorcetHelper votes = [] candidates = set() while True: try: v = list(input().strip().upper()) candidates |= set(v) votes.append(v) except EOFError: break ballots = [] for v in votes: d = {'count': 1} order = [[c] for c in v] order.append(list(candidates - set(v))) d['ballot'] = order ballots.append(d) result = SchulzeMethod( ballots, ballot_notation=CondorcetHelper.BALLOT_NOTATION_GROUPING).as_dict() for k, v in result.items(): print('{}: {}'.format(k, v)) winner = result['winner'] print('---') print('The candidate \'{}\' is the Final Winner !!!'.format(winner))
def test_wiki_example2(self): # Generate data input = [{ "count": 5, "ballot": [["A"], ["C"], ["B"], ["E"], ["D"]] }, { "count": 5, "ballot": [["A"], ["D"], ["E"], ["C"], ["B"]] }, { "count": 8, "ballot": [["B"], ["E"], ["D"], ["A"], ["C"]] }, { "count": 3, "ballot": [["C"], ["A"], ["B"], ["E"], ["D"]] }, { "count": 7, "ballot": [["C"], ["A"], ["E"], ["B"], ["D"]] }, { "count": 2, "ballot": [["C"], ["B"], ["A"], ["D"], ["E"]] }, { "count": 7, "ballot": [["D"], ["C"], ["E"], ["B"], ["A"]] }, { "count": 8, "ballot": [["E"], ["B"], ["A"], ["D"], ["C"]] }] output = SchulzeMethod( input, ballot_notation=SchulzeMethod.BALLOT_NOTATION_GROUPING).as_dict() # Run tests self.assertEqual( output, { 'candidates': set(['A', 'C', 'B', 'E', 'D']), 'pairs': { ('A', 'B'): 20, ('A', 'C'): 26, ('A', 'D'): 30, ('A', 'E'): 22, ('B', 'A'): 25, ('B', 'C'): 16, ('B', 'D'): 33, ('B', 'E'): 18, ('C', 'A'): 19, ('C', 'B'): 29, ('C', 'D'): 17, ('C', 'E'): 24, ('D', 'A'): 15, ('D', 'B'): 12, ('D', 'C'): 28, ('D', 'E'): 14, ('E', 'A'): 23, ('E', 'B'): 27, ('E', 'C'): 21, ('E', 'D'): 31 }, 'strong_pairs': { ('B', 'D'): 33, ('E', 'D'): 31, ('A', 'D'): 30, ('C', 'B'): 29, ('D', 'C'): 28, ('E', 'B'): 27, ('A', 'C'): 26, ('B', 'A'): 25, ('C', 'E'): 24, ('E', 'A'): 23 }, 'actions': [{ 'edges': set([('E', 'A')]) }, { 'edges': set([('C', 'E')]) }, { 'nodes': set(['A', 'C', 'B', 'D']) }], 'winner': 'E' })
def _calculate_results(unresolved): """ Given a QuerySet of unresolved topics (with expired deadlines), resolve them into results, possibly indicating a tie of some sort. TODO: Handle the case of abstaning being a "winning" option. """ extra = '' for topic in unresolved: # if topic.agenda.quorum: # raise Exception, '%d / %d' % (topic.agenda.quorum, topic.num_voters()) if topic.agenda.quorum and topic.num_voters() < topic.agenda.quorum: # Mark invalid with no results. Somewhat counter-intuitively, # we consider the results to have been "calculated" in this case # (specifically, we calculated that there are no valid results). topic.invalid = True topic.result_calculated = True topic.save() continue # Currently, proceed with results even if there are fewer results # than expected. It is conceivable that this is a valid outcome, # for instance, if only three candidates receive any votes in a Board # election, then there should be only three winners even though there # are four or five positions. options = topic.counted_options().filter(num_votes__gt=0) num_options = options.count() if topic.vote_type.name == TYPE_CHARTER: # Charter amendments require a 2/3 majority. for_option = options.get(name='For') against_option = options.get(name='Against') total_votes = for_option.num_votes + against_option.num_votes if for_option.num_votes >= (total_votes * (2.0 / 3.0)): for_option.result = True for_option.save() else: against_option.result = True against_option.save() # It's not possible for this sort of measure to tie- it either reaches # the two-thirds threshold or it does not. topic.invalid = False topic.result_calculated = True topic.save() extra = ('\n\nPlease note that Charter Amendments require a 2/3 ' 'majority to pass.') elif not topic.vote_type.max_votes: # evaluate Schulze method. First collect votes, than use library. voters = User.objects.filter(votes__option__topic=topic).distinct() options = topic.options.all() ballots = [] for voter in voters: votes = Vote.objects.filter(option__in=options, voter=voter)\ .order_by('rank') ordered_votes = [] last_rank = votes[0].rank - 1 current_rank = 0 for vote in votes: if vote.rank == last_rank: ordered_votes[-1].append(vote.option_id) else: ordered_votes.append([vote.option_id]) last_rank = vote.rank current_rank += 1 vote.rank = current_rank vote.save() ballot = {'ballot': ordered_votes} ballots.append(ballot) result = SchulzeMethod(ballots, ballot_notation="grouping") if hasattr(result, 'tied_winners'): # Schulze method can be tied as well, treat as other ties options = Option.objects.filter(id__in=result.tied_winners) for option in options: option.result = True option.save() topic.invalid = True topic.result_calculated = True topic.save() else: option = Option.objects.get(id=result.winner) option.result = True option.save() options = options.exclude(id=result.winner) for option in options: option.result = False option.save() topic.result_calculated = True topic.save() elif topic.vote_type.max_votes <= topic.vote_type.max_winners: # Flag ties that affect the validity of the results, # and set any tied options after the valid winning range # to a "winning" result as well, indicating that they are all # equally plausible as winners despite producing more winners # than are allowed. i = topic.vote_type.max_winners while (i > 0 and i < num_options and options[i - 1].num_votes == options[i].num_votes): topic.invalid = True # Note that setting options[i].result = True and then # saving options[i] does not work, probably as a side effect # of evaluationg the options queryset (it's not actualy an array) option = options[i] option.result = True option.save() i += 1 # Set all non-tied winning results. for option in options[0:topic.vote_type.max_winners]: option.result = True option.save() topic.result_calculated = True topic.save() else: return _send_result_email(topic, extra)
if "tie_breaker" in config: tie_breaker = config['tie_breaker'] result_schulze_pr = SchulzePR( ballots, winner_threshold=config['winner_threshold'], tie_breaker=tie_breaker, ballot_notation=CondorcetHelper.BALLOT_NOTATION_GROUPING).as_dict() else: tie_breaker = [] result_schulze_pr = SchulzePR( ballots, winner_threshold=config['winner_threshold'], ballot_notation=CondorcetHelper.BALLOT_NOTATION_GROUPING).as_dict() print(result_schulze_pr) result_schulze_method = SchulzeMethod(ballots).as_dict() print(result_schulze_method) print() winners = [] tie = False for round in result_schulze_pr["rounds"]: if "tied_winners" in round and not round['winner'] in tie_breaker: print(round) tie = True tie_between = [] for t in round['tied_winners']: tie_between.append(t) break else:
"ballot": [["A"], ["C"], ["D"], ["B"]] }, { "count": 9, "ballot": [["B"], ["A"], ["C"], ["D"]] }, { "count": 8, "ballot": [["C"], ["D"], ["A"], ["B"]] }, { "count": 5, "ballot": [["D"], ["A"], ["B"], ["C"]] }, { "count": 5, "ballot": [["D"], ["B"], ["C"], ["A"]] }] res = SchulzeMethod( ballots, ballot_notation=CondorcetHelper.BALLOT_NOTATION_GROUPING).as_dict() print(res) @dataclass class Ballot: """ Допускаются отдинаковые ранги для разных кандидатов """ total_num: int ranking: SortedList['Vote'] # Tuples of (rank, candidate id) def best(self): rank, res = self.ranking[-1], [] for r, c_id in reversed(self.ranking):
def test_wiki_example(self): # Generate data input = [ { "count": 3, "ballot": [["A"], ["C"], ["D"], ["B"]] }, { "count": 9, "ballot": [["B"], ["A"], ["C"], ["D"]] }, { "count": 8, "ballot": [["C"], ["D"], ["A"], ["B"]] }, { "count": 5, "ballot": [["D"], ["A"], ["B"], ["C"]] }, { "count": 5, "ballot": [["D"], ["B"], ["C"], ["A"]] }, ] output = SchulzeMethod( input, ballot_notation=SchulzeMethod.BALLOT_NOTATION_GROUPING).as_dict() # Run tests self.assertEqual( output, { "candidates": {"A", "C", "B", "D"}, "pairs": { ("A", "B"): 16, ("A", "C"): 17, ("A", "D"): 12, ("B", "A"): 14, ("B", "C"): 19, ("B", "D"): 9, ("C", "A"): 13, ("C", "B"): 11, ("C", "D"): 20, ("D", "A"): 18, ("D", "B"): 21, ("D", "C"): 10, }, "strong_pairs": { ("D", "B"): 21, ("C", "D"): 20, ("B", "C"): 19, ("D", "A"): 18, ("A", "C"): 17, ("A", "B"): 16, }, "actions": [ { "edges": {("A", "B")} }, { "edges": {("A", "C")} }, { "nodes": {"A"} }, { "edges": {("B", "C")} }, { "nodes": {"B", "D"} }, ], "winner": "C", 'placements': [{ 'candidates': {'C'} }, { 'candidates': {'D'}, 'points': 39 }, { 'candidates': {'A'}, 'points': 33 }, { 'candidates': {'B'}, 'points': 19 }], }, )