Jedidiah Barber's Personal Site

Single Transferable Vote Counter

Git repository: Link


To give an incredibly brief summary of Australia's political system, both the Federal Parliament and most of the State Parliaments are bicameral. The lower houses are generally elected by Instant Runoff, while the upper houses generally have half elections using Single Transferable Vote. There are exceptions and a whole lot of differing details, but that's the overall pattern.

In 2016, however, the Federal Parliament underwent a Double Dissolution, causing the entirety of both houses to go to an election. This had the outcome of 20 out of 76 seats going to third parties in the upper house, a record number. Even more than the 18 there were prior. As the entire purpose of a Double Dissolution is to break deadlocks in parliament, to have the outcome go in the complete opposite direction probably caused some dismay from Malcolm Turnbull and his Liberal/National government.

This raises the question: Would they have been better off had a normal election happened instead?

To calculate the likely outcome, the ballot preference data is needed. That's the easy part, as the Australian Electoral Commission makes that available here in the 'Formal preferences' section. Then, a program is needed to execute the STV algorithm, which is as follows:

  1. Set the quota of votes required for a candidate to win.
  2. Allocate the ballot papers according to first preference to each of the candidates for initial vote totals.
  3. Mark any candidate who has reached or exceeded the quota as elected.
  4. If any elected candidate has more votes than the quota, transfer the excess to the other candidates according to the next applicable preference.
  5. If no further candidates meet the quota, the candidate with the fewest votes is eliminated and their votes are transferred to the others according to next applicable preference.
  6. Repeat steps 3-5 until all seats are filled.

Seems simple enough, right? Except not really. There is a surprising amount of complexity in there, and most of it is to do with how to transfer votes around. So, in addition, there are the specifics for the version used for the Australian Senate:

My implementation also includes bulk exclusions using applied breakpoints in order to increase speed slightly and minimise superfluous logging.

At this point I'm fairly sure my program provides an accurate count. However, my numbers still differ slightly from the ones provided by the AEC's official distribution of preferences. Investigations into the exact cause are ongoing.


Calculations were done for each state using the formal preference data with vacancies set to 6 instead of 12, and the results were added to the Senators elected in 2013 to find the probable outcome. The results for ACT and NT were taken as-is, because the few Senators elected from the territories are not part of the half election cadence anyway.

Computational resources required varied from approximately 50 seconds using 46MB of memory for Tasmania, to nearly 30 minutes using 1452MB memory for NSW. The vast majority of that time was spent parsing preference data, and the program is single threaded, so there is still room for improvement. All counts were run on a Core 2 Quad Q9500.

Probable non-DD results by state
 Liberal  Liberal  Liberal National  Liberal  Liberal  Liberal
 Labor  Labor  Labor  Labor  Labor  Labor
 Liberal  National  Liberal National  Xenophon  Liberal  Liberal
 Labor  Labor  Labor  Liberal  Labor  Labor
 National  Green  One Nation  Labor  Green  Jacqui Lambie
 Green  Derryn Hinch  Liberal National  Xenophon  Liberal  Green
Probable non-DD Senate composition
Party Seats Won Continuing Senators Total Seats Difference From Actual
  Liberal/National Coalition 17 15 32 +2
  Australian Labor Party 14 10 24 -2
  Australian Greens 4 4 8 -1
  Xenophon Group 2 1 3 Nil
  Jacqui Lambie Network* 1 1 2 +1
  Liberal Democratic Party 0 1 1 Nil
  Family First Party 0 1 1 Nil
  Palmer United Party* 0 1 1 +1
  Glenn Lazarus Team* 0 1 1 +1
  Australian Motoring Enthusiast Party 0 1 1 +1
  One Nation 1 0 1 -3
  Derryn Hinch's Justice Party 1 0 1 Nil

* These three parties were all part of the Palmer United Party at the 2013/2014 election, but split up mid term.

Surprisingly, these projected results still have 20 out of 76 seats held by third party candidates, despite the half election putting them at a disadvantage. The number of third party groups the Liberal/Nationals have to negotiate with to pass legislation (assuming Labor and Greens attempt to block) equally remains unchanged.

The Greens manage to do slightly worse, even though their usual position of winning the 5th or 6th seat in most states often allows them to obtain more representation than their primary vote would otherwise support. This can't even be attributed to a bad 2013 result, as their primary vote both then and in 2016 was nearly identical.

One Nation's much reduced number of seats can be attributed to the inherent geographic bias that any system involving electing candidates across many independent divisions has. If like-minded voters are all in one place, they receive representation, but when the same number of voters are spread out, they get nothing. When this effect is intentionally exploited it's called gerrymandering, but here it's merely an artifact of electing Senators from each state separately. One Nation's support is strongest in Queensland but is relatively diffuse. Any claims of Pauline Hanson being one of the most powerful politicians in Australia are thus overblown.

The Xenophon Group, by contrast, has the vast majority of their support concentrated in South Australia. So the result for them remains unchanged.

The most noteworthy outcomes for the question though, are that the Liberal/Nationals would have obtained more seats, and Labor would have been in a more difficult position to block the passage of legislation. Meaning that yes, the Liberal/National government would definitely have been better off with a normal election.

Nice job screwing over your own party, Malcolm.