Table of contents
Introduction
This program written in Haskell computes the resulting parliament based on several electoral systems for constituencies and voters supplied by the user.
The program was inspired by ALEX3: a Simulation Program to Compare Electoral Systems.
Expected input format
To compute the resulting parliament, the program requires at least three parameters: information about constituencies (districts), information about voters and their preferences and the number of parties.
Information about districts and voters should be supplied as CSV files. See the example:
districs.csv
districtID,nseats
1,4
2,2
voters.csv
size,district,preferences
4,0,1:0:2
2,0,0:1:2
2,1,2:0:1
Here we have two districts, 1 and 2, with 4 and 2 seats in the parliament respectively. We also have 8 voters, divided into three groups (column size says how many voters with these characteristics there are). Voters are divided into groups, as they naturally can be in real circumstances, since it can significantly decrease the size of the file.
Additional file is required for Single Transferable Vote:
candidates.csv
candidateID,party
0,0
1,2
2,1
Single Transferable Vote asks voters to rank candidates, not parties, but each candidate belongs to one. So it is required to know the relationship between candidates and their parties. If we look at the voters.csv and candidates.csv, they say that voters from the first group prefer the most candidate number 1 from the party number 2.
To compute the index of governability it is necessary to know coalitions, which should be provided in the following format:
coalitions.csv
party,coalition
0,1
1,0
2,1
In this example parties number 0 and 2 belong to one coalition.
Example of usage
The program is supplied with one (somewhat [1]) real-world example: the United Kingdom general election in 2015.
The sciprt main.py generates voters.csv [2] and constituencies.csv. To see the result of election if one-district proportionality is used (instead of current 'First-past-the-post' system, in our case called 'Plurality'), the program should be started from the command line:
.virtual-arrow result --system one-district -d example/constituencies.csv -v example/voters.csv -p 5
Here we provide the name of the system (one-district), path to CSV with districts (example/constituencies.csv), path to CSV with voters (example/voters.csv) and the number of parties (5).
The program produces the following output:
party,number_of_seats
0,170
1,76
2,220
3,44
4,23
Which gives the structure of the elected parliament (the Labour Party has 170 seats, the United Kingdom Independent Party has 76 seats, and so on).
This output (if saved as one-district.csv) can be further used as an input for calculating the index of representativeness according to Gallagher:
./virtual-arrow gallagher -r one-district.csv -d example/constituencies.csv -v example/voters.csv -p 5
And the output is
0.0
as expected for absolutely proportional electorate system. Then if we try plurality:
$ ./virtual-arrow result --system plurality -d example/constituencies.csv -v example/voters.csv -p 5 >> plurality.csv
$ ./virtual-arrow gallagher -r plurality.csv -d example/constituencies.csv -v example/voters.csv -p 5
> 18.117455830983083
and borda-count:
$ ./virtual-arrow gallagher -r borda.csv -d example/constituencies.csv -v example/voters.csv -p 5
> 14.771806468611409
We see that representativeness increases in case of the Borda count, the result that can be further improved in case of run-off plurality:
$ ./virtual-arrow gallagher -r run-off.csv -d example/constituencies.csv -v example/voters.csv -p 5
> 11.541130581035421
Increase in the representativeness can lead to more fragmented parliament. Under plurality the Conservative party has a clear majority, and under run-off plurality it has to govern in coalition with the Liberal Democrat Party [3]. Hence, the governability index decreases:
$ ./virtual-arrow governability -r plurality.csv -c coalitions.csv
> 0.6097560975609756
$ ./virtual-arrow governability -r run-off.csv -c coalitions.csv
> 0.3430268918073796
To see the complete description of available commands and their arguments, run:
$ ./virtual-arrow --help
$ ./virtual-arrow result
Information on electoral systems
The Borda Count
Each voter ranks all parties from 0 to n − 1, where n is the number of parties. For each vote cast a party gets a number of points: 0 if it is on the first place in the ballot, 1 if on the second and so on till n − 1 points. For each district a winner is determined as a party with the least number of points. All seats are assigned to the winner.
One-district proportionality
Districts are aggregated into one and seats are assigned proportionally.
Plurality
Voters choose one party, the party with the most votes wins in each district.
Run-off plurality
The same as Plurality, but if no party gains at least 50 % of the votes, the second round is arranged with the two parties with the most votes. The one with the most votes in the second round wins.
Multi-district proportionality
In each district seats are allocated using Sainte-Laguë method: successive quotients are calculated for each party, whichever party has the highest quotient gets the next seat allocated. The process is repeated until all seats have been allocated.
Mixed-member 1
One parliament is elected with the Plurality, and one using Multi-district proportionality. The resulting parliament is a weighted mean of the two. The weight of the first parliament relative to the second one is specified by the user.
Mixed-member 2
Part of parliament is elected with the Plurality, and the remainder is elected using the Multi-district proportionality. Share of seats to be elected with the Plurality System is specified by the user.
Threshold proportionality
The same as One-district proportionality, but parties have to gain the specified percentage of votes. Parties that do not meet this criteria are discarded and the seats are distributed proportionally between the remaining parties.
Single Transferable Vote
The seats for each candidate, in each district, are assigned according to a quota (Droop quota). A candidate that reaches the quota is declared elected. If a candidate has more votes than the quota, surplus votes are transferred to the candidates chosen as the next preference. If no-one new meets the quota, the candidate with fewest votes is eliminated and those votes are transferred. This process repeats until either a winner is found for every seat or there are as many seats as remaining candidates.
Single Transferable Vote is used with the list of candidates, thus the additional parameter (each candidate's party membership) is required to determine the number of seats for each party.
| [1] | In the UK example only constituencies located in England are taken into account as I do not have enough data to predict the second and further orders of preferences for voters in Scotland, Wales and Northern Ireland. Thus regional parties, such as Scottish National Party, Democratic Unionist Party, Sinn Fein and so on, are not considered. |
| [2] | As can be seen from main.py, parties are given the following identifiers: |
'Labour': 0,
'UKIP': 1,
'Conservative': 2,
'Liberal Democrat': 3,
'Green Party': 4
| [3] | Assumption is made (based on public announcements) that the Conservative party is in a coalition with the Liberal Democrat Party and the Labour party is in a coalition with the Green Party. |