# I (well, mostly claude code) simulated proportional representation methods.

*Low-ish effort post just sharing something I found fun. No AI-written text outside the figures.*

I was recently nerd-sniped by proportional representation voting, and so when playing around with claude code I decided to have it build a simulation.

![](https://39669.cdn.cke-cs.com/rQvD3VnunXZu34m86e5f/images/e63ab0e57d8121c0b10eda41700864e37b7f3b65e44f9467.png)

Hot take:

*   If you're electing a legislature and want it to be proportional, use approval ballots and seq-PAV[^uigq2ge1bjn].

Other key points:

*   There's a tradeoff between how well you represent people on average, and how much inequality there is in how well you represent people.
    *   If you disproportionately cluster winning candidates near the center of the distribution of voter preferences, this does pretty well on average, but is more unequal, vice versa for spreading winning candidates apart from each other.
*   Voting methods don't change much in their ordering on metrics as you make the distribution of voter preferences more multimodal/spiky.
*   My idealized simulation of 4-party voting does surprisingly well (but has incentive problems in the real world).
*   STV (Single Transferable Vote) spreads out the winners more and therefore has low inequality, but at the cost of lower average representativeness. Maybe there are alternative clever things to do with ranked ballots that I should explore.
*   Code is at [https://github.com/Charlie-Steiner/voting-simulation](https://github.com/Charlie-Steiner/voting-simulation), claude code really did just (apparently) work. But there's a caveat that of the things I was paying attention to I found and fixed a few crazy choices, so there's probably at least one crazy choice I didn't find.

The voter model:

*   My sim voters had preferences that lived in a 3 or 4 dimensional space. Candidates also lived in this space.
*   Candidates were drawn from the same distribution as voters.
*   Voters just preferred closer candidates to farther ones.
*   For the headline results, I sampled multimodal distributions of voter preferences - modes sampled uniformly within a ball, population split between them at uniformly random percentages, then normally distributed around their mode.
*   This accentuated the differences between different voting methods - the methods were kind of hard to understand the differences of if the population was a symmetrical blob.

The metrics:

*   I decided to use distance to the median winner as my main metric, under the model that if we're voting for a legislature, the thing I care most about is how much the legislation that passes reflects my preferences (lower distance = better).
*   I also care about inequality of this metric. I used the Theil index as a measure of inequality, because I'm too much of a hipster to use the functionally-very-similar Gini coefficient (lower Theil = better).
*   Both of these can only be done because I have access to the ground truth sim-voter preferences. This is powerful and nice, but is an extra step of disconnection from empirical feedback.
*   Most of the voting methods tested[^h9cu7bx9pwp] also have nice theoretical proportionality guarantees (with names like Extended Justified Representation). Without these I'd be more worried about goodharting.
*   I also looked at distance to the nearest winner (and inequality of that), and mean distance to all winners. Didn't really find surprises, the principal component of "how spread out were the winners" largely controlled distance to nearest winner and inequality thereof.
*   Error bars in the plot are the data standard deviation, set by how much things fluctuate as we sample different voter preferences.

The contenders:

*   Random. The winners are random. A baseline.
*   STV. [Single transferable vote](https://en.wikipedia.org/wiki/Single_transferable_vote). Uses a ranked ballot. Declare candidates with votes above a winning threshold to be winners, redistribute the fraction of votes that were above the threshold to their second place choices, if nobody won eliminate the candidate with the fewest first place votes, and repeat.
    *   If there are hidden crazy claude choices, some are likely impacting the implementation of STV. In fact, behavior of STV has changed through versions as claude found (introduced?) bugs. *Caveat lector*.
*   PAV. Proportional Approval Voting. Uses an approval ballot. See [https://arxiv.org/abs/2007.01795](https://arxiv.org/abs/2007.01795). Optimize the average 'satisfaction' of all voters, where the nth winning candidate I approve of gives me 1/n units of 'satisfaction'. seq-PAV means it picks winners greedily. seq-PAV, seq-PAV-tight, and seq-PAV-10 just give the voters different strategies for filling in their approval ballots - they approve of the closest 40%, 20%, and 10% of candidates, respectively.
*   MES. The Method of Equal Shares. Uses an approval ballot. See [https://arxiv.org/abs/2007.01795](https://arxiv.org/abs/2007.01795) again. Voters start with a budget, and there's some cost required to make candidate into a winner. Declare the 'best' candidate to be a winner, where the 'best' candidate has the lowest cost per person if you split the cost of their victory as evenly as possible among their approvers, then repeat. This just has the 40% and 20% ("tight") approval strategy variants.
    *   Beware implementation bugs here too.
*   Party. I made a spherical-cow model of proportional party representation thinking they would be bad, but actually they're kind of competitive. A "party" is just a random point in preference space. All voters vote for the nearest party. Then the most under-represented party adds its favorite non-winner candidate to the list of winners, until the list is full. 2 parties is suboptimal, but 4 parties seems to be near the Pareto frontier.

Just averaging everything into two numbers:

![](https://39669.cdn.cke-cs.com/rQvD3VnunXZu34m86e5f/images/fc219d9ac6d7eebefac9dea7acefd6bb46b8a76d3eea8823.png)

Why I think PAV is the tentative winner:

*   Approval ballots are great. STV (and hopefully other uses of ranked ballots) is fine, it's definitely up there at the Pareto frontier[^alghegwbwi], but ranking candidates is significantly more demanding of voters than approving of a subset. If the easy thing works we should do the easy thing.
*   For some reason, PAV seems to dominate MES (further exploration of this might have to start with carefully checking the MES code) - it picks winners that are more spread out, but equally good at being representative.
*   You can make your own tradeoffs. As you approve of smaller percentage of candidates, you're trading off how good the median winner is versus how good the closest winner is. Since I'm personally unsure how this tradeoff should be made, leaving it to individuals seems like a strength.
*   It's party-agnostic. If the influence of voters doesn't reach outside of their parties, we don't get some of the nice anti-extremism properties, and it can be harder for unaffiliated candidates or small parties to keep the major players "honest."

[^uigq2ge1bjn]: Sequential Proportional Approval Voting. At each step, add the candidate to the list of winners who most increases the 'satisfaction' of all voters, where if I already have N winners I approve of, getting another winner I approve of only gives me 1/(N+1) units of 'satisfaction.' Repeat until you have enough winners. 

[^h9cu7bx9pwp]: (not the party-based methods or the random baseline)  

[^alghegwbwi]: In fact, STV is very slightly beyond the Pareto frontier formed as you change voter strategy with PAV. The closest point in the the sweep I did to check this had average distance to nearest winner 0.170 STV / 0.178 PAV, average distance to median winner 0.808 STV / 0.807 PAV (in arbitrary simulated voter preference space units).