Crates.io | trie_rcv |
lib.rs | trie_rcv |
version | 1.3.1 |
source | src |
created_at | 2024-05-03 16:51:30.407921 |
updated_at | 2024-10-23 13:10:16.900349 |
description | Ranked Choice Voting implementation using Tries in Rust |
homepage | |
repository | https://github.com/milselarch/trie_rcv |
max_upload_size | |
id | 1228977 |
size | 60,707 |
https://crates.io/crates/trie_rcv
Ranked Choice Voting (RCV) implementation using Tries in Rust.
RCV differs from normal first past the post voting in that voters are allowed to rank candidates from most to least preferable. To determine the winner of an RCV election, the votes for the least popular candidate each round is transferred to the next candidate in the respective ranked votes until some candidate achieves an effective majority.
Example usage:
use trie_rcv;
use trie_rcv::RankedChoiceVoteTrie;
use trie_rcv::vote::RankedVote;
fn main() {
let mut rcv = RankedChoiceVoteTrie::new();
// remove all candidates with the lowest number of votes each round
rcv.set_elimination_strategy(EliminationStrategies::EliminateAll);
rcv.insert_vote(RankedVote::from_vector(&vec![1, 2, 3, 4]).unwrap());
rcv.insert_vote(RankedVote::from_vector(&vec![1, 2, 3]).unwrap());
rcv.insert_vote(RankedVote::from_vector(&vec![3]).unwrap());
rcv.insert_vote(RankedVote::from_vector(&vec![3, 2, 4]).unwrap());
rcv.insert_vote(RankedVote::from_vector(&vec![4, 1]).unwrap());
let winner = rcv.determine_winner();
println!("WINNER = {:?}", winner);
assert_eq!(winner, Some(1));
// alternatively:
let votes = RankedVote::from_vectors(&vec![
vec![1, 2, 3, 4],
vec![1, 2, 3],
vec![3],
vec![3, 2, 4],
vec![4, 1]
]).unwrap();
let winner2 = rcv.run_election(votes);
println!("WINNER = {:?}", winner2);
assert_eq!(winner2, Some(1));
}
This implementation also supports ranked votes ending
with SpecialVotes::WITHHOLD
and SpecialVotes::ABSTAIN
values:
SpecialVotes::WITHHOLD
-1
via SpecialVotes::WITHHOLD.to_int()
SpecialVotes::ABSTAIN
-2
via SpecialVotes::ABSTAIN.to_int()
use trie_rcv;
use trie_rcv::RankedChoiceVoteTrie;
use trie_rcv::vote::{RankedVote, SpecialVotes};
fn main() {
let rcv = RankedChoiceVoteTrie::new();
let votes_round1 = RankedVote::from_vectors(&vec![
vec![1, SpecialVotes::WITHHOLD.to_int()],
vec![2, 1],
vec![3, 2],
vec![3]
]).unwrap();
let winner_round1 = rcv.run_election(votes_round1);
println!("WINNER = {:?}", winner);
assert_eq!(
winner_round1, None, concat![
"Candidate 1's vote should not count after round 1, ",
"no one should have majority"
]);
let votes_round2 = RankedVote::from_vectors(&vec![
vec![1, SpecialVotes::ABSTAIN.to_int()],
vec![2, 1],
vec![3, 2],
vec![3]
]).unwrap();
let winner_round2 = rcv.run_election(votes_round2);
println!("WINNER = {:?}", winner_round2);
assert_eq!(
winner_round2, Some(3), concat![
"First vote is ignored in round 2, candidate 3 wins"
]);
}
Technically the RCV algorithm specification doesn't state what to do in the situation that there are multiple candidates who all have the same, lowest number of votes in some round during RCV.
The elimination_strategy
setting handles which candidates to eliminate each round.
Technically the RCV algorithm specification doesn't state what to do in the situation that
there are multiple candidates who all have the same, lowest number of votes in some round during
RCV - EliminationStrategies::EliminateAll
, EliminationStrategies::DowdallScoring
,
and EliminationStrategies::RankedPairs
offer different ways to resolve that edge case.
EliminationStrategies::EliminateAll
EliminationStrategies::DowdallScoring
(default)EliminationStrategies::RankedPairs
EliminationStrategies::EliminateAll
EliminationStrategies::CondorcetRankedPairs
EliminationStrategies::EliminateAll
if the preference graph cannot
be constructed.Build crate using cargo build
, run integration tests with cargo test