1use crate::arithmetic::{Integer, IntegerRef, Rational, RationalRef};
19use crate::cli::Parallel;
20use crate::parallelism::{RangeStrategy, ThreadAccumulator, ThreadPool};
21use crate::types::{Ballot, Election};
22use log::Level::{Trace, Warn};
23use log::{debug, log_enabled, trace, warn};
24use rayon::prelude::*;
25use std::io;
26use std::marker::PhantomData;
27use std::num::NonZeroUsize;
28use std::sync::{Arc, RwLock, RwLockReadGuard};
29use std::thread::Scope;
30
31#[cfg_attr(test, derive(Debug, PartialEq))]
33pub struct VoteCount<I, R> {
34 pub sum: Vec<R>,
36 pub exhausted: R,
38 _phantom: PhantomData<I>,
39}
40
41#[cfg(test)]
42impl<I, R> VoteCount<I, R>
43where
44 R: Clone,
45{
46 pub(crate) fn new(sum: impl Into<Vec<R>>, exhausted: R) -> Self {
47 VoteCount {
48 sum: sum.into(),
49 exhausted,
50 _phantom: PhantomData,
51 }
52 }
53}
54
55#[derive(Clone)]
56pub struct VoteAccumulator<I, R> {
57 sum: Vec<R>,
59 exhausted: R,
61 fn_calls: usize,
63 _phantom: PhantomData<I>,
64}
65
66impl<I, R> VoteAccumulator<I, R>
67where
68 I: Integer,
69 for<'a> &'a I: IntegerRef<I>,
70 R: Rational<I>,
71 for<'a> &'a R: RationalRef<&'a I, R>,
72{
73 pub(crate) fn new(num_candidates: usize) -> Self {
74 Self {
75 sum: vec![R::zero(); num_candidates],
76 exhausted: R::zero(),
77 fn_calls: 0,
78 _phantom: PhantomData,
79 }
80 }
81
82 pub(crate) fn reduce(self, other: Self) -> Self {
83 Self {
84 sum: std::iter::zip(self.sum, other.sum)
85 .map(|(a, b)| a + b)
86 .collect(),
87 exhausted: self.exhausted + other.exhausted,
88 fn_calls: self.fn_calls + other.fn_calls,
89 _phantom: PhantomData,
90 }
91 }
92
93 fn into_vote_count(self) -> VoteCount<I, R> {
94 VoteCount {
95 sum: self.sum,
96 exhausted: self.exhausted,
97 _phantom: PhantomData,
98 }
99 }
100}
101
102pub struct VoteCountingThreadPool<'scope, I, R> {
104 pool: ThreadPool<'scope, VoteAccumulator<I, R>>,
106 keep_factors: Arc<RwLock<Vec<R>>>,
109}
110
111impl<'scope, I, R> VoteCountingThreadPool<'scope, I, R>
112where
113 I: Integer + Send + Sync + 'scope,
114 for<'a> &'a I: IntegerRef<I>,
115 R: Rational<I> + Send + Sync + 'scope,
116 for<'a> &'a R: RationalRef<&'a I, R>,
117{
118 pub fn new<'env>(
121 thread_scope: &'scope Scope<'scope, 'env>,
122 num_threads: NonZeroUsize,
123 range_strategy: RangeStrategy,
124 election: &'env Election,
125 pascal: Option<&'env [Vec<I>]>,
126 ) -> Self {
127 let keep_factors = Arc::new(RwLock::new(Vec::new()));
128 Self {
129 pool: ThreadPool::new(
130 thread_scope,
131 num_threads,
132 range_strategy,
133 &election.ballots,
134 || ThreadVoteCounter {
135 num_candidates: election.num_candidates,
136 pascal,
137 keep_factors: keep_factors.clone(),
138 },
139 ),
140 keep_factors,
141 }
142 }
143
144 pub fn accumulate_votes(&self, keep_factors: &[R]) -> VoteAccumulator<I, R> {
147 {
148 let mut keep_factors_guard = self.keep_factors.write().unwrap();
149 keep_factors_guard.clear();
150 keep_factors_guard.extend_from_slice(keep_factors);
151 }
152
153 self.pool
154 .process_inputs()
155 .reduce(|a, b| a.reduce(b))
156 .unwrap()
157 }
158}
159
160struct ThreadVoteCounter<'env, I, R> {
162 num_candidates: usize,
164 pascal: Option<&'env [Vec<I>]>,
166 keep_factors: Arc<RwLock<Vec<R>>>,
168}
169
170impl<I, R> ThreadAccumulator<Ballot, VoteAccumulator<I, R>> for ThreadVoteCounter<'_, I, R>
171where
172 I: Integer,
173 for<'a> &'a I: IntegerRef<I>,
174 R: Rational<I>,
175 for<'a> &'a R: RationalRef<&'a I, R>,
176{
177 type Accumulator<'a>
178 = (VoteAccumulator<I, R>, RwLockReadGuard<'a, Vec<R>>)
179 where
180 Self: 'a,
181 I: 'a,
182 R: 'a;
183
184 fn init(&self) -> Self::Accumulator<'_> {
185 (
186 VoteAccumulator::new(self.num_candidates),
187 self.keep_factors.read().unwrap(),
188 )
189 }
190
191 fn process_item<'a>(
192 &'a self,
193 accumulator: &mut Self::Accumulator<'a>,
194 index: usize,
195 ballot: &Ballot,
196 ) {
197 let (vote_accumulator, keep_factors) = accumulator;
198 VoteCount::<I, R>::process_ballot(
199 vote_accumulator,
200 keep_factors,
201 self.pascal,
202 index,
203 ballot,
204 );
205 }
206
207 fn finalize<'a>(&'a self, accumulator: Self::Accumulator<'a>) -> VoteAccumulator<I, R> {
208 accumulator.0
209 }
210}
211
212impl<I, R> VoteCount<I, R>
213where
214 I: Integer + Send + Sync,
215 for<'a> &'a I: IntegerRef<I>,
216 R: Rational<I> + Send + Sync,
217 for<'a> &'a R: RationalRef<&'a I, R>,
218{
219 pub fn count_votes(
221 election: &Election,
222 keep_factors: &[R],
223 parallel: Parallel,
224 thread_pool: Option<&VoteCountingThreadPool<'_, I, R>>,
225 pascal: Option<&[Vec<I>]>,
226 ) -> Self {
227 let vote_accumulator = match parallel {
228 Parallel::No => Self::accumulate_votes_serial(election, keep_factors, pascal),
229 Parallel::Rayon => Self::accumulate_votes_rayon(election, keep_factors, pascal),
230 Parallel::Custom => thread_pool.unwrap().accumulate_votes(keep_factors),
231 };
232
233 if log_enabled!(Trace) {
234 trace!("Finished counting ballots:");
235 for (i, x) in vote_accumulator.sum.iter().enumerate() {
236 trace!(" Sum[{i}] = {x} ~ {}", x.to_f64());
237 }
238 }
239
240 let equalize = pascal.is_some();
241 if !equalize {
242 debug!(
243 "Finished counting votes ({} recursive calls)",
244 vote_accumulator.fn_calls
245 );
246 }
247
248 vote_accumulator.into_vote_count()
249 }
250
251 fn accumulate_votes_rayon(
254 election: &Election,
255 keep_factors: &[R],
256 pascal: Option<&[Vec<I>]>,
257 ) -> VoteAccumulator<I, R> {
258 election
259 .ballots
260 .par_iter()
261 .enumerate()
262 .fold_with(
263 VoteAccumulator::new(election.num_candidates),
264 |mut vote_accumulator, (i, ballot)| {
265 Self::process_ballot(&mut vote_accumulator, keep_factors, pascal, i, ballot);
266 vote_accumulator
267 },
268 )
269 .reduce(
270 || VoteAccumulator::new(election.num_candidates),
271 |a, b| a.reduce(b),
272 )
273 }
274}
275
276impl<I, R> VoteCount<I, R>
277where
278 I: Integer,
279 for<'a> &'a I: IntegerRef<I>,
280 R: Rational<I>,
281 for<'a> &'a R: RationalRef<&'a I, R>,
282{
283 pub fn write_stats(
285 &self,
286 out: &mut impl io::Write,
287 threshold: &R,
288 surplus: &R,
289 ) -> io::Result<()> {
290 writeln!(out, "\tQuota: {threshold}")?;
291 let total_votes = self.sum.iter().sum::<R>();
292 writeln!(out, "\tVotes: {total_votes}")?;
293 writeln!(out, "\tResidual: {}", self.exhausted)?;
294 writeln!(out, "\tTotal: {}", total_votes + &self.exhausted)?;
295 writeln!(out, "\tSurplus: {surplus}")?;
296 Ok(())
297 }
298
299 fn accumulate_votes_serial(
301 election: &Election,
302 keep_factors: &[R],
303 pascal: Option<&[Vec<I>]>,
304 ) -> VoteAccumulator<I, R> {
305 let mut vote_accumulator = VoteAccumulator::new(election.num_candidates);
306 for (i, ballot) in election.ballots.iter().enumerate() {
307 Self::process_ballot(&mut vote_accumulator, keep_factors, pascal, i, ballot);
308 }
309 vote_accumulator
310 }
311
312 pub(crate) fn process_ballot(
314 vote_accumulator: &mut VoteAccumulator<I, R>,
315 keep_factors: &[R],
316 pascal: Option<&[Vec<I>]>,
317 i: usize,
318 ballot: &Ballot,
319 ) {
320 trace!("Processing ballot {i} = {:?}", ballot);
321
322 let mut unused_power = R::from_usize(ballot.count());
323 let counter = BallotCounter {
324 ballot,
325 sum: &mut vote_accumulator.sum,
326 unused_power: &mut unused_power,
327 keep_factors,
328 fn_calls: &mut vote_accumulator.fn_calls,
329 pascal,
330 _phantom: PhantomData,
331 };
332
333 let equalize = pascal.is_some();
334 if equalize {
335 counter.process_ballot_equalize()
336 } else {
337 counter.process_ballot_rec()
338 };
339
340 if log_enabled!(Trace) {
341 if !unused_power.is_zero() {
342 let pwr = &unused_power / &I::from_usize(ballot.count());
343 trace!(" Exhausted voting_power = {pwr} ~ {}", pwr.to_f64());
344 } else {
345 trace!(" Exhausted voting_power is zero :)");
346 }
347 }
348
349 vote_accumulator.exhausted += unused_power;
350 }
351
352 pub fn threshold(&self, election: &Election) -> R {
355 Self::threshold_exhausted(election, &self.exhausted)
356 }
357
358 pub fn surplus_droop(&self, threshold: &R, elected: &[usize]) -> R {
369 elected
370 .iter()
371 .map(|&i| {
372 let result = &self.sum[i] - threshold;
373 if log_enabled!(Warn) && result < R::zero() {
374 warn!(
375 "Candidate #{i} was elected but received fewer votes than the threshold."
376 );
377 }
378 result
379 })
380 .sum()
381 }
382
383 pub fn surplus_positive(&self, threshold: &R, elected: &[usize]) -> R {
393 elected
394 .iter()
395 .map(|&i| {
396 let x = &self.sum[i];
397 if x < threshold {
398 warn!(
399 "Candidate #{i} was elected but received fewer votes than the threshold."
400 );
401 R::zero()
402 } else {
403 x - threshold
404 }
405 })
406 .sum()
407 }
408
409 pub fn threshold_exhausted(election: &Election, exhausted: &R) -> R {
416 let numerator = R::from_usize(election.num_ballots) - exhausted;
417 let denominator = I::from_usize(election.num_seats + 1);
418 let result = &numerator / &denominator + R::epsilon();
419 debug!(
420 "threshold_exhausted = {numerator} / {denominator:?} + {} ~ {} / {:?} + {}",
421 R::epsilon(),
422 numerator.to_f64(),
423 R::from_int(denominator.clone()).to_f64(),
424 R::epsilon().to_f64(),
425 );
426 debug!("\t= {result} ~ {}", result.to_f64());
427 result
428 }
429}
430
431struct BallotCounter<'a, I, R> {
432 ballot: &'a Ballot,
434 sum: &'a mut [R],
436 unused_power: &'a mut R,
439 keep_factors: &'a [R],
441 fn_calls: &'a mut usize,
443 pascal: Option<&'a [Vec<I>]>,
446 _phantom: PhantomData<I>,
447}
448
449impl<I, R> BallotCounter<'_, I, R>
450where
451 I: Integer,
452 for<'a> &'a I: IntegerRef<I>,
453 R: Rational<I>,
454 for<'a> &'a R: RationalRef<&'a I, R>,
455{
456 fn process_ballot_rec(mut self) {
459 let voting_power = R::one();
460 let ballot_count = I::from_usize(self.ballot.count());
461 if !self.ballot.has_tie() {
462 self.process_ballot_rec_notie(voting_power, &ballot_count);
463 } else {
464 self.process_ballot_rec_impl(voting_power, &ballot_count, 0);
465 }
466 }
467
468 fn process_ballot_rec_notie(&mut self, mut voting_power: R, ballot_count: &I) {
478 *self.fn_calls += 1;
479
480 for ranking in self.ballot.order() {
481 let candidate = ranking[0].into();
483 let (used_power, remaining_power) =
484 self.split_power_one_candidate(&voting_power, candidate);
485 self.increment_candidate(candidate, used_power, ballot_count);
486 voting_power = remaining_power;
487 if voting_power.is_zero() {
488 break;
489 }
490 }
491 }
492
493 fn process_ballot_rec_impl(&mut self, mut voting_power: R, ballot_count: &I, i: usize) {
519 *self.fn_calls += 1;
520 if i == self.ballot.order_len() {
521 return;
522 }
523
524 let ranking = self.ballot.order_at(i);
527
528 let filtered_ranking_len = ranking
532 .iter()
533 .filter(|&&candidate| !self.keep_factors[candidate.into()].is_zero())
534 .count();
535 if filtered_ranking_len == 0 {
538 return;
539 }
540
541 voting_power /= &I::from_usize(filtered_ranking_len);
548 for candidate in ranking.iter().filter_map(|&candidate| {
549 let candidate: usize = candidate.into();
550 if self.keep_factors[candidate].is_zero() {
551 None
552 } else {
553 Some(candidate)
554 }
555 }) {
556 let (used_power, remaining_power) =
557 self.split_power_one_candidate(&voting_power, candidate);
558 self.increment_candidate(candidate, used_power, ballot_count);
559 if !remaining_power.is_zero() {
560 self.process_ballot_rec_impl(remaining_power, ballot_count, i + 1)
561 }
562 }
563 }
564
565 fn process_ballot_equalize(mut self) {
578 let mut voting_power = R::one();
583 let ballot_count = I::from_usize(self.ballot.count());
584
585 let pascal: &[Vec<I>] = self.pascal.unwrap();
586
587 for ranking in self.ballot.order() {
588 if ranking.len() == 1 {
589 let candidate = ranking[0].into();
591 let (used_power, remaining_power) =
592 self.split_power_one_candidate(&voting_power, candidate);
593 self.increment_candidate(candidate, used_power, &ballot_count);
594 voting_power = remaining_power;
595 } else {
596 trace!(
598 " Ranking = {:?}",
599 ranking.iter().map(|&x| x.into()).collect::<Vec<_>>()
600 );
601 let ranking_keep_factors: Vec<R> = ranking
602 .iter()
603 .map(|&candidate| self.keep_factors[candidate.into()].clone())
604 .collect();
605 let ranking_unused_factors: Vec<R> =
608 ranking_keep_factors.iter().map(|k| R::one() - k).collect();
609 trace!(" Ranking keep_factors = {ranking_keep_factors:?}");
610 for (i, candidate) in ranking.iter().map(|&x| x.into()).enumerate() {
611 let w =
612 Self::polyweights(&ranking_unused_factors, i, &pascal[ranking.len() - 1])
613 * &ranking_keep_factors[i]
614 / I::from_usize(ranking.len());
615 trace!(" polyweight[{i}] = {w} ~ {}", w.to_f64());
616 let used_power = &voting_power * &w;
617 trace!(
618 " Sum[{candidate}] += {used_power} ~ {}",
619 used_power.to_f64()
620 );
621 self.increment_candidate(candidate, used_power, &ballot_count);
622 }
623 let remaining_power: R = ranking_unused_factors.into_iter().product();
632 voting_power *= remaining_power;
633 }
634 if voting_power.is_zero() {
635 break;
636 }
637 }
638 }
639
640 fn increment_candidate(&mut self, candidate: usize, used_power: R, ballot_count: &I) {
647 let scaled_power = &used_power * ballot_count;
648 self.sum[candidate] += &scaled_power;
649 *self.unused_power -= &scaled_power;
650 }
651
652 fn split_power_one_candidate(&self, voting_power: &R, candidate: usize) -> (R, R) {
655 let keep_factor = &self.keep_factors[candidate];
656 let used_power = voting_power * keep_factor;
659 let remaining_power = voting_power * &(R::one() - keep_factor);
664
665 trace!(
666 " Split[{candidate}]: used = {used_power} ~ {} | remaining = {remaining_power} ~ {}",
667 used_power.to_f64(),
668 remaining_power.to_f64(),
669 );
670
671 if log_enabled!(Trace) {
672 let total = &used_power + &remaining_power;
673 if &total > voting_power {
675 trace!(
676 "used + remaining > voting | {} + {} = {} > {}",
677 used_power.to_f64(),
678 remaining_power.to_f64(),
679 total.to_f64(),
680 voting_power.to_f64()
681 );
682 }
683 }
684
685 (used_power, remaining_power)
686 }
687
688 #[allow(clippy::needless_range_loop)]
700 fn polyweights(ranking_unused_factors: &[R], skip: usize, pascal_row: &[I]) -> R {
701 let n = ranking_unused_factors.len() - 1;
702 let poly = expand_polynomial(ranking_unused_factors, skip);
703
704 let mut result = R::zero();
705 for i in 0..=n {
706 result += &poly[i] / &pascal_row[i];
707 }
708 result
709 }
710}
711
712#[allow(clippy::needless_range_loop)]
728fn expand_polynomial<I, R>(coefficients: &[R], skip: usize) -> Vec<R>
729where
730 I: Integer,
731 for<'a> &'a I: IntegerRef<I>,
732 R: Rational<I>,
733 for<'a> &'a R: RationalRef<&'a I, R>,
734{
735 let n = coefficients.len() - 1;
738 let mut poly = vec![R::zero(); n + 1];
740 poly[0] = R::one();
742
743 for (i, a) in coefficients.iter().enumerate() {
746 if i == skip {
747 continue;
748 }
749
750 if !a.is_zero() {
752 let mut prev = poly[0].clone();
765 for j in 1..=n {
766 let tmp = poly[j].clone();
767 poly[j] += prev * a;
768 prev = tmp;
769 }
770 }
771 }
772
773 poly
774}
775
776pub fn pascal<I>(n: usize) -> Vec<Vec<I>>
780where
781 I: Integer,
782 for<'a> &'a I: IntegerRef<I>,
783{
784 let mut result = Vec::new();
785
786 let mut row = vec![I::zero(); n + 1];
787 row[0] = I::one();
788 result.push(row);
789
790 for i in 1..=n {
791 let row = result.last().unwrap();
792 let mut newrow = vec![I::zero(); n + 1];
793 newrow[0] = I::one();
794 for j in 1..=i {
795 newrow[j] = &row[j - 1] + &row[j];
796 }
797 result.push(newrow);
798 }
799 result
800}
801
802#[cfg(test)]
803mod test {
804 use super::*;
805 use crate::arithmetic::{ApproxRational, BigFixedDecimal9, FixedDecimal9, Integer64};
806 use crate::types::Candidate;
807 use ::test::Bencher;
808 use num::rational::Ratio;
809 use num::{BigInt, BigRational};
810 use std::borrow::Borrow;
811 use std::fmt::{Debug, Display};
812 use std::hint::black_box;
813
814 macro_rules! numeric_tests {
815 ( $typei:ty, $typer:ty, ) => {};
816 ( $typei:ty, $typer:ty, $case:ident, $( $others:tt )* ) => {
817 #[test]
818 fn $case() {
819 $crate::vote_count::test::NumericTests::<$typei, $typer>::$case();
820 }
821
822 numeric_tests!($typei, $typer, $($others)*);
823 };
824 ( $typei:ty, $typer:ty, $case:ident => fail($msg:expr), $( $others:tt )* ) => {
825 #[test]
826 #[should_panic(expected = $msg)]
827 fn $case() {
828 $crate::vote_count::test::NumericTests::<$typei, $typer>::$case();
829 }
830
831 numeric_tests!($typei, $typer, $($others)*);
832 };
833 }
834
835 macro_rules! numeric_benches {
836 ( $typei:ty, $typer:ty, $($case:ident,)+ ) => {
837 $(
838 #[bench]
839 fn $case(b: &mut ::test::Bencher) {
840 $crate::vote_count::test::NumericTests::<$typei, $typer>::$case(b);
841 }
842 )+
843 };
844 }
845
846 macro_rules! all_numeric_benches {
847 ( $typei:ty, $typer:ty ) => {
848 numeric_benches!(
849 $typei,
850 $typer,
851 bench_count_votes_serial_16,
852 bench_count_votes_serial_32,
853 bench_count_votes_serial_64,
854 bench_count_votes_serial_128,
855 bench_count_votes_parallel_16,
856 bench_count_votes_parallel_32,
857 bench_count_votes_parallel_64,
858 bench_count_votes_parallel_128,
859 bench_process_ballot_rec_chain,
860 bench_process_ballot_rec_pairs_01,
861 bench_process_ballot_rec_pairs_02,
862 bench_process_ballot_rec_pairs_03,
863 bench_process_ballot_rec_pairs_04,
864 bench_process_ballot_rec_pairs_05,
865 bench_process_ballot_rec_pairs_06,
866 bench_process_ballot_rec_pairs_07,
867 bench_process_ballot_rec_pairs_08,
868 bench_process_ballot_rec_pairs_09,
869 bench_process_ballot_rec_pairs_10,
870 bench_process_ballot_rec_tens_1,
871 bench_process_ballot_rec_tens_2,
872 bench_process_ballot_rec_tens_3,
873 bench_process_ballot_rec_tens_4,
874 bench_process_ballot_equalize_chain,
875 bench_process_ballot_equalize_pairs_01,
876 bench_process_ballot_equalize_pairs_02,
877 bench_process_ballot_equalize_pairs_03,
878 bench_process_ballot_equalize_pairs_04,
879 bench_process_ballot_equalize_pairs_05,
880 bench_process_ballot_equalize_pairs_06,
881 bench_process_ballot_equalize_pairs_07,
882 bench_process_ballot_equalize_pairs_08,
883 bench_process_ballot_equalize_pairs_09,
884 bench_process_ballot_equalize_pairs_10,
885 bench_process_ballot_equalize_pairs_15,
886 bench_process_ballot_equalize_tens_1,
887 bench_process_ballot_equalize_tens_2,
888 bench_process_ballot_equalize_tens_3,
889 bench_process_ballot_equalize_tens_4,
890 );
891 };
892 }
893
894 macro_rules! base_numeric_tests {
895 ( $typei:ty, $typer:ty ) => {
896 numeric_tests!(
897 $typei,
898 $typer,
899 test_write_stats,
900 test_threshold,
901 test_threshold_exhausted,
902 test_surplus_droop,
903 test_surplus_positive,
904 test_process_ballot_first,
905 test_process_ballot_chain,
906 test_process_ballot_defeated,
907 test_process_ballot_rec_tie_first,
908 test_process_ballot_rec_tie_chain,
909 test_process_ballot_rec_tie_defeated,
910 test_process_ballot_rec_ties,
911 test_process_ballot_multiplier,
912 test_increment_candidate_ballot_multiplier,
913 test_pascal_small,
914 test_pascal_50,
915 test_expand_polynomial,
916 test_polyweights,
917 );
918 };
919 }
920
921 macro_rules! advanced_numeric_tests {
922 ( $typei:ty, $typer:ty ) => {
923 numeric_tests!(
924 $typei,
925 $typer,
926 test_count_votes_rayon_is_consistent,
927 test_count_votes_parallel_is_consistent,
928 );
929 };
930 }
931
932 macro_rules! all_numeric_tests {
933 ( $mod:ident, $typei:ty, $typer:ty, $( $other_tests:tt )* ) => {
934 mod $mod {
935 use super::*;
936
937 base_numeric_tests!($typei, $typer);
938 advanced_numeric_tests!($typei, $typer);
939 numeric_tests!($typei, $typer, $($other_tests)*);
940 all_numeric_benches!($typei, $typer);
941 }
942 };
943 }
944
945 all_numeric_tests!(exact, BigInt, BigRational, test_pascal_100,);
946 all_numeric_tests!(approx_rational, BigInt, ApproxRational, test_pascal_100,);
947 #[cfg(not(any(feature = "checked_i64", overflow_checks)))]
948 all_numeric_tests!(fixed, Integer64, FixedDecimal9, test_pascal_100,);
949 #[cfg(feature = "checked_i64")]
950 all_numeric_tests!(
951 fixed,
952 Integer64,
953 FixedDecimal9,
954 test_pascal_100 => fail(r"called `Option::unwrap()` on a `None` value"),
955 );
956 #[cfg(all(not(feature = "checked_i64"), overflow_checks))]
957 all_numeric_tests!(
958 fixed,
959 Integer64,
960 FixedDecimal9,
961 test_pascal_100 => fail(r"attempt to add with overflow"),
962 );
963 all_numeric_tests!(fixed_big, BigInt, BigFixedDecimal9, test_pascal_100,);
964
965 mod ratio_i64 {
966 use super::*;
967 base_numeric_tests!(i64, Ratio<i64>);
968 #[cfg(not(overflow_checks))]
969 numeric_tests!(i64, Ratio<i64>, test_pascal_100,);
970 #[cfg(not(overflow_checks))]
971 all_numeric_benches!(i64, Ratio<i64>);
972 }
973
974 mod float64 {
975 all_numeric_benches!(f64, f64);
976 numeric_tests!(f64, f64, test_pascal_100,);
977 }
978
979 pub struct NumericTests<I, R> {
980 _phantomi: PhantomData<I>,
981 _phantomr: PhantomData<R>,
982 }
983
984 impl<I, R> NumericTests<I, R>
985 where
986 I: Integer + Send + Sync + Display + Debug + PartialEq,
987 for<'a> &'a I: IntegerRef<I>,
988 R: Rational<I> + Send + Sync,
989 for<'a> &'a R: RationalRef<&'a I, R>,
990 {
991 fn test_write_stats() {
992 let mut buf = Vec::new();
993
994 let vote_count = VoteCount {
995 sum: (0..10).map(R::from_usize).collect(),
996 exhausted: R::from_usize(42),
997 _phantom: PhantomData,
998 };
999 vote_count
1000 .write_stats(
1001 &mut buf,
1002 &R::from_usize(123),
1003 &R::from_usize(456),
1004 )
1005 .unwrap();
1006
1007 let stdout = std::str::from_utf8(&buf).unwrap();
1008 let expected = format!(
1009 "\tQuota: {quota}\n\tVotes: {votes}\n\tResidual: {residual}\n\tTotal: {total}\n\tSurplus: {surplus}\n",
1010 quota = R::from_usize(123),
1011 votes = R::from_usize(45),
1012 residual = R::from_usize(42),
1013 total = R::from_usize(87),
1014 surplus = R::from_usize(456)
1015 );
1016 assert_eq!(stdout, expected);
1017 }
1018
1019 fn test_threshold() {
1020 for num_seats in 0..10 {
1021 for num_ballots in 0..100 {
1022 let election = Election::builder()
1023 .title("")
1024 .num_seats(num_seats)
1025 .num_ballots(num_ballots)
1026 .build();
1027
1028 let vote_count = VoteCount {
1029 sum: Vec::new(),
1030 exhausted: R::zero(),
1031 _phantom: PhantomData,
1032 };
1033 assert_eq!(
1034 vote_count.threshold(&election),
1035 R::ratio(num_ballots, num_seats + 1) + R::epsilon()
1036 );
1037
1038 let exhausted = std::cmp::min(num_ballots, 42);
1039 let vote_count = VoteCount {
1040 sum: Vec::new(),
1041 exhausted: R::from_usize(exhausted),
1042 _phantom: PhantomData,
1043 };
1044 assert_eq!(
1045 vote_count.threshold(&election),
1046 R::ratio(num_ballots - exhausted, num_seats + 1) + R::epsilon()
1047 );
1048 }
1049 }
1050 }
1051
1052 fn test_threshold_exhausted() {
1053 for num_seats in 0..10 {
1054 for num_ballots in 0..100 {
1055 let election = Election::builder()
1056 .title("")
1057 .num_seats(num_seats)
1058 .num_ballots(num_ballots)
1059 .build();
1060
1061 assert_eq!(
1062 VoteCount::threshold_exhausted(
1063 &election,
1064 &R::zero()
1065 ),
1066 R::ratio(num_ballots, num_seats + 1) + R::epsilon()
1067 );
1068
1069 let exhausted = std::cmp::min(num_ballots, 42);
1070 assert_eq!(
1071 VoteCount::threshold_exhausted(
1072 &election,
1073 &R::from_usize(exhausted)
1074 ),
1075 R::ratio(num_ballots - exhausted, num_seats + 1) + R::epsilon()
1076 );
1077 }
1078 }
1079 }
1080
1081 fn test_surplus_droop() {
1082 let vote_count = VoteCount {
1083 sum: vec![
1084 R::ratio(14, 100),
1085 R::ratio(28, 100),
1086 R::ratio(57, 100),
1087 R::ratio(42, 100),
1088 R::ratio(85, 100),
1089 R::ratio(71, 100),
1090 ],
1091 exhausted: R::zero(),
1092 _phantom: PhantomData,
1093 };
1094
1095 assert_eq!(
1096 vote_count.surplus_droop(&R::ratio(10, 100), &[0]),
1097 R::ratio(4, 100)
1098 );
1099
1100 assert_eq!(
1101 vote_count.surplus_droop(&R::ratio(10, 100), &[0, 1, 2, 3, 4, 5]),
1102 R::ratio(237, 100)
1103 );
1104 assert_eq!(
1105 vote_count.surplus_droop(&R::ratio(40, 100), &[2, 3, 4, 5]),
1106 R::ratio(95, 100)
1107 );
1108 assert_eq!(
1109 vote_count.surplus_droop(&R::ratio(40, 100), &[0, 1, 2, 3, 4, 5]),
1110 R::ratio(57, 100)
1111 );
1112 }
1113
1114 fn test_surplus_positive() {
1115 let vote_count = VoteCount {
1116 sum: vec![
1117 R::ratio(14, 100),
1118 R::ratio(28, 100),
1119 R::ratio(57, 100),
1120 R::ratio(42, 100),
1121 R::ratio(85, 100),
1122 R::ratio(71, 100),
1123 ],
1124 exhausted: R::zero(),
1125 _phantom: PhantomData,
1126 };
1127
1128 assert_eq!(
1129 vote_count.surplus_positive(&R::ratio(10, 100), &[0]),
1130 R::ratio(4, 100)
1131 );
1132
1133 assert_eq!(
1134 vote_count.surplus_positive(&R::ratio(10, 100), &[0, 1, 2, 3, 4, 5]),
1135 R::ratio(237, 100)
1136 );
1137 assert_eq!(
1138 vote_count.surplus_positive(&R::ratio(40, 100), &[2, 3, 4, 5]),
1139 R::ratio(95, 100)
1140 );
1141 assert_eq!(
1142 vote_count.surplus_positive(&R::ratio(40, 100), &[0, 1, 2, 3, 4, 5]),
1143 R::ratio(95, 100)
1144 );
1145 }
1146
1147 fn fake_ballots(n: usize) -> Vec<Ballot> {
1148 let mut ballots = Vec::new();
1149 for i in 0..n {
1150 ballots.push(Ballot::new(1, [vec![i]]));
1151 for j in 0..i {
1152 ballots.push(Ballot::new(1, [vec![i], vec![j]]));
1153 }
1154 }
1155 ballots
1156 }
1157
1158 fn fake_keep_factors(n: usize) -> Vec<R> {
1159 (1..=n).map(|i| R::ratio(1, i + 1)).collect()
1160 }
1161
1162 fn fake_candidates(n: usize) -> Vec<Candidate> {
1163 (0..n)
1164 .map(|i| Candidate::new(format!("candidate{i}"), false))
1165 .collect()
1166 }
1167
1168 fn test_count_votes_rayon_is_consistent() {
1169 for n in [1, 2, 4, 8, 16, 32, 64, 128] {
1170 let ballots = Self::fake_ballots(n);
1171 let keep_factors = Self::fake_keep_factors(n);
1172 let election = Election::builder()
1173 .title("")
1174 .candidates(Self::fake_candidates(n))
1175 .num_seats(0)
1176 .ballots(ballots)
1177 .build();
1178
1179 let vote_count = VoteCount::<I, R>::count_votes(
1180 &election,
1181 &keep_factors,
1182 Parallel::No,
1183 None,
1184 None,
1185 );
1186 let vote_count_parallel = VoteCount::<I, R>::count_votes(
1187 &election,
1188 &keep_factors,
1189 Parallel::Rayon,
1190 None,
1191 None,
1192 );
1193 assert_eq!(
1194 vote_count, vote_count_parallel,
1195 "Mismatch with {n} candidates"
1196 );
1197 }
1198 }
1199
1200 fn test_count_votes_parallel_is_consistent() {
1201 for n in [1, 2, 4, 8, 16, 32, 64, 128] {
1202 let ballots = Self::fake_ballots(n);
1203 let keep_factors = Self::fake_keep_factors(n);
1204 let election = Election::builder()
1205 .title("")
1206 .candidates(Self::fake_candidates(n))
1207 .num_seats(0)
1208 .ballots(ballots)
1209 .build();
1210
1211 let vote_count = VoteCount::<I, R>::count_votes(
1212 &election,
1213 &keep_factors,
1214 Parallel::No,
1215 None,
1216 None,
1217 );
1218
1219 for num_threads in 1..=10 {
1220 std::thread::scope(|thread_scope| {
1221 let thread_pool = VoteCountingThreadPool::new(
1222 thread_scope,
1223 NonZeroUsize::new(num_threads).unwrap(),
1224 RangeStrategy::WorkStealing,
1225 &election,
1226 None,
1227 );
1228 let vote_count_parallel = VoteCount::<I, R>::count_votes(
1229 &election,
1230 &keep_factors,
1231 Parallel::Custom,
1232 Some(&thread_pool),
1233 None,
1234 );
1235 assert_eq!(
1236 vote_count, vote_count_parallel,
1237 "Mismatch with {n} candidates"
1238 );
1239 });
1240 }
1241 }
1242 }
1243
1244 fn process_ballot_rec(
1245 ballot: impl Borrow<Ballot>,
1246 keep_factors: &[R],
1247 ) -> (Vec<R>, R, usize) {
1248 let num_candidates = keep_factors.len();
1249 let mut sum = vec![R::zero(); num_candidates];
1250 let mut unused_power = R::one();
1251 let mut fn_calls = 0;
1252
1253 let counter = BallotCounter {
1254 ballot: ballot.borrow(),
1255 sum: &mut sum,
1256 unused_power: &mut unused_power,
1257 keep_factors,
1258 fn_calls: &mut fn_calls,
1259 pascal: None,
1260 _phantom: PhantomData,
1261 };
1262 counter.process_ballot_rec();
1263
1264 (sum, unused_power, fn_calls)
1265 }
1266
1267 fn process_ballot_equalize(
1268 ballot: impl Borrow<Ballot>,
1269 keep_factors: &[R],
1270 pascal: &[Vec<I>],
1271 ) -> (Vec<R>, R) {
1272 let num_candidates = keep_factors.len();
1273 let mut sum = vec![R::zero(); num_candidates];
1274 let mut unused_power = R::one();
1275
1276 let counter = BallotCounter {
1277 ballot: ballot.borrow(),
1278 sum: &mut sum,
1279 unused_power: &mut unused_power,
1280 keep_factors,
1281 fn_calls: &mut 0,
1282 pascal: Some(pascal),
1283 _phantom: PhantomData,
1284 };
1285 counter.process_ballot_equalize();
1286
1287 (sum, unused_power)
1288 }
1289
1290 fn test_process_ballot_first() {
1292 let ballot = Ballot::new(1, [vec![0], vec![1], vec![2]]);
1293 let keep_factors = [R::one(), R::one(), R::one()];
1294 let pascal = pascal::<I>(3);
1295
1296 let (sum, unused_power, fn_calls) = Self::process_ballot_rec(&ballot, &keep_factors);
1298 assert_eq!(sum, vec![R::one(), R::zero(), R::zero()]);
1299 assert_eq!(unused_power, R::zero());
1300 assert_eq!(fn_calls, 1);
1301
1302 let (sum, unused_power) =
1304 Self::process_ballot_equalize(&ballot, &keep_factors, &pascal);
1305 assert_eq!(sum, vec![R::one(), R::zero(), R::zero()]);
1306 assert_eq!(unused_power, R::zero());
1307 }
1308
1309 fn test_process_ballot_chain() {
1311 let ballot = Ballot::new(1, [vec![0], vec![1], vec![2]]);
1312 let keep_factors = [R::ratio(1, 2), R::ratio(2, 3), R::ratio(3, 4)];
1313 let pascal = pascal::<I>(3);
1314
1315 let (sum, unused_power, fn_calls) = Self::process_ballot_rec(&ballot, &keep_factors);
1317 assert_eq!(sum, vec![R::ratio(1, 2), R::ratio(1, 3), R::ratio(1, 8)]);
1318 assert_eq!(unused_power, R::one() - R::ratio(23, 24));
1319 assert_eq!(fn_calls, 1);
1320
1321 let (sum, unused_power) =
1323 Self::process_ballot_equalize(&ballot, &keep_factors, &pascal);
1324 assert_eq!(sum, vec![R::ratio(1, 2), R::ratio(1, 3), R::ratio(1, 8)]);
1325 assert_eq!(unused_power, R::one() - R::ratio(23, 24));
1326 }
1327
1328 fn test_process_ballot_defeated() {
1330 let ballot = Ballot::new(1, [vec![0], vec![1], vec![2]]);
1331 let keep_factors = [R::zero(), R::ratio(2, 3), R::ratio(3, 4)];
1332 let pascal = pascal::<I>(3);
1333
1334 let (sum, unused_power, fn_calls) = Self::process_ballot_rec(&ballot, &keep_factors);
1336 assert_eq!(sum, vec![R::zero(), R::ratio(2, 3), R::ratio(1, 4)]);
1337 assert_eq!(unused_power, R::one() - R::ratio(11, 12));
1338 assert_eq!(fn_calls, 1);
1339
1340 let (sum, unused_power) =
1342 Self::process_ballot_equalize(&ballot, &keep_factors, &pascal);
1343 assert_eq!(sum, vec![R::zero(), R::ratio(2, 3), R::ratio(1, 4)]);
1344 assert_eq!(unused_power, R::one() - R::ratio(11, 12));
1345 }
1346
1347 fn test_process_ballot_rec_tie_first() {
1349 let (sum, unused_power, fn_calls) = Self::process_ballot_rec(
1350 Ballot::new(1, [vec![0, 1], vec![2]]),
1351 &[R::one(), R::one(), R::one()],
1352 );
1353
1354 assert_eq!(sum, vec![R::ratio(1, 2), R::ratio(1, 2), R::zero()]);
1355 assert_eq!(unused_power, R::zero());
1356 assert_eq!(fn_calls, 1);
1357 }
1358
1359 fn test_process_ballot_rec_tie_chain() {
1361 let (sum, unused_power, fn_calls) = Self::process_ballot_rec(
1362 Ballot::new(1, [vec![0, 1], vec![2]]),
1363 &[R::ratio(1, 2), R::ratio(2, 3), R::ratio(3, 4)],
1364 );
1365
1366 assert_eq!(sum, vec![R::ratio(1, 4), R::ratio(1, 3), R::ratio(5, 16)]);
1368 assert_eq!(unused_power, R::one() - R::ratio(43, 48));
1370 assert_eq!(fn_calls, 5);
1371 }
1372
1373 fn test_process_ballot_rec_tie_defeated() {
1375 let (sum, unused_power, fn_calls) = Self::process_ballot_rec(
1376 Ballot::new(1, [vec![0], vec![1, 2]]),
1377 &[R::zero(), R::ratio(2, 3), R::ratio(3, 4)],
1378 );
1379
1380 assert_eq!(sum, vec![R::zero(); 3]);
1382 assert_eq!(unused_power, R::one());
1383 assert_eq!(fn_calls, 1);
1384 }
1385
1386 fn test_process_ballot_rec_ties() {
1388 let (sum, unused_power, fn_calls) = Self::process_ballot_rec(
1389 Ballot::new(1, [vec![0, 1], vec![2, 3]]),
1390 &[
1392 R::ratio(1, 2),
1393 R::ratio(2, 3),
1394 R::ratio(3, 4),
1395 R::ratio(4, 5),
1396 ],
1397 );
1398
1399 assert_eq!(
1401 sum,
1402 vec![
1403 R::ratio(1, 4),
1404 R::ratio(1, 3),
1405 R::ratio(5, 24) * R::ratio(3, 4),
1407 R::ratio(1, 6),
1409 ]
1410 );
1411 assert_eq!(
1413 unused_power,
1414 R::one()
1415 - (R::ratio(1, 4)
1416 + R::ratio(1, 3)
1417 + R::ratio(5, 24) * R::ratio(3, 4)
1418 + R::ratio(1, 6))
1419 );
1420 assert_eq!(fn_calls, 7);
1421 }
1422
1423 fn test_process_ballot_multiplier() {
1424 let ballots = [
1425 vec![vec![0], vec![1], vec![2], vec![3], vec![4]],
1426 vec![vec![4], vec![3], vec![2], vec![1], vec![0]],
1427 vec![vec![0, 2], vec![1, 3, 4]],
1428 vec![vec![0, 1, 2, 3, 4]],
1429 ];
1430 let keep_factors_list = [
1431 [R::zero(), R::zero(), R::zero(), R::zero(), R::zero()],
1432 [R::one(), R::one(), R::one(), R::one(), R::one()],
1433 [
1434 R::ratio(1, 2),
1435 R::ratio(2, 3),
1436 R::ratio(4, 5),
1437 R::ratio(6, 7),
1438 R::ratio(10, 11),
1439 ],
1440 ];
1441 for keep_factors in &keep_factors_list {
1442 for order in &ballots {
1443 for ballot_count in 1..=30 {
1444 let left_vote_count = {
1446 let mut vote_accumulator = VoteAccumulator::new(5);
1447 let ballot = Ballot::new(ballot_count, order.clone());
1448 VoteCount::process_ballot(
1449 &mut vote_accumulator,
1450 keep_factors,
1451 None,
1452 0,
1453 &ballot,
1454 );
1455 vote_accumulator.into_vote_count()
1456 };
1457
1458 let right_vote_count = {
1460 let mut vote_accumulator = VoteAccumulator::new(5);
1461 let ballot = Ballot::new(1, order.clone());
1462 for _ in 0..ballot_count {
1463 VoteCount::process_ballot(
1464 &mut vote_accumulator,
1465 keep_factors,
1466 None,
1467 0,
1468 &ballot,
1469 );
1470 }
1471 vote_accumulator.into_vote_count()
1472 };
1473
1474 assert_eq!(left_vote_count.sum, right_vote_count.sum);
1476 assert_eq!(left_vote_count.exhausted, right_vote_count.exhausted);
1477 }
1478 }
1479 }
1480 }
1481
1482 fn test_increment_candidate_ballot_multiplier() {
1483 let empty_ballot = Ballot::empty();
1484 let empty_keep_factors = vec![];
1485
1486 for used_power in R::get_positive_test_values() {
1487 for ballot_count in 1..=30 {
1488 let (left_sum, left_unused_power) = {
1490 let mut sum = vec![R::zero()];
1491 let mut unused_power = R::zero();
1492 let mut ballot_counter = BallotCounter {
1493 ballot: &empty_ballot,
1494 sum: &mut sum,
1495 unused_power: &mut unused_power,
1496 keep_factors: &empty_keep_factors,
1497 fn_calls: &mut 0,
1498 pascal: None,
1499 _phantom: PhantomData,
1500 };
1501 ballot_counter.increment_candidate(
1502 0,
1503 used_power.clone(),
1504 &I::from_usize(ballot_count),
1505 );
1506 (sum, unused_power)
1507 };
1508
1509 let (right_sum, right_unused_power) = {
1512 let mut sum = vec![R::zero()];
1513 let mut unused_power = R::zero();
1514 let mut ballot_counter = BallotCounter {
1515 ballot: &empty_ballot,
1516 sum: &mut sum,
1517 unused_power: &mut unused_power,
1518 keep_factors: &empty_keep_factors,
1519 fn_calls: &mut 0,
1520 pascal: None,
1521 _phantom: PhantomData,
1522 };
1523 for _ in 0..ballot_count {
1524 ballot_counter.increment_candidate(
1525 0,
1526 used_power.clone(),
1527 &I::from_usize(1),
1528 );
1529 }
1530 (sum, unused_power)
1531 };
1532
1533 assert_ne!(left_sum[0], R::zero());
1535 assert_ne!(left_unused_power, R::zero());
1536
1537 assert_eq!(left_sum, right_sum);
1539 assert_eq!(left_unused_power, right_unused_power);
1540 }
1541 }
1542 }
1543
1544 fn test_pascal_small() {
1545 assert_eq!(
1546 pascal::<I>(0),
1547 [[1]].map(|row| row.map(I::from_usize).to_vec()).to_vec()
1548 );
1549 assert_eq!(
1550 pascal::<I>(1),
1551 [[1, 0], [1, 1]]
1552 .map(|row| row.map(I::from_usize).to_vec())
1553 .to_vec()
1554 );
1555 assert_eq!(
1556 pascal::<I>(5),
1557 [
1558 [1, 0, 0, 0, 0, 0],
1559 [1, 1, 0, 0, 0, 0],
1560 [1, 2, 1, 0, 0, 0],
1561 [1, 3, 3, 1, 0, 0],
1562 [1, 4, 6, 4, 1, 0],
1563 [1, 5, 10, 10, 5, 1],
1564 ]
1565 .map(|row| row.map(I::from_usize).to_vec())
1566 .to_vec()
1567 );
1568 assert_eq!(
1569 pascal::<I>(10),
1570 [
1571 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
1572 [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
1573 [1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0],
1574 [1, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0],
1575 [1, 4, 6, 4, 1, 0, 0, 0, 0, 0, 0],
1576 [1, 5, 10, 10, 5, 1, 0, 0, 0, 0, 0],
1577 [1, 6, 15, 20, 15, 6, 1, 0, 0, 0, 0],
1578 [1, 7, 21, 35, 35, 21, 7, 1, 0, 0, 0],
1579 [1, 8, 28, 56, 70, 56, 28, 8, 1, 0, 0],
1580 [1, 9, 36, 84, 126, 126, 84, 36, 9, 1, 0],
1581 [1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1],
1582 ]
1583 .map(|row| row.map(I::from_usize).to_vec())
1584 .to_vec()
1585 );
1586 }
1587
1588 fn test_pascal_50() {
1589 Self::test_pascal_properties(50);
1590 }
1591
1592 fn test_pascal_100() {
1593 Self::test_pascal_properties(100);
1594 }
1595
1596 fn test_pascal_properties(count: usize) {
1597 let pascal = pascal::<I>(count);
1598 for i in 0..=count {
1599 assert_eq!(pascal[i][0], I::from_usize(1));
1600 assert_eq!(pascal[i][i], I::from_usize(1));
1601 assert_eq!(pascal[i][1], I::from_usize(i));
1602 if i < count {
1603 assert_eq!(pascal[i + 1][i], I::from_usize(i + 1));
1604 }
1605 for j in 1..=i {
1606 assert_eq!(pascal[i][j], &pascal[i - 1][j - 1] + &pascal[i - 1][j]);
1607 }
1608 }
1609 }
1610
1611 fn test_expand_polynomial() {
1612 assert_eq!(
1613 expand_polynomial::<I, R>(&[1].map(R::from_usize), 0),
1614 [1].map(R::from_usize)
1615 );
1616 assert_eq!(
1617 expand_polynomial::<I, R>(&[1, 1].map(R::from_usize), 0),
1618 [1, 1].map(R::from_usize)
1619 );
1620 assert_eq!(
1621 expand_polynomial::<I, R>(&[1, 1, 1].map(R::from_usize), 0),
1622 [1, 2, 1].map(R::from_usize)
1623 );
1624 assert_eq!(
1625 expand_polynomial::<I, R>(&[1, 1, 1, 1].map(R::from_usize), 0),
1626 [1, 3, 3, 1].map(R::from_usize)
1627 );
1628 assert_eq!(
1629 expand_polynomial::<I, R>(&[1, 1, 1, 1, 1].map(R::from_usize), 0),
1630 [1, 4, 6, 4, 1].map(R::from_usize)
1631 );
1632 assert_eq!(
1637 expand_polynomial::<I, R>(&[1, 2, 3, 0].map(R::from_usize), 3),
1638 [1, 6, 11, 6].map(R::from_usize)
1639 );
1640 assert_eq!(
1642 expand_polynomial::<I, R>(&[1, 2, 3, 4, 5].map(R::from_usize), 0),
1643 [1, 14, 71, 154, 120].map(R::from_usize)
1644 );
1645 }
1646
1647 fn polyweight_array(keep_factors: &[R], pascal: &[Vec<I>]) -> Vec<R> {
1648 let unused_factors: Vec<_> = keep_factors.iter().map(|k| R::one() - k).collect();
1649 let count = keep_factors.len();
1650 (0..count)
1651 .map(|i| BallotCounter::<I, R>::polyweights(&unused_factors, i, &pascal[count - 1]))
1652 .collect::<Vec<_>>()
1653 }
1654
1655 fn weights(keep_factors: &[R], pascal: &[Vec<I>]) -> Vec<R> {
1656 let unused_factors: Vec<_> = keep_factors.iter().map(|k| R::one() - k).collect();
1657 let count = keep_factors.len();
1658 (0..count)
1659 .map(|i| {
1660 BallotCounter::<I, R>::polyweights(&unused_factors, i, &pascal[count - 1])
1661 * &keep_factors[i]
1662 / I::from_usize(count)
1663 })
1664 .collect::<Vec<_>>()
1665 }
1666
1667 fn test_polyweights() {
1668 let count = 3;
1669 let pascal = pascal::<I>(count);
1670
1671 let keep_factors = [1, 1, 1].map(R::from_usize);
1672 assert_eq!(
1673 Self::polyweight_array(&keep_factors, &pascal),
1674 [1, 1, 1].map(R::from_usize)
1675 );
1676 assert_eq!(
1677 Self::weights(&keep_factors, &pascal),
1678 [R::ratio(1, 3), R::ratio(1, 3), R::ratio(1, 3)]
1679 );
1680
1681 let keep_factors = [1, 0, 1].map(R::from_usize);
1682 assert_eq!(
1683 Self::polyweight_array(&keep_factors, &pascal),
1684 [R::ratio(3, 2), R::from_usize(1), R::ratio(3, 2)]
1685 );
1686 assert_eq!(
1687 Self::weights(&keep_factors, &pascal),
1688 [R::ratio(1, 2), R::from_usize(0), R::ratio(1, 2)]
1689 );
1690
1691 let keep_factors = [1, 0, 0].map(R::from_usize);
1692 assert_eq!(
1693 Self::polyweight_array(&keep_factors, &pascal),
1694 [R::from_usize(3), R::ratio(3, 2), R::ratio(3, 2)]
1695 );
1696 assert_eq!(
1697 Self::weights(&keep_factors, &pascal),
1698 [R::from_usize(1), R::from_usize(0), R::from_usize(0)]
1699 );
1700
1701 let keep_factors = [R::from_usize(1), R::ratio(1, 2), R::ratio(1, 2)];
1709 assert_eq!(
1710 Self::polyweight_array(&keep_factors, &pascal),
1711 [R::ratio(7, 4), R::ratio(5, 4), R::ratio(5, 4)]
1712 );
1713 assert_eq!(
1714 Self::weights(&keep_factors, &pascal),
1715 [R::ratio(7, 12), R::ratio(5, 24), R::ratio(5, 24)]
1716 );
1717
1718 let keep_factors = [R::ratio(1, 2), R::ratio(1, 2), R::ratio(1, 2)];
1721 assert_eq!(
1722 Self::polyweight_array(&keep_factors, &pascal),
1723 [R::ratio(7, 4), R::ratio(7, 4), R::ratio(7, 4)]
1724 );
1725 assert_eq!(
1726 Self::weights(&keep_factors, &pascal),
1727 [R::ratio(7, 24), R::ratio(7, 24), R::ratio(7, 24)]
1728 );
1729 }
1730
1731 fn bench_count_votes_serial_16(bencher: &mut Bencher) {
1732 Self::bench_count_votes(bencher, 16, Parallel::No);
1733 }
1734
1735 fn bench_count_votes_serial_32(bencher: &mut Bencher) {
1736 Self::bench_count_votes(bencher, 32, Parallel::No);
1737 }
1738
1739 fn bench_count_votes_serial_64(bencher: &mut Bencher) {
1740 Self::bench_count_votes(bencher, 64, Parallel::No);
1741 }
1742
1743 fn bench_count_votes_serial_128(bencher: &mut Bencher) {
1744 Self::bench_count_votes(bencher, 128, Parallel::No);
1745 }
1746
1747 fn bench_count_votes_parallel_16(bencher: &mut Bencher) {
1748 Self::bench_count_votes(bencher, 16, Parallel::Rayon);
1749 }
1750
1751 fn bench_count_votes_parallel_32(bencher: &mut Bencher) {
1752 Self::bench_count_votes(bencher, 32, Parallel::Rayon);
1753 }
1754
1755 fn bench_count_votes_parallel_64(bencher: &mut Bencher) {
1756 Self::bench_count_votes(bencher, 64, Parallel::Rayon);
1757 }
1758
1759 fn bench_count_votes_parallel_128(bencher: &mut Bencher) {
1760 Self::bench_count_votes(bencher, 128, Parallel::Rayon);
1761 }
1762
1763 fn bench_count_votes(bencher: &mut Bencher, n: usize, parallel: Parallel) {
1764 let ballots = Self::fake_ballots(n);
1765 let keep_factors = Self::fake_keep_factors(n);
1766 let election = Election::builder()
1767 .title("")
1768 .candidates(Self::fake_candidates(n))
1769 .num_seats(0)
1770 .ballots(ballots)
1771 .build();
1772
1773 bencher.iter(|| {
1774 VoteCount::<I, R>::count_votes(
1775 black_box(&election),
1776 black_box(&keep_factors),
1777 parallel,
1778 None,
1779 None,
1780 )
1781 });
1782 }
1783
1784 fn bench_process_ballot_rec_chain(bencher: &mut Bencher) {
1785 let ballot = Ballot::new(1, (0..10).map(|i| vec![i]));
1786 let keep_factors = Self::fake_keep_factors(10);
1787 bencher.iter(|| Self::process_ballot_rec(black_box(&ballot), black_box(&keep_factors)))
1788 }
1789
1790 fn bench_process_ballot_rec_pairs_01(bencher: &mut Bencher) {
1791 Self::bench_process_ballot_rec_pairs(bencher, 1);
1792 }
1793
1794 fn bench_process_ballot_rec_pairs_02(bencher: &mut Bencher) {
1795 Self::bench_process_ballot_rec_pairs(bencher, 2);
1796 }
1797
1798 fn bench_process_ballot_rec_pairs_03(bencher: &mut Bencher) {
1799 Self::bench_process_ballot_rec_pairs(bencher, 3);
1800 }
1801
1802 fn bench_process_ballot_rec_pairs_04(bencher: &mut Bencher) {
1803 Self::bench_process_ballot_rec_pairs(bencher, 4);
1804 }
1805
1806 fn bench_process_ballot_rec_pairs_05(bencher: &mut Bencher) {
1807 Self::bench_process_ballot_rec_pairs(bencher, 5);
1808 }
1809
1810 fn bench_process_ballot_rec_pairs_06(bencher: &mut Bencher) {
1811 Self::bench_process_ballot_rec_pairs(bencher, 6);
1812 }
1813
1814 fn bench_process_ballot_rec_pairs_07(bencher: &mut Bencher) {
1815 Self::bench_process_ballot_rec_pairs(bencher, 7);
1816 }
1817
1818 fn bench_process_ballot_rec_pairs_08(bencher: &mut Bencher) {
1819 Self::bench_process_ballot_rec_pairs(bencher, 8);
1820 }
1821
1822 fn bench_process_ballot_rec_pairs_09(bencher: &mut Bencher) {
1823 Self::bench_process_ballot_rec_pairs(bencher, 9);
1824 }
1825
1826 fn bench_process_ballot_rec_pairs_10(bencher: &mut Bencher) {
1827 Self::bench_process_ballot_rec_pairs(bencher, 10);
1828 }
1829
1830 fn bench_process_ballot_rec_pairs(bencher: &mut Bencher, layers: usize) {
1831 let n = layers * 2;
1832 let ballot = Ballot::new(1, (0..n).array_chunks::<2>());
1833 let keep_factors = Self::fake_keep_factors(n);
1834 bencher.iter(|| Self::process_ballot_rec(black_box(&ballot), black_box(&keep_factors)))
1835 }
1836
1837 fn bench_process_ballot_rec_tens_1(bencher: &mut Bencher) {
1838 Self::bench_process_ballot_rec_tens(bencher, 1);
1839 }
1840
1841 fn bench_process_ballot_rec_tens_2(bencher: &mut Bencher) {
1842 Self::bench_process_ballot_rec_tens(bencher, 2);
1843 }
1844
1845 fn bench_process_ballot_rec_tens_3(bencher: &mut Bencher) {
1846 Self::bench_process_ballot_rec_tens(bencher, 3);
1847 }
1848
1849 fn bench_process_ballot_rec_tens_4(bencher: &mut Bencher) {
1850 Self::bench_process_ballot_rec_tens(bencher, 4);
1851 }
1852
1853 fn bench_process_ballot_rec_tens(bencher: &mut Bencher, layers: usize) {
1854 let n = layers * 10;
1855 let ballot = Ballot::new(1, (0..n).array_chunks::<10>());
1856 let keep_factors = Self::fake_keep_factors(n);
1857 bencher.iter(|| Self::process_ballot_rec(black_box(&ballot), black_box(&keep_factors)))
1858 }
1859
1860 fn bench_process_ballot_equalize_chain(bencher: &mut Bencher) {
1861 let pascal = pascal::<I>(10);
1862 let ballot = Ballot::new(1, (0..10).map(|i| vec![i]));
1863 let keep_factors = Self::fake_keep_factors(10);
1864 bencher.iter(|| {
1865 Self::process_ballot_equalize(black_box(&ballot), black_box(&keep_factors), &pascal)
1866 })
1867 }
1868
1869 fn bench_process_ballot_equalize_pairs_01(bencher: &mut Bencher) {
1870 Self::bench_process_ballot_equalize_pairs(bencher, 1);
1871 }
1872
1873 fn bench_process_ballot_equalize_pairs_02(bencher: &mut Bencher) {
1874 Self::bench_process_ballot_equalize_pairs(bencher, 2);
1875 }
1876
1877 fn bench_process_ballot_equalize_pairs_03(bencher: &mut Bencher) {
1878 Self::bench_process_ballot_equalize_pairs(bencher, 3);
1879 }
1880
1881 fn bench_process_ballot_equalize_pairs_04(bencher: &mut Bencher) {
1882 Self::bench_process_ballot_equalize_pairs(bencher, 4);
1883 }
1884
1885 fn bench_process_ballot_equalize_pairs_05(bencher: &mut Bencher) {
1886 Self::bench_process_ballot_equalize_pairs(bencher, 5);
1887 }
1888
1889 fn bench_process_ballot_equalize_pairs_06(bencher: &mut Bencher) {
1890 Self::bench_process_ballot_equalize_pairs(bencher, 6);
1891 }
1892
1893 fn bench_process_ballot_equalize_pairs_07(bencher: &mut Bencher) {
1894 Self::bench_process_ballot_equalize_pairs(bencher, 7);
1895 }
1896
1897 fn bench_process_ballot_equalize_pairs_08(bencher: &mut Bencher) {
1898 Self::bench_process_ballot_equalize_pairs(bencher, 8);
1899 }
1900
1901 fn bench_process_ballot_equalize_pairs_09(bencher: &mut Bencher) {
1902 Self::bench_process_ballot_equalize_pairs(bencher, 9);
1903 }
1904
1905 fn bench_process_ballot_equalize_pairs_10(bencher: &mut Bencher) {
1906 Self::bench_process_ballot_equalize_pairs(bencher, 10);
1907 }
1908
1909 fn bench_process_ballot_equalize_pairs_15(bencher: &mut Bencher) {
1910 Self::bench_process_ballot_equalize_pairs(bencher, 15);
1911 }
1912
1913 fn bench_process_ballot_equalize_pairs(bencher: &mut Bencher, layers: usize) {
1914 let n = layers * 2;
1915 let pascal = pascal::<I>(n);
1916 let ballot = Ballot::new(1, (0..n).array_chunks::<2>());
1917 let keep_factors = Self::fake_keep_factors(n);
1918 bencher.iter(|| {
1919 Self::process_ballot_equalize(black_box(&ballot), black_box(&keep_factors), &pascal)
1920 })
1921 }
1922
1923 fn bench_process_ballot_equalize_tens_1(bencher: &mut Bencher) {
1924 Self::bench_process_ballot_equalize_tens(bencher, 1);
1925 }
1926
1927 fn bench_process_ballot_equalize_tens_2(bencher: &mut Bencher) {
1928 Self::bench_process_ballot_equalize_tens(bencher, 2);
1929 }
1930
1931 fn bench_process_ballot_equalize_tens_3(bencher: &mut Bencher) {
1932 Self::bench_process_ballot_equalize_tens(bencher, 3);
1933 }
1934
1935 fn bench_process_ballot_equalize_tens_4(bencher: &mut Bencher) {
1936 Self::bench_process_ballot_equalize_tens(bencher, 4);
1937 }
1938
1939 fn bench_process_ballot_equalize_tens(bencher: &mut Bencher, layers: usize) {
1940 let n = layers * 10;
1941 let pascal = pascal::<I>(n);
1942 let ballot = Ballot::new(1, (0..n).array_chunks::<10>());
1943 let keep_factors = Self::fake_keep_factors(n);
1944 bencher.iter(|| {
1945 Self::process_ballot_equalize(black_box(&ballot), black_box(&keep_factors), &pascal)
1946 })
1947 }
1948 }
1949}