Created
September 13, 2013 02:50
-
-
Save stefanw/6546325 to your computer and use it in GitHub Desktop.
BTW 2009 Seat Calculator. Do not use if your democracy relies on it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
from collections import defaultdict, Counter | |
year = 2009 | |
default_mandates = 598 | |
mandates = default_mandates | |
sperrklausel = 0.05 | |
laender = ['berlin']#, 'bayern'] | |
laender_data = {} | |
for land in laender: | |
land_module = __import__(land) | |
laender_data.update(land_module.get_data(year)) | |
direct_vote = {} | |
seats = defaultdict(int) | |
zweitstimmen = Counter() | |
landzweitstimmen = defaultdict(Counter) | |
def get_direct_candidate(district, e): | |
l = [(k, v) for k, v in e['votes'].items()] | |
l.sort(key=lambda x: x[1]['count'], reverse=True) | |
if len(l) > 1 and l[0][1]['count'] == l[1][1]['count']: | |
# § 5 | |
raise Exception('Draw for direct vote at %s' % district) | |
if l[0][1].get('partyless', False): | |
# § 6 (1) Satz 2 | |
raise Exception('Independent candidate won at %s' % district) | |
return l[0] | |
for land in laender_data: | |
landesliste = {} | |
for district, votedict in laender_data[land].items(): | |
party, d = get_direct_candidate(district, votedict['E']) | |
direct_vote[district] = (party, d) | |
seats[party] += 1 | |
zweitvotes = dict([(k, v['count']) for k, v in votedict['Z']['votes'].items()]) | |
zweitstimmen.update(zweitvotes) | |
landzweitstimmen[land].update(zweitvotes) | |
totalz = float(sum(zweitstimmen.values())) | |
ignored = set() | |
for party in zweitstimmen: | |
if zweitstimmen[party] / totalz < sperrklausel and seats[party] < 3: | |
ignored.add(party) | |
# § 1 (1) Satz 3 | |
decrease_mandates = 0 | |
for party, d in direct_vote.values(): | |
if party in ignored: | |
decrease_mandates += 1 | |
mandates -= decrease_mandates | |
print "New Number of Mandates:", mandates | |
old_landzweitstimmen = dict(landzweitstimmen) | |
old_zweitstimmen = dict(zweitstimmen) | |
old_totalz = totalz | |
for land in laender_data: | |
for party in ignored: | |
if party in landzweitstimmen[land]: | |
del landzweitstimmen[land][party] | |
for party in ignored: | |
if party in zweitstimmen: | |
del zweitstimmen[party] | |
def saint_lague(zweitstimmen, mandates, ensure_seat_majority=True): | |
def distribute_seats(landeslisten, divisor): | |
seats = {} | |
ambiguous = [] | |
for party in landeslisten: | |
val = landeslisten[party] / float(divisor) | |
floatval = val - int(val) | |
if floatval > 0.5: | |
seats[party] = int(val) + 1 | |
elif floatval < 0.5: | |
seats[party] = int(val) | |
else: | |
seats[party] = int(val) | |
ambiguous.append(party) | |
return seats, ambiguous | |
total = float(sum(zweitstimmen.values())) | |
divisor = total / mandates | |
additional = defaultdict(int) | |
additional_needed = False | |
while True: | |
while True: | |
print "Distributing Seats" | |
seats, ambig = distribute_seats(zweitstimmen, divisor) | |
for p in additional: | |
seats[p] += additional[p] | |
sumseats = sum(seats.values()) | |
print "New Seats with Divisor %s: %d" % (divisor, sumseats) | |
if sumseats == mandates and len(ambig) < 2: | |
break | |
diff = mandates - sumseats | |
if diff == len(ambig): | |
# difference is equal to the number of | |
# unrounded (possibly + 1) seats, all get a seat | |
for p in ambig: | |
seats[p] += 1 | |
assert sum(seats.values()) == mandates | |
break | |
if diff > 0 and len(ambig) > diff: | |
raise Exception('Ambiguous seats, need random decision') | |
if diff < 0: | |
if int(divisor) != divisor: | |
divisor = int(divisor) | |
divisor += 1 | |
else: | |
if int(divisor) != divisor: | |
divisor = int(divisor) | |
else: | |
divisor -= 1 | |
if not ensure_seat_majority: | |
break | |
# §6 (3) | |
if additional_needed: | |
break | |
for party in zweitstimmen: | |
val = zweitstimmen[party] | |
if val * 2 > totalz and seats[party] * 2 < mandates: | |
additional[party] += 1 | |
additional_needed = True | |
if not additional_needed: | |
break | |
return seats | |
print seats | |
print saint_lague(zweitstimmen, mandates) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment