-
Notifications
You must be signed in to change notification settings - Fork 16
Elections and recounts
(This page is current as of August 2016)
- Users can announce their candidacy up to a certain date/time
- At another date/time, elections begin
- At the final date/time, elections end
- Someone (an admin or a cron job) invokes
manage.py processelections
:-
core.models.Elections.process
is invoked - An instance of
core.elections.BallotCounter
counts the votes - 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 bysettings.BALLOT_SAVEFILE_FORMAT
. - The original ballot data will be deleted from the database
- A set of
core.elections.ElectionResultRow
objects will be created, representing the results
-
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 test_data/condorcet_cycle.json
...
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).
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!