Skip to content

Elections and recounts

Bjarni Rúnar Einarsson edited this page Sep 7, 2016 · 18 revisions

(This page is current as of August 2016)

The Default Election Process

  1. Users can announce their candidacy up to a certain date/time
  2. At another date/time, voting begins and users submit sorted lists of candidates
  3. At the final date/time, voting ends
  4. Someone (an admin or a cron job) invokes manage.py processelections:
    1. core.models.Elections.process is invoked
    2. An instance of core.elections.BallotCounter counts the votes
    3. The same core.elections.BallotCounter writes a copy of raw (but anonymized) ballots to a JSON file in the filesystem, the name/path of which are determined by settings.BALLOT_SAVEFILE_FORMAT.
    4. The original ballot data will be deleted from the database
    5. A set of core.elections.ElectionResultRow objects will be created, representing the results

Manual recounts

The file core/elections.py can be invoked as a stand-alone tool and has no Django dependencies. It can be used to recount ballots from a JSON file using different algorithms, and/or omitting certain candidates.

An example of the common case, recounting after one or more candidates have withdrawn from the election:

$ python core/elections.py \
    -e quitter1 -e quitter2 \
    count schulze /path/to/ballot/data.json
...

Getting real names

The list of usernames can be converted into a more human-readable list of real names, by using the manage.py lookup_usernames command:

$ manage.py lookup_usernames user1, user2, user3
...

(Commas will be ignored, to facilitate copy-pasting directly from the elections.py output into the lookup tool)

Avoiding randomness in recounts

Note that if two users are tied, the libraries used by election.py will perform a virtual coin toss to order those candidates. As a result, recounts may randomly change the order of candidates for no other reason than pure chance. It may be worth recounting multiple times to detect when this happens, and manually preserve the order chosen by the first election in such cases.

Supported counting methods

At the time of writing, elections.py supports the following voting systems: schulze, stcom, condorcet, stv1, ..., stv5, stv10

Most of these are standard counting methods that you can read about on Wikipedia or elsewhere. The exception is the stcom method: it implements the Icelandic pirate party steering committee election system; currently a combination of schulze and plain condorcet (to verify whether the chairperson is unambiguously elected).

More election.py examples

The built-in help is likely to be more current than this document:

$ python core/elections.py --help
usage: elections.py [-h] [-e EXCLUDE] [--keep-gaps]
                    operation system filenames [filenames ...]

positional arguments:
  operation             Operation to perform (count)
  system                Counting system to use (schulze, stv5, ...)
  filenames             Ballot files to read

optional arguments:
  -h, --help            show this help message and exit
  -e EXCLUDE, --exclude EXCLUDE
                        Candidate(s) to exclude when counting
  --keep-gaps           Preserve gaps if ballots are not sequential

We can use the included test-data to verify that Schulze will arbitrarily break Condorcet ties/cycles; if you run this a few times you'll get different results each time.

$ python core/elections.py count schulze test_data/condorcet_cycle.json 
Voting system:
        Schulze, Ordered list (schulze)

Loaded 3 ballots from:
        test_data/condorcet_cycle.json

Schulze old and new match, hooray.
Results:
        Bjarni, Smari, Bjorn

Counting using the condorcet method should however correctly return no results:

$ python core/elections.py count condorcet test_data/condorcet_cycle.json 
Voting system:
        Condorcet (condorcet)

Loaded 3 ballots from:
        test_data/condorcet_cycle.json

Results:

To break the cycle, we can try omitting one candidate:

$ python core/elections.py -e Bjorn count condorcet test_data/condorcet_cycle.json 
Voting system:
        Condorcet (condorcet)

Loaded 3 ballots from:
        test_data/condorcet_cycle.json

Results:
        Bjarni

Hooray!

Miscellania

  • If you're not sure what cron-jobs exist, try this: crontab -l

  • Since during elections, the wasa2il database contains non-anonymized ballots, we recommend using a backup system which prevents admins from easily accessing old data. This prevents after-the-fact attacks on voter privacy. This is what the Icelandic pirates use.

  • The schulze method should tolerate candidates withdrawing from an election right in the middle. It's unclear whether the same can be said about other counting methods supported by wasa2il, further research is needed before implementing a user-friendly "instant withdraw" feature.

Clone this wiki locally