#############################################################
# Gregory S. Warrington
# March 8, 2018
# 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
#
# Functions assume that any uncontested races have been imputed.
#############################################################
# input: vector of vote fractions from party A.
# oumbtput: declination value (between -1 and 1)
# declination > 0 corresponds to advantage for party B.
# declination < 0 corresponds to advantage for party A.
declination<-function(votes)
{
abo = votes[votes > 0.5] # districts won by party A
bel = votes[votes <= 0.5] # districts won by party B
# declination is undefined if one party wins all seats.
# since I don't use R, not sure if this is correct way
# to signal that that value is undefined.
if (length(bel) == 0 | length(abo) == 0) {
return(NaN)
}
# angle for party B
theta = atan((1-2*mean(bel))*length(votes)/length(bel))
# angle for party A
gamma = atan((2*mean(abo)-1)*length(votes)/length(abo))
# normalize from radians to values betwen -1 and 1
# A little extra precision just in case :)
return(2.0*(gamma-theta)/3.1415926535)
}
# input: vector of vote fractions from party A.
# oumbtput: declination-tilde value (between -1 and 1)
# declination > 0 corresponds to advantage for party B.
# declination < 0 corresponds to advantage for party A.
# scaling aims to reduce dependence on number of districts
declination_tilde<-function(votes)
{
dec = declination(votes)
if (is.nan(dec)) {
return(NaN)
}
return(dec*log(length(votes))/2)
}
# # input: vector of vote fractions from party A.
# oumbtput: estimated number of seats flipped due to asymmetry.
# positive values correspond to an advantage for party B.
# negative values correspond to an advantage for party A.
# In "Quantifying gerrymandering..." paper, I use a scaling
# factor of 1/2. In "Gerrymandering and the net..." paper we
# identify 5/12 as more appropriate.
declination_seats<-function(votes)
{
dec = declination(votes)
if (is.nan(dec)) {
return(NaN)
}
return(dec*length(votes)*5.0/12)
}
# small example that can be computed by hand.
a = c(0.3,0.3,0.7)
declination(a)
declination_tilde(a)
declination_seats(a)
# 2012 North Carolina US House results
NC2012 = c(0.767, 0.426, 0.369, 0.745, 0.425, 0.391, 0.501, 0.46, 0.469, 0.43,
0.426, 0.796, 0.432)
declination(NC2012)
declination_tilde(NC2012)
declination_seats(NC2012)
# party A wins all seats, so all should be undefined
b = c(0.62,0.7,0.87)
declination(b)
declination_tilde(b)
declination_seats(b)