Skip to content

Commit

Permalink
Merge branch 'fix/hagenbachOverSeats'
Browse files Browse the repository at this point in the history
  • Loading branch information
edugzlez committed Sep 14, 2024
2 parents b60a721 + 80d1e99 commit ab630a5
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 76 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "electosim"
version = "0.2.0"
version = "0.2.1"
edition = "2021"
authors = ["Eduardo González Vaquero <edugonzalezvaq@gmail.com>"]
description = "Library to compute electoral methods (as D'Hondt) and simulate elections"
Expand Down
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Add this to your `Cargo.toml`:

```toml
[dependencies]
electosim = "0.2.0"
electosim = "0.2.1"
```

or add it directly from crates.io:
Expand All @@ -24,14 +24,14 @@ cargo add electosim
### Using macro `election!`

```rust
use electosim::{ methods::Method, models::Candidacy, electosim::election };
use electosim::*;

fn main() {
let candidacies = vec![
Candidacy::new(2010, 9),
Candidacy::new(1018, 4),
Candidacy::new(86, 0),
Candidacy::new(77, 0),
candidacy!(2010, 9),
candidacy!(1018, 4),
candidacy!(86, 0),
candidacy!(77, 0),
];

let seats = 13;
Expand All @@ -48,15 +48,15 @@ fn main() {
### Directly with the compute_ method

```rust
use electosim::*;
use electosim::methods::divisor::compute_dhondt;
use electosim::models::Candidacy;

fn main() {
let mut candidacies = vec![
Candidacy::new(2010, 0),
Candidacy::new(1018, 0),
Candidacy::new(86, 0),
Candidacy::new(77, 0),
candidacy!(2010, 0),
candidacy!(1018, 0),
candidacy!(86, 0),
candidacy!(77, 0),
];
compute_dhondt(&mut candidacies, 13).unwrap();
candidacies.iter().for_each(|c| println!("{:?}", c));
Expand Down
88 changes: 26 additions & 62 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,19 @@
//! ## Usage
//!
//! ```rust
//! use electosim::methods::Method;
//! use electosim::models::Candidacy;
//! use electosim::election;
//! use electosim::*;
//!
//! fn main() {
//! let mut election = election!(
//! vec![
//! Candidacy::new(2010, 9),
//! Candidacy::new(1018, 4),
//! Candidacy::new(86, 0),
//! Candidacy::new(77, 0),
//! candidacy!(2010, 9),
//! candidacy!(1018, 4),
//! candidacy!(86, 0),
//! candidacy!(77, 0),
//! ],
//! 13,
//! Method::HAGENBASCHBISCHOFF
//! Method::HAGENBASCHBISCHOFF,
//! 0.1
//! );
//!
//! election.compute().expect("Can not compute method");
Expand All @@ -44,15 +43,15 @@
//! A method is a function with type `fn(&mut Vec<T>, u16) -> Result<(), &str>` where `T` is a type that implements the [`WithVotes`][interface::WithVotes] and [`WithSeats`][interface::WithSeats] traits.
//! You can use the `compute_` functions directly if you want to compute the election results without using the [SimpleElection] struct. For example:
//! ```rust
//! use electosim::*;
//! use electosim::methods::divisor::compute_dhondt;
//! use electosim::models::Candidacy;
//!
//! fn main() {
//! let mut candidacies = vec![
//! Candidacy::new(2010, 0),
//! Candidacy::new(1018, 0),
//! Candidacy::new(86, 0),
//! Candidacy::new(77, 0),
//! candidacy!(2010, 0),
//! candidacy!(1018, 0),
//! candidacy!(86, 0),
//! candidacy!(77, 0),
//! ];
//!
//! compute_dhondt(&mut candidacies, 13).unwrap();
Expand All @@ -64,14 +63,16 @@
//! There are some implementations of the `compute_` functions in the [methods::divisor] (ex: D'hondt) and [methods::remainder] (ex: Hare) modules.
pub mod interface;
pub mod macros;
pub mod methods;
pub mod models;
pub mod utils;

use interface::WithVotes;
use methods::{get_method_function, Method};
use models::Candidacy;
use utils::clear_results;
use methods::get_method_function;
pub use methods::Method;
pub use models::Candidacy;
use utils::clear_results; // Add this line to import the SimpleElection struct

/// Represents a simple election.
pub struct SimpleElection {
Expand Down Expand Up @@ -129,57 +130,20 @@ impl SimpleElection {
}
}

#[macro_export]
macro_rules! election {
($results:expr) => {
SimpleElection {
results: $results,
seats: 0,
method: Method::DHONDT,
cutoff: 0.0,
}
};
($results:expr, $seats:expr) => {
SimpleElection {
results: $results,
seats: $seats,
method: Method::DHONDT,
cutoff: 0.0,
}
};
($results:expr, $seats:expr, $method:expr) => {
SimpleElection {
results: $results,
seats: $seats,
method: $method,
cutoff: 0.0,
}
};
($results:expr, $seats:expr, $method:expr, $cutoff:expr) => {
SimpleElection {
results: $results,
seats: $seats,
method: $method,
cutoff: $cutoff,
}
};
}

#[cfg(test)]
mod tests {
use interface::WithSeats;

use super::*;
use crate::models::Candidacy;

#[test]
fn test_simple_election() {
let mut election = election!(
vec![
Candidacy::new(2010, 9),
Candidacy::new(1018, 4),
Candidacy::new(86, 0),
Candidacy::new(77, 0),
candidacy!(2010, 9),
candidacy!(1018, 4),
candidacy!(86),
candidacy!(77),
],
13,
Method::DHONDT
Expand All @@ -193,10 +157,10 @@ mod tests {
fn test_load_new_election() {
let _ = SimpleElection::new(
vec![
Candidacy::new(2010, 9),
Candidacy::new(1018, 4),
Candidacy::new(86, 0),
Candidacy::new(77, 0),
candidacy!(2010),
candidacy!(1018),
candidacy!(86),
candidacy!(77),
],
13,
Method::DHONDT,
Expand All @@ -206,7 +170,7 @@ mod tests {
#[test]
fn test_with_cutoff() {
let mut res = election!(
vec![Candidacy::new(10, 0), Candidacy::new(1, 0),],
vec![candidacy!(10, 0), candidacy!(1, 0),],
13,
Method::DHONDT,
0.1
Expand Down
45 changes: 45 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#[macro_export]
macro_rules! election {
($results:expr) => {
electosim::SimpleElection {
results: $results,
seats: 0,
method: electosim::Method::DHONDT,
cutoff: 0.0,
}
};
($results:expr, $seats:expr) => {
electosim::SimpleElection {
results: $results,
seats: $seats,
method: electosim::Method::DHONDT,
cutoff: 0.0,
}
};
($results:expr, $seats:expr, $method:expr) => {
SimpleElection {
results: $results,
seats: $seats,
method: $method,
cutoff: 0.0,
}
};
($results:expr, $seats:expr, $method:expr, $coff:expr) => {
SimpleElection {
results: $results,
seats: $seats,
method: $method,
cutoff: $coff,
}
};
}

#[macro_export]
macro_rules! candidacy {
($votes:expr) => {
Candidacy::new($votes, 0)
};
($votes:expr, $seats:expr) => {
Candidacy::new($votes, $seats)
};
}
14 changes: 14 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use electosim::*;

fn main() {
let candidacies = vec![candidacy!(600, 9), candidacy!(31, 4), candidacy!(32, 0)];

let seats = 1000;
let method = Method::HAGENBASCHBISCHOFF;
let cutoff = 0.1;

let mut ele = election!(candidacies, seats, method, cutoff);

ele.compute().expect("Can not compute method");
ele.results.iter().for_each(|c| println!("{:?}", c));
}
26 changes: 25 additions & 1 deletion src/methods/remainder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
utils::{clear_results, compute_total_votes},
};

use std::cmp::min;
struct RemainderResult {
pub integer: u16,
pub remainder: f32,
Expand Down Expand Up @@ -64,7 +65,7 @@ where

remainders.iter().enumerate().for_each(|(idx, r)| {
results[idx].set_seats(r.integer);
seats_left -= r.integer;
seats_left -= min(r.integer, seats_left);
});

for _ in 0..seats_left {
Expand Down Expand Up @@ -124,3 +125,26 @@ where
(total_votes as f32 / (seats + 2) as f32).floor() + 1.0
})
}

#[cfg(test)]
pub mod tests {
use crate::*;

#[test]
fn test_bug_hagenbach_seats() {
let candidacies = vec![
Candidacy::new(600, 9),
Candidacy::new(31, 4),
Candidacy::new(32, 0),
];

let seats = 1000;
let method = Method::HAGENBASCHBISCHOFF;
let cutoff = 0.1;

let mut ele = election![candidacies, seats, method, cutoff];

ele.compute().expect("Can not compute method");
ele.results.iter().for_each(|c| println!("{:?}", c));
}
}

0 comments on commit ab630a5

Please sign in to comment.