Skip to content


Folders and files

Last commit message
Last commit date

Latest commit


Repository files navigation

Voting system simulator

This is a voting system simulator intended to simulate various methods used in proportional voting systems, in particular those that use a biproportional apportionment method for allocation of adjustment seats based on national outcomes. Such systems are common, such as in Iceland, Sweden, and Norway.

M.L. Balinski and G. Demange have shown that only one method, the Alternating-Scaling method, exists that upholds the five axioms for proportionality in matrices. All other methods are heuristic simplifications that approach the optimal solution to varying degrees. This software implements the Alternating-Scaling method, and various other methods for comparison, and provides mechanisms to compare them.

Biproportional allocation on matrices is a common issue that arises when you have multiple parties in multiple constituencies vying for a set number of seats which are pinned to different constituencies. The goal is to determine which parties get which seats in which constituencies.

More generally this approach could be used to allocate limited resources to factories depending on their relative importance or needs, or to solve a number of other biproportional optimization problems.


It is highly recommended that you use a Virtualenv for voting. Python 3 is recommended.

  1. Create a new Python3 Virtualenv, e.g. 'voting', and enter it.
  2. Make sure you have npm available on your system.
  3. Clone this repository (e.g. from
  4. (cd backend && pip install -r requirements.txt)
  5. (cd vue-frontend && npm install)
  6. (cd vue-frontend && npm run-script build)

That should be enough to start using the simulator.

Command Line Interface

The basic interaction mode. You feed it some data files, it feeds you some results.

For help, try:

python --help

A few usage examples follow below.


Basic apportioning is done through the apportion command. For help with that command, do:

python apportion --help

The apportion command takes several flags, including:

  • constituencies: path to a CSV or XLSX file describing constituencies.
  • votes: path to a CSV or XLSX file containing votes.
  • divider: the name of a supported divider method.
  • adjustment-divider: a supported divider method to use for adjustment seats; defaults to the same as the selected divider method.
  • adjustment-method: a supported adjustment method to use for resolving adjustment seat apportionment. Use multiple times to compare outputs.
  • output: the output format to use.
  • show-entropy: show the calculated entropy of each method.

Example using the 2013 elections in Iceland and d'Hondt method:

python apportion \
	--constituencies=../data/constituencies/constituencies_iceland_2013.csv \
	--votes=../data/elections/iceland_landskjorstjorn_2013.csv \
	--divider=dhondt \
	--adjustment-method=alternating-scaling \

You can get HTML, LaTeX, MediaWiki or various other types of table output and swap out the divider methods as you please:

python apportion \
	--constituencies=../data/constituencies/constituencies_iceland_2013.csv \
	--votes=../data/elections/iceland_landskjorstjorn_2013.csv \
	--divider=sainte-lague \
    --adjustment-method=monge \


Simulation is done through the simulate command. For help with that command, do:

python simulate --help

The simulate command takes several flags, including:

  • constituencies: path to a CSV or XLSX file describing constituencies.
  • votes: path to a CSV or XLSX file containing votes to use as reference for the simulation.
  • test_method: the method to be tested.
  • num_sim: number of simulations to run.
  • gen_method: a supported method to generate votes.

Example using the 2013 elections in Iceland:

python simulate \
	--constituencies=../data/constituencies/constituencies_iceland_2013.csv \
	--votes=../data/elections/iceland_landskjorstjorn_2013.csv \

Script mode

Because all the parameters can be confusing and sometimes you just want to be able to work with a particular set of settings again and again, there is a "script mode" (for lack of a better term) which allows you to specify a set of rules which then execute:

python script ../data/presets/iceland2013.json

A script or preset is simply a JSON file that specifies what should happen, see examples in data/presets/.

Web Interface

The web interface can be started by:


Then direct a browser to http://localhost:5000/ and start having fun. This is the recommended mode to use the simulator in.


The web interface involves a Javascript Single Page App (SPA) which acts as a visual editor for data that is then passed to the backend for calculations. As such, the SPA is the source of truth, and the backend is "dumb", merely reacting to the frontend. The backend is made with Flask.

The SPA's data model should be the same as the backend's script-mode input model.

The SPA is built using vue.js.


Basic functionality

  • Read constituency data files
  • Read vote data files
  • Basic click UI
  • Per ruleset click UI options
  • Simulation click UI options
  • Web server

Apportionment methods

  • One dimensional greedy apportionment
    • d'Hondt method
    • Sainte-Lague method
    • Nordic Sainte-Lague method
  • Constituency seat allocation
  • Threshold elimination (on matrices and vectors)
  • Optimization and heuristic methods
    • Linear programming
    • Greedy Alternating-Scaling algorithm (AS)
    • Alternating-Scaling algorithm (AS)
    • Relative Superiority algorithm (RS)
    • Relative Inferiority algorithm (RI)
    • Nearest neighbor algorithm
    • Monge algorithm
    • Icelandic voting law algorithm
    • Swedish voting law algorithm
    • Norwegian voting law algorithm
    • Norwegian voting law algorithm adjusted for Icelandic conditions
    • Kristinn Lund method
    • Pure vote ratios method


  • Generate random initial votes
    • Draw percentages for each party in each district from a beta distribution with historical mean and variance. Then normalize the percentages to add up to 100%.
  • Fuzz votes
    • Add votes, one-by-one, in support of a party list in a district
      • If a new vote doesn't gain that party list a seat, report any change in results.
      • Even if a new vote does gain that party list a seat, do report if the result change is greater than just moving a seat in the relevant constituency between parties and moving one seat in the opposite direction in another constituency.
  • Compare different apportionment methods

Evaluation of methods

  • Apportionment entropy
  • Entropy relative to optimal entropy
  • Seat deviation from optimal solution
  • Seat deviation from Icelandic law
  • Seat deviation from independent constituencies
  • Seat deviation from single constituency country
  • Seat deviation from all seats apportioned with adjustment method
  • Loosemore-Hanby index
  • Sainte-Lague minsum index
  • d'Hondt maxmin index
  • d'Hondt minsum index
  • Monotonicity violation: A party list losing a seat by receiving an additional vote
  • Significant irrelevant alternative: A new vote having side effects without without affecting the number of seats won by the party list voted for.

Output formats

  • Simple text result table (Total seats) output
  • HTML, LaTeX, CSV, result table (Total seats) output
  • Excel file detailed result output
    • Votes
    • Vote shares
    • Constituency seats
    • Adjustment seats
    • Total seats
    • Evaluation metrics

Web interface

  • Simple web server
  • Javascript SPA
    • Configurable running of single elections
    • Configurable running of simulations
    • Display results
      • Votes
      • Vote shares
      • Constituency seats
      • Adjustment seats
      • Total seats
      • Evaluation metrics
    • Visualizations
      • "Election TV" result animations
      • Simulation errors
      • 3D bar chart of cumulative violations in the constituency/party matrix
  • Configurable host/port/etc


See our issue tracker on Github.


  • Smári McCarthy
  • Þorkell Helgason
  • Martha Guðrún Bjarnadóttir
  • Pétur Ólafur Aðalgeirsson
  • Helgi Hrafn Gunnarsson
  • Bjartur Thorlacius.


Released under the terms of the Affero GNU General Public License version 3.