Created
April 2, 2020 05:36
-
-
Save joriki/28232922bbf6f949082855f325a6c434 to your computer and use it in GitHub Desktop.
Apply various methods of apportioning seats in a parliament; see https://math.stackexchange.com/questions/3605591.
This file contains 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
import java.io.IOException; | |
import java.util.Arrays; | |
import java.util.Comparator; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.Map; | |
import java.util.PriorityQueue; | |
import java.util.Queue; | |
import java.util.Set; | |
import info.joriki.io.Util; | |
public class Question3605591 { | |
final static int nseats = 435; | |
final static int nstates = 50; | |
final static int ncensus = 11; | |
// This should be set to the name of a file that contains the data from Table 1 at | |
// https://www.census.gov/content/dam/Census/library/publications/2011/dec/c2010br-08.pdf | |
final static String censusFile = "<pathname>"; | |
static class State { | |
String name; | |
int population; | |
int seats; | |
Map<Comparator<State>,Integer> apportionments = new HashMap<>(); | |
public State(String name,int population,int seats) { | |
this.name = name; | |
this.population = population; | |
this.seats = seats; | |
} | |
public String toString() { | |
return "State [name=" + name + ", population=" + population + ", seats=" + seats + "]"; | |
} | |
} | |
static abstract class ApportionmentComparator implements Comparator<State> { | |
public int compare(State s1,State s2) { | |
return (int) Math.signum(quotient(s2) - quotient(s1)); | |
} | |
private double quotient (State s) { | |
if (!s.apportionments.containsKey(this)) | |
s.apportionments.put(this, 0); | |
return s.population / divisor (s.apportionments.get(this)); | |
} | |
abstract protected double divisor(int seats); | |
}; | |
static class DeltaComparator extends ApportionmentComparator { | |
private double delta; | |
public DeltaComparator(double delta) { | |
this.delta = delta; | |
} | |
protected double divisor(int seats) { | |
return seats + delta; | |
} | |
} | |
static class HuntingtonHillComparator extends ApportionmentComparator { | |
protected double divisor(int seats) { | |
return Math.sqrt(seats * (seats + 1)); | |
} | |
} | |
final static ApportionmentComparator [] comparators = { | |
new HuntingtonHillComparator(), | |
new DeltaComparator(0), | |
new DeltaComparator(1/2.), | |
new DeltaComparator(1), | |
}; | |
static char [] data; | |
static int i; | |
public static void main(String [] args) throws IOException { | |
Set<State> states = new HashSet<>(); | |
data = new String(Util.undump(censusFile)).replace("(X)","0").toCharArray(); | |
outer: | |
for (i = 0;;) { | |
int beg = i; | |
while (Character.isAlphabetic(data [i]) || data [i] == ' ') | |
i++; | |
String name = new String(data,beg,i - beg); | |
while (!Character.isDigit(data [i])) | |
i++; | |
int population = readCommaDelimitedInteger(); | |
readCommaDelimitedInteger(); // resident population | |
readCommaDelimitedInteger(); // overseas population | |
int r = i; | |
while (Character.isDigit(data [r])) | |
r++; | |
r -= i; | |
int ndigits = r / ncensus; | |
if (r % ncensus != 0 && data [i] < '4') | |
ndigits++; | |
int representatives = Integer.parseInt(new String(data,i,ndigits)); | |
State state = new State(name, population, representatives); | |
states.add(state); | |
while (!Character.isAlphabetic(data [i])) { | |
i++; | |
if (i == data.length) | |
break outer; | |
} | |
} | |
if (states.size() != nstates) | |
throw new Error(); | |
State [] stateArray = states.toArray(new State [nstates]); | |
Arrays.sort(stateArray,comparators [2]); | |
int rank = 0; | |
for (State state : stateArray) | |
System.out.println(++rank + " : " + state); | |
for (ApportionmentComparator comparator : comparators) { | |
Queue<State> queue = new PriorityQueue<>(comparator); | |
queue.addAll(states); | |
for (int seat = 0;seat < nseats;seat++) { | |
State state = queue.poll(); | |
state.apportionments.put(comparator,state.apportionments.get (comparator) + 1); | |
queue.add(state); | |
} | |
} | |
for (Comparator<State> comparator : comparators) | |
if (comparator != comparators [0]) { | |
for (State state : states) { | |
int diff = state.apportionments.get(comparator) - state.apportionments.get(comparators [0]); | |
if (diff != 0) | |
System.out.println(diff + " " + state); | |
} | |
System.out.println(); | |
} | |
for (Comparator<State> comparator : comparators) { | |
double s = 0; | |
double s2 = 0; | |
double total = 0; | |
for (State state : states) { | |
double weight = state.population; | |
double voterWeight = state.apportionments.get(comparator) / (double) state.population; | |
s += weight * voterWeight; | |
s2 += weight * (voterWeight * voterWeight); | |
total += weight; | |
} | |
s /= total; | |
s2 /= total; | |
System.out.println(s + " ± " + (Math.sqrt(s2 - s * s))); | |
} | |
} | |
private static int readCommaDelimitedInteger() { | |
int result = 0; | |
for (int ndigits = 0;;i++) { | |
if (data [i] == ',') | |
ndigits = 0; | |
else { | |
if (!Character.isDigit(data [i])) | |
throw new Error(); | |
if (++ndigits > 3) | |
break; | |
result *= 10; | |
result += data [i] - '0'; | |
} | |
} | |
return result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment