Yep, I wrote starvote, an election tabulator that supports STAR Voting and several of its variants. (pip install starvote
!) But I assure you I’m not an election scientist–just an interested, mildly-informed amateur. So I’m not sure how much expertise I have to lend. I’d feel better if we simply tabled this until a certain banned community member returns in a month or two, as they’re an expert in these areas and can speak with far more authority. Though I’m willing to answer questions in the interim as best I can.
It seems to me that Helios brought a lot of other trappings like “here’s a hash that guarantees your vote was counted” and other stuff I didn’t really understand but seemed nice. I liked the “you can vote as many times as you like, we’ll only keep the last one” feature even if I never needed it. I assume there’s a lot of porcelain and plumbing that we (or someone) would need to reimplement if we want to abandon Helios and host our own elections, and voting is important enough that you want some assurances that it was conducted fairly and accurately.
FWIW, STAR Voting is pretty easy to tabulate. I spent a lot of time in my library hammering out the API and sorting out tiebreakers–the latter of which I’m assured are exceedingly rare in real-world elections. (My library does maintain 100% coverage though, which I find reassuring.) The multiwinner variant, “Bloc STAR”, is only slightly more complicated. The proportional representation variants got very complicated however.
I think I’d prefer simple multiwinner (“Bloc STAR”) to a proportional representation scheme.
First, a clarification on terminology: “STAR-PR” is not a specific electoral system. It’s a label given to officially-approved STAR Voting electoral systems that support proportional representation. So far there’s only one such approved system, “Allocated Score Voting”. (As a result, sloppy people use “Allocated Score Voting” and “STAR-PR” interchangeably. I’m pedantic enough that I try to avoid it.) My starvote library implements three STAR-Voting-ish schemes for proportional reprentation, including Allocated Score Voting.
Here’s the problem proportional representation solves: if 60% of your populace is Republican, and 40% is Democrat, and you have five seats on the city council, how do you want to fill them? In a straight multiwinner election, the majority would presumably vote in five Republicans. Is that best? “Proportional representation” means you’d allocate the winners based on them representing portions of the electorate; in the example I just gave, a PR scheme would likely elect three Republicans and two Democrats. Is that better? Maybe! Or maybe not! Which scheme leads to better results is highly subjective.
Often proportional representation is done by organizing around / voting for political parties. That’s called party-list proportional representation, and it’s used all over the world. But we don’t have political parties in the Python core development electorate.
Lucky for us, the STAR-Voting-adjacent PR schemes work in a different way, that doesn’t require political parties. But what they do is hella complicated. I cover it in detail in the starvote README, but in a nutshell: when the electoral system elects a candidate, all the ballots that helped elect that candidate are weakened (“re-weighted”) or outright thrown away (“allocated”). It’s like, you won, your vote is represented in the outcome, you’ve had your say. Now we need to amplify the ballots from the other voters who haven’t gotten anyone elected yet, and we do that by reducing how much your ballots count in subsequent rounds.
“Allocated Score Voting” is frustrating because it gives up one of the design tenets I like about STAR Voting. In STAR Voting, every vote is always counted, in every round; at no point is a vote ever thrown away. (Unlike IRV.) Unfortunately, “Allocated Score Voting” does allocate votes, meaning it does throw them away. That’s also true of “Sequential Score Voting”, an electoral system I implemented just for fun, just because I was curious about it. Of the PR systems I implemented, only “Reweighted Range Voting” never throws away votes. So I find that more appealing. (Technically “Reweighted Range” isn’t a STAR Voting variant, it’s a Score Voting variant. It doesn’t have STAR’s runoff round. AFAIK none of these methods are widely used, though Reweighted Range is now used to pick the five nominees for the Oscars in one or more categories.)
Another downside: all three PR schemes use a lot of fractions. That’s one feature of my starvote library: I use Fraction
objects for all the tabulation, never floating-point. My tabulation is 100% deterministic and never ever loses precision. But with all three PR methods, this does have the downside of making the output look ridiculous. Here’s some sample output from one of my test cases:
[Reweighted Range Voting: Round 5: Score round]
The highest-scoring candidate wins a seat.
Jo Jorgensen -- 866+ 46490201/81124680 (average 70300463081/235991694120) -- First place
Adam Kokesh -- 838+ 254151133/535422888 (average 448938531277/1557545181192)
Daniel Behrman -- 724+ 64381511/178474296 (average 129279771815/519181727064)
Sam Robb -- 572+ 25687/1312311 (average 750667579/3817512699)
John Monds -- 552+ 69926651/76488984 (average 42291845819/222506454456)
(One of my todo items for starvote is to use floating-point, but just for presentation. Tabulation would still strictly use Fraction
, but at the end when I print out the result I think I should convert to float and only print a couple of decimal places.)
Bloc STAR isn’t a PR system, and tabulating it never requires fractions. It’s far simpler to tabulate than any of the PR systems, and therefore it’s easier to get right and (if necessary) to verify by hand. I think I’d prefer straight multiwinner to this squirrely proportional representation stuff.