From 6ae977ea229bd09ccccaef150dc4726c72b737cc Mon Sep 17 00:00:00 2001 From: benjaminkrenn Date: Thu, 9 Jan 2020 11:37:45 +0100 Subject: [PATCH] implement threshold. add austria example. --- README.md | 3 ++- __init__.py | 0 apportionment.py | 25 +++++++++++++++++++++---- examples/__init__.py | 0 examples/austria_examples.py | 17 +++++++++++++++++ example.py => examples/example.py | 2 ++ examples/nr_wahlen.txt | 9 +++++++++ 7 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 __init__.py create mode 100644 examples/__init__.py create mode 100644 examples/austria_examples.py rename example.py => examples/example.py (92%) create mode 100644 examples/nr_wahlen.txt diff --git a/README.md b/README.md index b1f02de..ca67015 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,8 @@ D'Hondt (Jefferson) method which is indeed the [official result](https://www.bmi.gv.at/412/Europawahlen/Europawahl_2019). -Another example can be found in [example.py](example.py). +Another example can be found in [examples/example.py](examples/example.py). +An example with the Austrian National Council elections can be found in [examples/austria_examples.py](examples/austria_examples.py) ## References diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apportionment.py b/apportionment.py index 1445b0a..03dfbda 100644 --- a/apportionment.py +++ b/apportionment.py @@ -4,22 +4,39 @@ import math from fractions import Fraction -def method(method, votes, seats, parties=string.letters, +def method(method, votes, seats, parties=string.letters, threshold=None, verbose=True): + filtered_votes = apply_threshold(votes, threshold) if method == "quota": - return quota(votes, seats, parties, verbose) + return quota(filtered_votes, seats, parties, verbose) elif method in ["lrm", "hamilton", "largest_remainder"]: - return largest_remainder(votes, seats, parties, verbose) + return largest_remainder(filtered_votes, seats, parties, verbose) elif method in ["dhondt", "jefferson", "saintelague", "webster", "huntington", "hill", "adams", "dean", "smallestdivisor", "harmonicmean", "equalproportions", "majorfractions", "greatestdivisors"]: - return divisor(votes, seats, method, parties, verbose) + return divisor(filtered_votes, seats, method, parties, verbose) else: raise NotImplementedError("apportionment method " + method + " not known") +def apply_threshold(votes, threshold): + """Sets vote counts to 0 if threshold is not met.""" + if threshold is not None: + v = [] + combined_votes = sum(votes) + min_votes = combined_votes * threshold + for vote in votes: + if vote < min_votes: + v.append(0) + else: + v.append(vote) + return v + else: + return votes + + def __print_results(representatives, parties): for i in range(len(representatives)): print(" "+str(parties[i])+": "+str(representatives[i])) diff --git a/examples/__init__.py b/examples/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/examples/austria_examples.py b/examples/austria_examples.py new file mode 100644 index 0000000..30c4873 --- /dev/null +++ b/examples/austria_examples.py @@ -0,0 +1,17 @@ +from __future__ import print_function +import sys +sys.path.insert(0, '..') +import apportionment + +with open("./nr_wahlen.txt", "r") as f: + + for line in f: + result = eval(line) + print(result[0]) + print(apportionment.method("dhondt", result[2], + sum(result[3]), + parties=result[1], + threshold=.04, + verbose=False)) + # actual results + print(result[3]) diff --git a/example.py b/examples/example.py similarity index 92% rename from example.py rename to examples/example.py index 72aa2ee..e14d1fc 100644 --- a/example.py +++ b/examples/example.py @@ -1,4 +1,6 @@ from __future__ import print_function +import sys +sys.path.insert(0, '..') import apportionment diff --git a/examples/nr_wahlen.txt b/examples/nr_wahlen.txt new file mode 100644 index 0000000..5cb0b10 --- /dev/null +++ b/examples/nr_wahlen.txt @@ -0,0 +1,9 @@ +(2019,["ÖVP", "SPÖ", "FPÖ", "NEOS", "JETZT", "GRÜNE", "KPÖ", "WANDL", "BZÖ", "BIER", "CPÖ", "GILT", "SLP"], [1789417, 1011868, 772666, 387124, 89169, 664055, 32736, 22168, 760, 4946, 260, 1767, 310], [71, 40, 31, 15, 0, 26, 0, 0, 0, 0, 0, 0, 0]) +(2017, ["SPÖ", "ÖVP", "FPÖ", "GRÜNE", "NEOS", "PILZ", "GILT", "FLÖ", "KPÖ", "WEIßE", "SLP", "EUAUS", "M", "CPÖ", "NBZ", "ODP"], [1361746, 1595526, 1316442, 192638, 268518, 223543, 48234, 8889, 39689, 9167, 713, 693, 221, 425, 2724, 761], [52, 62, 51, 0, 10, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) +(2013, ["SPÖ", "ÖVP", "FPÖ","BZÖ", "GRÜNE", "FRANK", "NEOS", "KPÖ", "PIRAT", "CPÖ", "WANDL", "M", "EUAUS", "SLP"], [1258605, 1125876, 962313, 165746, 582657, 268679, 243946, 48175, 36265, 6647, 3051, 490, 510, 947], [52, 47, 40, 0, 24, 11, 9, 0, 0, 0, 0, 0, 0, 0]) +(2008, ["SPÖ", "ÖVP", "GRÜNE", "FPÖ", "BZÖ", "FRITZ", "DC", "KPÖ", "LIF", "RETTÖ", "LINKE", "KLEMENTE", "LINKE", "STARK", "TRP"], [1430206, 1269656, 509936, 857029, 522933, 86194, 31080, 37362, 102249, 35718, 349, 347, 1789, 237, 2224], [57, 51, 20, 34, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) # LINKE = Die Linke und LINKE = Linke +(2006, ["ÖVP", "SPÖ", "FPÖ", "GRÜNE", "BZÖ", "KPÖ", "MATIN", "NFÖ", "IVE", "STARK", "SAU", "SLP"], [1616493, 1663986, 519598, 520130, 193539, 47578, 131688, 10594, 592, 312, 1514, 2257], [66, 68, 21, 21, 7, 0, 0, 0, 0, 0, 0, 0]) +(2002, ["SPÖ", "FPÖ", "ÖVP", "GRÜNE", "KPÖ", "LIF", "DD", "CWG", "SLP"], [1792499, 491328, 2076833, 454980, 27568, 48083, 2439, 2009, 3906], [69, 18, 79, 17, 0, 0, 0, 0, 0]) +(1999, ["SPÖ", "ÖVP", "FPÖ", "LIF", "GRÜNE", "KPÖ", "DU", "NEIN", "CWG"], [1532448, 1243672, 1244087, 168612, 342260, 22016, 46943, 19286, 3030], [65, 52, 52, 0, 14, 0, 0, 0, 0]) +(1995, ["SPÖ", "ÖVP", "FPÖ", "GRÜNE", "LIF", "NEIN", "KPÖ", "ÖNP", "DBP"], [1843474, 1370510, 1060377, 233208, 267026, 53176, 13938, 1634, 830], [71, 52, 41, 9, 10, 0, 0, 0, 0]) +(1994, ["SPÖ", "ÖVP", "FPÖ", "GRÜNE", "LIF", "VGÖ", "KPÖ", "BGÖ", "NEIN", "CWG", "ÖNP", "FG", "DBP"], [1617804, 1281846, 1042332, 338538, 276580, 5776, 11919, 2504, 41492, 9051, 4209, 482, 581], [65, 52, 42, 13, 11, 0, 0, 0, 0, 0, 0, 0, 0]) \ No newline at end of file