Switch branches/tags
Nothing to show
Find file History
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


    Copyright 2015-2016 Silicon Econometrics Pty. Ltd.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

 Libraries needed
 gson (https://github.com/google/gson), and the scala xml library (in the Scala distribution)
 Also jsoup.


This is a program to count the senate votes in the NSW (Australia) state election.
It is designed for research purposes only, being deficient in a
variety of important ways compared to the specification at 
  (1) It may not correctly implement tie resolution for rounding of partially transferred votes,
      in the case of a more than three way tie. [ The specification and indeed legislation is ambiguous ]
      (this can rarely affect the choice of one vote during a partial redistribution)
      This is step 18/19 from the specification.
  (2) Not seriously tested. It produces similar results to the official tally 
      (taking randomness into account), but has not been serious tested.
      There are some differences with the official tallies. The biggest one
      (Griffith LGE 2012) turned out to be an error in the official count,
      acknowledged by the NSW election commission. [ See tech report in the
      github repository. ]
  (3) Not producing the required documentation (e.g. recording each PRN)
  (4) Is not reproducible with a given random seed, as, when a random selection is
      made of a set, the elements are not first sorted into a canonical order.
  (5) It often does things that are mathematically equivalent to the specification,
      but different for performance reasons. For instance, if choosing 900,000 out of 
      1,000,000 votes randomly, it will randomly pick the 100,000 to leave out rather than the
      larger number to leave in.
  (6) Random draws are done automatically; you can't physically draw them out of a hat.
  (7) Sections and of the specification are contradictory. I have tried
      to implement as it seems more defensible given my reading of the legislation.
      [ and has since been confirmed by the NSW election commission. ] But the 
      legislation appears ambiguous to me so I have no idea if I am following it.
  (8) Things I have forgotten or neglected.
Summary: This is provided in the hope it is useful but no guarantees of anything.

It can run multiple times in a multithreaded manner to investigate the effect of randomness,
taking 5s per run.

Federal Australia
It has been modified to run the (much simpler, deterministic other than tie resolution) counting
algorithm used by the AEC and load 2013 data. It also produces some margin information - some number
of votes that could be changed to alter the election outcome - useful for determining tamper

To run 2013: Put downloaded data files in Election/Federal/2013, and run FederalSenateCount2013App in FederalSenateCount.scala.
It will produce files in Federal2013Reports. Start with About.html

To run 2013: Put downloaded data files in Election/Federal/2016, and run FederalSenateCount2016App in FederalSenateCount.scala.
It will produce files in Federal2016Reports. Start with About.html

This seems to produce exactly the same results as the official 2013 results, except for a difference of one paper in the last count in 2013 (which didn't change the number of votes because of rounding). I have no idea what caused this.
It produced exactly the same results as the official 2016 results (if you disable multiple eliminations and continue counting past the point everyone is elected).

As above, there are lots of reasons not to trust it. This is provided in the hope it is useful but no guarantees of anything.

A web front end is available at https://vote.andrewconway.org

It is written in Scala. It was written in version 2.12, but should work with
2.10 & 2.11 and probably future versions. It needs the standard scala libraries, plus
the xml library that comes with the scala distribution but is not generally
added by default to the classpath.

The directory structure includes files that allows it to be used as an sbt project or idea project.

Running NSW State Election 2015

1) Get the state wide preferences data file from

2) Look at the file NSWStateElectionData.scala, the first three lines starting 
      val <something> = new File("<path>")
   The first one should contain the path to the previously downloaded file.
   The second should contain a path where cache files can be created. 
   These are simplified version of the above file.
   These files may be deleted after use if wished.
   The third one should contain a folder where reports should be stored. Note that the program
   will create files in there, first deleting ones that may conflict. *** VITAL: Don't make it somewhere
   containing something you want to save. ******* 

3) Run "RunElection" as a scala application to run a single time. It will make a statistics
   file in the directory specified above.
   The report will look prettier if you copy the file report.css into the parent directory
   of said directory. Start at index.html.
   Much information will also be printed to the console.

4) Run "RunNSWStateElectionProbabilistically" as a scala application to run many times. Set the lines
    val numTotalRuns = 10000
    val numThreads = 4
   To the numbers required.
   After each of the first ten, and then every hundred, it will print out a summary
   of the results, including the margin for the final elimination, and for each
   candidate ever elected, the proportion of times elected and mean position.
Running Local Government Elections 2012
The easiest solution to running a single contest is to use the NSWLocalElectionGUI application (with a GUI).

Reproducing in bulk is harder because it requires downloading everything and putting it in an understandable
directory structure.

General comments on code

The code was written quickly and with an eye on performance. Don't expect a shining example
of software engineering.

DataStructures.scala reads the input formats and merges adjacent tallys.
ElectionReport.scala contains the result of the election and code to print out pretty reports
RunElection.scala contains the actual meat of the election.

For performance reasons, identical votes are gathered together and processed as a group.
This makes the random subset generation slightly more complex, but reduces the number
of votes to be dealt with by a factor of roughly 40, providing a significant speedup and
memory reduction.

Also for performance reasons, votes being counted consist of an array of preferences,
plus an integer offset into the array indicating candidates to be skipped due
to elimination or redistribution.

This means the basic data structure for a vote during the count is the DVote 
(distributable vote) in RunElection.scala, containing an offset and multiplicity
as well as the expected preference list.