Skip to main content

Election simulation and analysis

Project description

Election Simulator 3000

Actions Status codecov

This is a library of functions for simulating thousands of elections held using different voting methods (Borda count, Approval voting, etc.) under different voter models (impartial culture, spatial model, etc.) and estimating various metrics from them (Social Utility Efficiency = Voter Satisfaction Efficiency = VSE, Condorcet Efficiency, likelihood of Condorcet cycles, etc.)

For example, it can be used to reproduce Figure 1 from Merrill 1984:

Graph of Condorcet Efficiencies for a Random Society for Plurality, Runoff, Hare, Approval, Borda, Coomsb, Black compared to Merrill's results

Or the table of Effectiveness from Weber 1977:

Standard Vote-for-half Borda
2 81.37 81.71 81.41
3 75.10 75.00 86.53
4 69.90 79.92 89.47
5 65.02 79.09 91.34
6 61.08 81.20 92.61
10 50.78 82.94 95.35
255 12.78 86.37 99.80

See /examples folder for more on what it can do, such as reproductions of previous research.

Goals

  • Fast (~25,000 elections per second on Core i7-9750H)
  • Flexible
  • Well-documented, easily-used and improved upon by other people
  • Well-tested and bug-free
  • Able to reproduce peer-reviewed research

Requirements

See pyproject.toml. As of this README, it includes numpy and scipy for the simulations, tabulate for printing example tables, joblib for parallelizing extreme examples, and pytest, hypothesis, and pytest-cov for running the tests. All should be installable through conda.

Optionally, elsim can use numba for speed. If not available, the code will still run, just more slowly.

Installation

One possibility is to install with pip:

pip install git+https://github.com/endolith/elsim.git

Documentation

Currently just the docstrings of the submodules and functions themselves, in numpydoc format. Now being rendered at https://endolith.github.io/elsim/

Usage

Specify an election with three candidates (0, 1, 2), where two voters rank candidates 0 > 2 > 1, two voters rank candidates 1 > 2 > 0, and one ranks candidates 2 > 0 > 1:

>>> election = [[0, 2, 1],
...             [0, 2, 1],
...             [1, 2, 0],
...             [1, 2, 0],
...             [2, 0, 1]]

Calculate the winner using Black's method:

>>> from elsim.methods import black
>>> black(election)
2

Candidate 2 is the Condorcet winner, and wins under Black's method.

Submodules and chained functions

Originally, the functions in submodules were meant to be chained together in a simple flow:

  1. A function from elsim.elections takes parameters as input (number of candidates, number of voters, dispersion in spatial model, etc.) and produces an array of utilities (each voter's appraisal of each candidate).
  2. Then a function from elsim.strategies converts each voter's utilities into a ballot.
  3. Then a function from elsim.methods counts the collection of ballots and chooses a winner.
flowchart LR
    Parameters -- Election --> Utilities
    Utilities -- Strategy --> Ballots
    Ballots -- Method --> Winner

However, while implementing many different types of simulations, it has become more complicated. Some functions produce intermediate results, while others skip over multiple steps. I'm no longer sure the best way to organize these functions into submodules. Here is a diagram showing the flow of every function currently in the submodules:

%%{ init: { 'flowchart': { 'curve': 'monotoneX' } } }%%
flowchart LR
    %% elections.py
    Parameters -- <code>normal_electorate</code> --> Positions[Spatial positions]
    Positions -- <code>normed_dist_utilities</code> --> Utilities
    Parameters -- <code>random_utilities</code> --> Utilities
    Parameters -- <code>impartial_culture</code> --> ranked_ballots

    %% strategies.py
    Utilities -- <code>approval_optimal</code> --> approval_ballots
    Utilities -- <code>vote_for_k</code> --> approval_ballots
    Utilities -- <code>honest_normed_scores</code> --> score_ballots
    Utilities -- <code>honest_rankings</code> --> ranked_ballots

    subgraph Ballots
        approval_ballots[Approval ballots]
        score_ballots[Score ballots]
        ranked_ballots[Ranked ballots]
    end

    %% approval.py
    approval_ballots -- <code>approval</code> --> Winner
    score_ballots -- <code>combined_approval</code> --> Winner

    %% condorcet.py (moved out of order so it renders with fewer line collisions)
    ranked_ballots -- <code>ranked_election_to_matrix</code> --> Matrix
    Matrix -- <code>condorcet_from_matrix</code> --> Winner
    ranked_ballots -- <code>condorcet</code> --> Winner

    %% black.py
    ranked_ballots -- <code>black</code> --> Winner

    %% borda.py
    ranked_ballots -- <code>borda</code> --> Winner

    %% coombs.py
    ranked_ballots -- <code>coombs</code> --> Winner

    %% fptp.py
    ranked_ballots -- <code>fptp</code> --> Winner
    ranked_ballots -- <code>sntv</code> --> Winner

    %% irv.py
    ranked_ballots -- <code>irv</code> --> Winner

    %% runoff.py
    ranked_ballots -- <code>runoff</code> --> Winner

    %% score.py
    score_ballots -- <code>score</code> --> Winner

    %% star.py
    score_ballots -- <code>star</code> --> Winner
    score_ballots -- <code>matrix_from_scores</code> --> Matrix

    %% utility_winner.py
    Utilities -- <code>utility_winner</code> --> Winner

Tests

Tests can be run by installing the testing dependencies and then running pytest in the project folder.

Bugs / Requests

File issues on the GitHub issue tracker.

Similar projects

Election simulators

Voting system implementations

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

elsim-0.1.0.tar.gz (1.7 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

elsim-0.1.0-py3-none-any.whl (32.5 kB view details)

Uploaded Python 3

File details

Details for the file elsim-0.1.0.tar.gz.

File metadata

  • Download URL: elsim-0.1.0.tar.gz
  • Upload date:
  • Size: 1.7 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for elsim-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3e13e9ae185dabc7ad43a928d3cfe6ebd7255f394459e05b13cd2b7b8f12fd5f
MD5 0463d00743122f74f3c05bb1f65ca1b9
BLAKE2b-256 9d88609ec0d8d3b862ee46847f60589c26cd9023f4aab127fbae2ed2504e8678

See more details on using hashes here.

Provenance

The following attestation bundles were made for elsim-0.1.0.tar.gz:

Publisher: publish.yml on endolith/elsim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file elsim-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: elsim-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 32.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for elsim-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5321970ab817db24b1825a6b3a35cf7763ee72844dbd858285ed03f903cd5f0a
MD5 6c0563bc64544d02cb6ab748e0fc06c2
BLAKE2b-256 cbfe5507c83f64e219c50aa9074d2952fab1622b3b84015190e7be6599c03582

See more details on using hashes here.

Provenance

The following attestation bundles were made for elsim-0.1.0-py3-none-any.whl:

Publisher: publish.yml on endolith/elsim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page