This repository was archived by the owner on Jul 26, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathanalysis.py
77 lines (61 loc) · 2.6 KB
/
analysis.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import itertools
import math
import concurrent.futures
import random
from gametype import GameType
from profile import Profile
from game import Game
from multiprocessing import Manager
class Analysis:
def __init__(self, type, profile, quota, expected_outcome=None):
self.type = type
self.profile = profile
self.quota = quota
self.expected_outcome = expected_outcome
def outcomes(self):
"""The possible outcomes for the current configuration.
Currently just loops over all permutations of the agenda, calculates the
outcome and adds the result to the set of outcomes. This is not very
efficient, so keep that in mind for larger agendas/profiles!
"""
outcomes = dict.fromkeys(self.profile.alternatives, 0)
m = len(self.profile.alternatives)
n = len(self.profile.ballots)
permutations = []
if m > 7:
# minimum between n^2 and 7!
# based on doi:10/gdtm7r, section 6.3
total = min(n**2, 5040)
for _ in range(total):
new_perm = list(random.sample(list(self.profile.alternatives), m))
while new_perm in permutations:
new_perm = list(random.sample(list(self.profile.alternatives), m))
permutations.append(new_perm)
else:
permutations = list(itertools.permutations(self.profile.alternatives))
total = math.factorial(len(self.profile.alternatives))
print(f"Testing {total} agendas...")
outcomes_temp = []
with concurrent.futures.ProcessPoolExecutor(max_workers=6) as executor:
for permutation in permutations:
outcomes_temp.append(
executor.submit(calculate_outcome, self.type, permutation, self.quota, self.profile)
)
for outcome in outcomes_temp:
result = outcome.result()
outcomes[result] = outcomes.get(result, 0) + 1
nonzero_outcomes = list(filter(lambda x: x[1] > 0, outcomes.items()))
outcome = sorted(
list(
map(lambda tup: self.profile.alternative_name(tup[0]), nonzero_outcomes)
)
)
percentage = 0
if self.expected_outcome != None:
total = sum(outcomes.values())
num_expected_outcome = outcomes[self.expected_outcome]
percentage = num_expected_outcome / total * 100
return percentage, outcome
def calculate_outcome(type, permutation, quota, profile):
game = Game(type, list(permutation), quota, profile)
return game.outcome()