diff --git a/src/stv/gregory/transfers.rs b/src/stv/gregory/transfers.rs index 6eb5d52..ac1e986 100644 --- a/src/stv/gregory/transfers.rs +++ b/src/stv/gregory/transfers.rs @@ -202,7 +202,8 @@ impl<'e, N: Number> TransferTable<'e, N> { if self.surplus.is_none() || opts.sum_surplus_transfers == SumSurplusTransfersMode::ByValue { for (_candidate, cell) in self.total.cells.iter_mut() { let mut votes_out; - if is_weighted { + if is_weighted || self.surpfrac.is_none() { + // NB: If surplus.is_none, then votes transferred at values received votes_out = cell.votes_in.clone(); } else { votes_out = cell.ballots.clone(); @@ -221,7 +222,7 @@ impl<'e, N: Number> TransferTable<'e, N> { if self.surplus.is_none() || !opts.transferable_only { let mut votes_out; - if is_weighted { + if is_weighted || self.surpfrac.is_none() { votes_out = self.total.exhausted.votes_in.clone(); } else { votes_out = self.total.exhausted.ballots.clone(); diff --git a/tests/data/surplus_values_received.blt b/tests/data/surplus_values_received.blt new file mode 100644 index 0000000..a2c3ea6 --- /dev/null +++ b/tests/data/surplus_values_received.blt @@ -0,0 +1,13 @@ +# Comment: Constructed example - surplus votes need to be transferred at values received +4 3 +12 1 2 0 +3 1 2 3 0 # These votes need to be transferred to C at values received by B +9 2 0 +8 3 0 +7 4 0 +0 +"A" +"B" +"C" +"D" +"Surplus transferred at values received" diff --git a/tests/data/surplus_values_received.csv b/tests/data/surplus_values_received.csv new file mode 100644 index 0000000..f1842c0 --- /dev/null +++ b/tests/data/surplus_values_received.csv @@ -0,0 +1,7 @@ +Stage:,1,,2,,3, +Comment:,First preferences,,Surplus of A,,Surplus of B, +A,15,EL,9.75,EL,9.75,EL +B,9,H,14.25,EL,9.75,EL +C,8,H,8,H,9.05,EL +D,7,H,7,H,7,H +Exhausted,0,,0,,3.45, diff --git a/tests/data/surplus_values_received.ods b/tests/data/surplus_values_received.ods new file mode 100644 index 0000000..266209d Binary files /dev/null and b/tests/data/surplus_values_received.ods differ diff --git a/tests/tests_impl/special_cases.rs b/tests/tests_impl/special_cases.rs index 172f9b2..dadc9a1 100644 --- a/tests/tests_impl/special_cases.rs +++ b/tests/tests_impl/special_cases.rs @@ -15,8 +15,10 @@ * along with this program. If not, see . */ +use crate::utils; + use opentally::election::{CandidateState, CountState, Election}; -use opentally::numbers::Rational; +use opentally::numbers::{Fixed, Rational}; use opentally::parser::blt; use opentally::stv; use opentally::ties::TieStrategy; @@ -146,3 +148,28 @@ fn tideman_a34_prsa1977_rational() { // Assert count completes } + +/// Surplus votes need to be transferred at values received +#[test] +fn surplus_values_received() { + let stv_opts = stv::STVOptionsBuilder::default() + .round_surplus_fractions(Some(2)) + .round_values(Some(2)) + .round_votes(Some(2)) + .round_quota(Some(2)) + .quota(stv::QuotaType::DroopExact) + .quota_criterion(stv::QuotaCriterion::GreaterOrEqual) + .quota_mode(stv::QuotaMode::ERS97) + .surplus(stv::SurplusMethod::EG) + .transferable_only(true) + .exclusion(stv::ExclusionMethod::ByValue) + .bulk_exclude(true) + .defer_surpluses(true) + .build().unwrap(); + + Fixed::set_dps(5); + + assert_eq!(stv_opts.describe::(), "--numbers fixed --decimals 5 --round-surplus-fractions 2 --round-values 2 --round-votes 2 --round-quota 2 --quota droop_exact --quota-criterion geq --quota-mode ers97 --surplus eg --transferable-only --exclusion by_value --bulk-exclude --defer-surpluses"); + + utils::read_validate_election::("tests/data/surplus_values_received.csv", "tests/data/surplus_values_received.blt", stv_opts, None, &["exhausted"]); +}