Home

Awesome

Single Transferable Vote implementation in Rust

Crate Documentation Safety Dance Minimum Rust 1.75.0 Dependencies Codecov Lines of Code Build Status Test Status Integration tests Status

This program is an implementation of Single Transferable Vote in Rust. The goal is to provide vote-counting transcripts that are reproducible with other vote-counting software, such as Droop.py.

For now, only Meek's counting method is implemented.

You can find more details in the following blog article: STV-rs: Single Transferable Vote implementation in Rust.

Usage

With Cargo:

$ RUST_LOG=$LOG_LEVEL cargo run \
  --release -- \
  --arithmetic $ARITHMETIC \
  --input ballots.txt \
  meek \
  --parallel=<no|rayon|custom>
$ RUST_LOG=$LOG_LEVEL cargo run \
  --release -- \
  --arithmetic $ARITHMETIC \
  --input ballots.txt \
  meek \
  --parallel=<no|rayon|custom> \
  --equalize

Arithmetic implementations

You can control the arithmetic used to count votes via the --arithmetic command-line flag. The following implementations are available.

Equalized counting

In this mode, ballots where candidates are ranked equally are counted as fairly as possible, by simulating a superposition of all possible permutations of equally-ranked candidates.

For example, the ballot a b=c becomes a superposition of a b c (with weight 1/2) and a c b (with weight 1/2). Likewise, the ballot a b=c=d is counted as a superposition of 6 ballots, each with weight 1/6: a b c d, a b d c, a c b d, a c d b, a d b c, a d c b.

Log levels

Besides the election transcript written to the standard output (which aims to be consistent with Droop.py for reproducibility), you can get more details via Rust's logging capabilities, controlled by setting the $RUST_LOG environment variable.

The log levels will provide the following information.

For more advanced logging control, please check the env_logger crate documentation.

Parallelism

To speed up the computation, you can enable parallelism via the --parallel command-line flag.

The vote-counting process involves accumulating votes across all ballots, summing the outcomes of counting each ballot. Without parallelism, this is done by a simple serial loop over the ballots. With parallelism enabled, a parallel loop is used instead, where each ballot is counted independently on any thread, and the sum is computed in any order.

Because the sum is computed in an arbitrary order, it is important to use an arithmetic where addition is commutative and associative, otherwise results won't be reproducible. This excludes float64, as addition is not associative.

Under the hood, the rayon crate is used to automatically schedule and spread the work across available CPU cores (map-reduce architecture).

Other STV implementations

Here is a non-exhaustive list of STV implementations.

Contributing

See CONTRIBUTING.md for details.

License

Apache 2.0; see LICENSE for details.

Disclaimer

This project is not an official Google project. It is not supported by Google and Google specifically disclaims all warranties as to its quality, merchantability, or fitness for a particular purpose.