Beispiel #1
0
    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)
Beispiel #2
0
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'
        })
Beispiel #4
0
    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']))
Beispiel #5
0
    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
                }],
            },
        )
Beispiel #6
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
Beispiel #7
0
    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
Beispiel #8
0
    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)
Beispiel #9
0
 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))
Beispiel #11
0
    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'
            })
Beispiel #12
0
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:
Beispiel #14
0
    "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):
Beispiel #15
0
    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
                }],
            },
        )