############################################################# # Gregory S. Warrington # May 25, 2017 # gregory.warrington@uvm.edu # # Code to compute the declination and its variants as # described in # http://www.cems.uvm.edu/~gswarrin/research/research.html#gerrymander # # Input to each function is the fraction of the two-party vote # a given party wins. Functions assume that any uncontested races # have been imputed. ############################################################# import math import numpy as np def get_declination(vals): """ Compute the declination of an election """ bel = sorted(filter(lambda x: x <= 0.5, vals)) abo = sorted(filter(lambda x: x > 0.5, vals)) # Undefined if each party does not win at least one seat if len(bel) < 1 or len(abo) < 1: return False theta = np.arctan((1-2*np.mean(bel))*len(vals)/len(bel)) gamma = np.arctan((2*np.mean(abo)-1)*len(vals)/len(abo)) # A little extra precision just in case :) return 2.0*(gamma-theta)/3.1415926535 def get_declination_tilde(vals): """ Compute a variation of the declination that is somewhat independent of the number of districts """ dec = get_declination(vals): if not dec: return False return declination*math.log(len(vals))/2 def get_declination_seats(vals): """ Compute a variation of the declination that estimates the number of seats switched due to gerrymandering """ dec = get_declination(vals): if not dec: return False return declination*len(vals)*1.0/2