The ElectionAudits software project is designed to help audit elections with good statistical confidence. It is provided in support of the Principles and Best Practices for Post-Election Audits http://electionaudits.org/principles Features: ========= It helps with several facets of the task of auditing elections: * Imports standard election report files into a simple SQL database * Protects voter anonymity by combining results for very small precincts or batches into larger audit units. * Enables audits of central-count systems and mail-in ballots without requiring that the paper ballots be sorted into piles by precinct. Works with election systems which can't produce batch results, by importing full election results for each batch and subtracting the result for the previous batch from the current batch. * Facilitates risk-limiting audits by calculating relevant statistics based on the margin, number, size, and results of the audit units. Support for PPEBWR, SAFE, and NEGEXP is provided, with more on the drawing board. * Supports augmenting dice throws with the "Sum of Square Roots" (SSR) Pseudorandom Sampling Method to select which audit units to audit and/or which contests to audit, based on margin size. * Ad-hoc calculator form lets you quickly enter information about hypothetical contests and get selection statistics for them also. This supports planning for future audits, e.g. deciding how many batches to report on so as to minimize the fraction of the ballots you'll have to audit. * Provides information to help candidates, parties, or other observers target unusual audit units for elective audit. * Convenient platform for publication and archiving of auditable reports for the public. The software is "Open source" via the very permissive MIT license. It can be used with no obligation, by anyone from elections officials, to citizens to Election Management System vendors. For up-to-date information, see the project home page at http://neal.mcburnett.org/electionaudits/ Authors ======= Neal McBurnett Includes a variant of varsize.py from Ronald L. Rivest Copyright and License ("MIT" aka "X11" license) ===================== Copyright 2008 Neal McBurnett http://neal.mcburnett.org/ varsize.py: Copyright Ronald L. Rivest Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Support and Participation ========================= Join the https://launchpad.net/~electionaudits team and get support via that mailing list. Or for real-time chat support try #electionaudits on irc.freenode.net Versions, Bug reports ===================== See launchpad.net for project support at https://launchpad.net/electionaudits to download the latest version or report bugs. It uses the bzr ("Bazaar") distributed version control software, making it easy for you to contribute. Requirements ============ ElectionAudits has been tested on Ubuntu Linux and Windows, and should run fine on Mac OS X and others. It requires these other components: * Python (developed with python version 2.5, but should work with 2.3) * lxml (xml parsing package) * Django 1.0 * sqlite3 lightweight database Helpful but optional Django apps used in settings.DEBUG mode: * lukeplant_me_uk.django.validator, for automatic xhtml validation * django_extensions, for ease in development and documentation * debug-toolbar, http://github.com/robhudson/django-debug-toolbar/tree/master If you want to run in DEBUG mode and don't have these, just comment them out of root/settings_debug.py and electionaudits/urls.py Installation ============ Ubuntu Linux ------------ On Linux, installation is easy. On the Intrepid release, 8.10, you can get all the prerequisites this way: $ sudo apt-get install python-lxml libsqlite3-0 python-django or install the same packages via the Synaptic Package Manager GUI. For earlier Ubuntu releases, you'll need to get Django 1.0 from http://www.djangoproject.com/download/ Windows XP, and maybe Vista --------------------------- First install a release of python 2.5 (e.g. 2.5.2, though 2.6 might work): http://www.python.org/download/ Next install the official version of Django 1.0 using the simple steps described at http://www.djangoproject.com/download/ On Windows you can use a tool like 7-zip (http://www.7-zip.org/) to unpack the .tar.gz file, or bsdtar (http://gnuwin32.sourceforge.net/packages/bsdtar.htm) for more straightforward command-line use. Then install lxml via setuptools: Get and run this setuptools installer: http://pypi.python.org/packages/2.5/s/setuptools/setuptools-0.6c9.win32-py2.5.exe You can then just run this: C:> easy-install lxml Or use the MS Windows Installer for lxml that matches your version of python at http://pypi.python.org/pypi/lxml/2.1.2, e.g. http://pypi.python.org/packages/2.5/l/lxml/lxml-2.1.2.win32-py2.5.exe Finally, get the sqlite3 library DLL from http://www.sqlite.org/download.html e.g. http://www.sqlite.org/sqlitedll-3_6_4.zip Unzip it and put the .dll file with your other DLLs in your default System directory, e.g. C:\WINDOWS\system32 Mac OS X -------- This should be pretty easy if you search a bit, but we don't have specific instructions. Let us know if you want help, or if you can share advice. Initialization ============== Security note: you should change the SECRET_KEY in the settings.py file to a long random string, especially if you ever change the default URL or deploy the site on a publicly accessible server. Otherwise, authentication will be less secure. When you first install or upgrade the software, you need to initialize the database: $ cd root $ ./manage.py syncdb In Windows leave off the "./": C:> cd root C:> manage.py syncdb When it asks: "You just installed Django's auth system, which means you don't have any superusers defined. Would you like to create one now? (yes/no)" answer "yes" and provide a username and password for the "admin" system. Logging in with this account, or another "staff" account, is necessary for parsing new data files from within the web interface. It asks for a valid email address also, but doesn't share it or use it unless you customize things. Usage ===== parse ===== You can import and parse new files in two ways: via the http://127.0.0.1:8000/parse/ page (see below) or from the command line. From the command line, use the manage.py parse command to import election results data into easily manipulated databases. Use the --help option to print usage instructions: $ ./manage.py parse --help In Windows leave off the "./": C:> manage.py parse --help Test data is provided, so you can just run $ ./manage.py parse -s -c ../testdata/t0 which parses all the files in that directory in chronological order. It may take a while to run. A brief synopsis of each contest is printed at the end. In Windows: C:> manage.py parse or C:> manage.py parse -s -c ..\testdata\t0 Use "manage.py reset electionaudits" to clear the database before trying to re-enter data. Currently supported input formats: * Hart InterCivic Tally "cumulative" reports in xml (crystal-reports) format (including all options: Absentee, Early and Election day, and the info box) One file per cumulative batch of input. Use the "-s" option to "manage.py parse" to subtract each cumulative report from the previous one. Examples: testdata/t0/*.xml * CSV input with one line per candidate using these headers: 'Precinct_name' 'Contest_title' 'Party_Code' 'candidate_name' 'cand_seq_nbr' 'absentee_votes' 'early_votes', 'election_votes' and these columns, only used for 1st candidate (when 'cand_seq_nbr' is 1) 'absentee_under_votes' 'absentee_over_votes' 'early_under_votes', 'early_over_votes', 'election_under_votes' 'election_over_votes' Examples: testdata/test-san-mateo-dp-92-p.csv Planned * Hart "precinct" reports Web server ========== This provides a web-based graphical user interface for exploration, reporting and even entry of information. It is built on the Django framework. Usage: First run the internal django server: $ cd root $ ./manage.py runserver This will remain running until you kill it with ctrl-c or close the window. It will show each web page you visit. Then, in a browser, visit the main URL, e.g. http://127.0.0.1:8000/ to see the Audit Reports for the various Contests, etc. The "Parse incoming data files" page provides an alternative to the command line for importing xml data files. It automatically selects the --subtract and --chronological options. Just put the files in the "incoming" directory, visit that page to see a list of the files, and click the button. Beware that there is currently no feedback during the import, so just be patient. See http://127.0.0.1:8000/admin/ (using the username and password you entered during the "syncdb" step) to enter new data, and http://127.0.0.1:8000/admin/doc/ for more documentation on the data models and various available views of the information. For example, you will usually want to edit the countyelection to specifiy the confidence level for each contest, and the overall margin of victory if there are ballots that are outside the county. Visit: http://127.0.0.1:8000/admin/electionaudits/countyelection/ See doc/model_graph.png for a diagram of the various database tables and associated fields and relationships. PROCEDURE ========= Here, in brief, are the steps for using this in an election, along with some "TODO" notes for likely future enhancements to ElectionAudits. * Parse the elections data * To get accurate statistics, set the number of ballots for each batch, either by taking it from contest_batch.contest_ballots() for some contest that is on every ballot, or by getting it from some other source, e.g. by parsing the pdf files. This currently needs to be done via the python interface, or one-at-a-time from the admin interface. [TODO: make this easier] * Publish the results (http://127.0.0.1:8000/reports/) publicly. * Roll dice and enter the random seed for the appropriate election via http://127.0.0.1:8000/admin/electionaudits/countyelection/ * Sort the http://127.0.0.1:8000/selections/ table by priority and select the appropriate number of contests of each type via http://127.0.0.1:8000/admin/electionaudits/contest/ [TODO: sort it automatically, rather than requiring browser plug-ins or manual steps] * Select additional targeted audit units manually via http://127.0.0.1:8000/admin/electionaudits/contestbatch/ * Publish the selected contests via http://127.0.0.1:8000/results/ * [TODO] Print tally sheets for each audit unit * Hand count the selected audit units * [TODO] Enter the results via a new form * [TODO] Provisional ballots: Parse new batches, publish the /reports/ and select more audit units: either old ones based on the new margins with the old random seed, and ones from the new audit units using a new random seed. Debugging ========= You can run the test cases via this command: manage.py test electionaudits or a single class of them via, e.g. manage.py test electionaudits.TestT0 If you install the django html validator app lukeplant_me_uk.django.validator and use debug settings manage.py runserver --settings settings_debug the server will do self-validation of all xhtml pages generated. You can then see a report of any errors at http://127.0.0.1:8000/validator/ Acknowledgements: ================= Thanks to these contributors: The auditing experts led by Mark Halvorson and John McCarthy at Verified Voting. Others who made significant contributions: Crystal Christman, Mark Lindeman, Hillary Hall, Aaron D. Gerber, Mary Eberle, Holly Lewis. FAQ - Frequently Asked Questions ================================ Q: Parsing failed with " ValueError: Negative vote count in test" - why? A: When parsing xml files with the --subtract option, you need to make sure they are processed in sequential order, or else the subtraction will result in negative vote counts. If you can preserve the modification timestamps on the files, you should be able to use the "--chronological" option to process them in order. But note that various ways of copying will change the timestamps - e.g. via cp without the "-p" option, or via bzr, or via some versions of Nautilus. This can also happen if you read the same data in twice. Before re-reading data, you should clear out all vote counts in the database with manage.py reset electionaudits Q: I've forgotten the admin password and can't access staff pages! A: See http://coderseye.com/2007/howto-reset-the-admin-password-in-django.html Q: I forgot to get a zero cumulative xml report before reading in ballots. What do I do now? A: You can specify the same report as the first two cumulative reports, and it will subtract one from the other, and not add any audit units because everything subtracts out to be zero.