stv_rs/
vote_count.rs

1// Copyright 2023 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Module to count votes, based on input ballots and the current keep factor
16//! values.
17
18use 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/// Result of a vote count.
32#[cfg_attr(test, derive(Debug, PartialEq))]
33pub struct VoteCount<I, R> {
34    /// Sum of votes for each candidate.
35    pub sum: Vec<R>,
36    /// Exhausted voting power.
37    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 of votes for each candidate.
58    sum: Vec<R>,
59    /// Exhausted voting power.
60    exhausted: R,
61    /// Number of function calls performed.
62    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
102/// A thread pool tied to a scope, that can perform vote counting rounds.
103pub struct VoteCountingThreadPool<'scope, I, R> {
104    /// Inner thread pool.
105    pool: ThreadPool<'scope, VoteAccumulator<I, R>>,
106    /// Storage for the keep factors, used as input of the current round by the
107    /// worker threads.
108    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    /// Creates a new pool tied to the given scope, with the given number of
119    /// threads and references to the necessary election inputs.
120    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    /// Accumulates votes from the election ballots based on the given keep
145    /// factors.
146    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
160/// Helper state to accumulate votes in a worker thread.
161struct ThreadVoteCounter<'env, I, R> {
162    /// Number of candidates in the election.
163    num_candidates: usize,
164    /// Pre-computed Pascal triangle.
165    pascal: Option<&'env [Vec<I>]>,
166    /// Keep factors used in the current round.
167    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    /// Counts the votes, based on the given keep factors.
220    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    /// Parallel implementation of vote counting, leveraging all CPU cores to
252    /// speed up the computation.
253    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    /// Writes statistics about this vote count to the given output.
284    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    /// Serial implementation of vote counting, using only one CPU core.
300    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    /// Processes a ballot and adds its votes to the accumulator.
313    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    /// Computes the new threshold, based on the election parameters and the
353    /// exhausted votes after this count.
354    pub fn threshold(&self, election: &Election) -> R {
355        Self::threshold_exhausted(election, &self.exhausted)
356    }
357
358    /// Computes the current surplus, based on the votes, the threshold and the
359    /// currently elected candidates, in a manner compatible with Droop.py. This
360    /// is the sum of the differences between the received vote count and
361    /// the required threshold, across all elected candidates.
362    ///
363    /// Note: Normally we'd only add positive surpluses here, but sometimes an
364    /// already elected candidate goes below the threshold. In this case,
365    /// Droop.py just sums the difference for the elected candidates, which
366    /// can lead to crashes. See the [`Self::surplus_positive()`] function which
367    /// fixes this behavior.
368    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    /// Computes the current surplus, based on the votes, the threshold and the
384    /// currently elected candidates. This is the sum of the differences between
385    /// the received vote count and the required threshold, across all
386    /// elected candidates.
387    ///
388    /// Note: Normally we'd only add positive surpluses here, but sometimes an
389    /// already elected candidate goes below the threshold. In this case, this
390    /// function counts a positive surplus for this candidate. See the
391    /// [`Self::surplus_droop()`] function for Droop.py's behavior.
392    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    /// Computes the new threshold, based on the given election parameters and
410    /// exhausted votes.
411    ///
412    /// This is the ratio between the effectively used voting power (i.e.
413    /// subtracted from any exhausted voting power) and the number of elected
414    /// seats plus one.
415    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 to count.
433    ballot: &'a Ballot,
434    /// Candidates' attributed votes.
435    sum: &'a mut [R],
436    /// Voting power that was not used (due to rounding and/or voting power not
437    /// kept by any candidate in the ballot).
438    unused_power: &'a mut R,
439    /// Candidates' keep factors.
440    keep_factors: &'a [R],
441    /// Number of functions called to count this ballot (due to recursion).
442    fn_calls: &'a mut usize,
443    /// Pre-computed Pascal triangle. Set only if the "equalized counting" is
444    /// enabled.
445    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    /// Processes a ballot, using a recursive method (consistent with Droop.py)
457    /// to count ballots that contain candidates ranked equally.
458    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    /// Processes a ballot which contains a strict order of candidates (no tie),
469    /// in a manner consistent with Droop.py.
470    ///
471    /// This is a straightforward application of
472    /// [Meek's rules](https://en.wikipedia.org/wiki/Counting_single_transferable_votes#Meek):
473    /// each candidate in the ballot retains its own keep factor share of the
474    /// voting power, and passes the rest to the next candidate, until no voting
475    /// power is left (i.e. a candidate has a keep factor of 1), or the whole
476    /// ballot was used.
477    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            // Only one candidate at this level. Easy case.
482            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    /// Processes a ballot which contains at least a tie, in a manner consistent
494    /// with [Droop.py](https://github.com/jklundell/droop). There are two
495    /// remarks to make about this method.
496    ///
497    /// First, if a ranking among the ballot only contains defeated candidates,
498    /// then the remaining power is not distributed any further, which is
499    /// contrary to Meek's method (a defeated candidate should pass all of its
500    /// voting power to the next candidate).
501    ///
502    /// For example, with the ballot `a b c=d`, if `a` is defeated then no
503    /// voting power will be distributed to `b`, `c` nor `d`. On the contrary,
504    /// the ballot `a b c` would get voting power distributed to `b` if `a`
505    /// was defeated (via [`Self::process_ballot_rec_notie()`]).
506    ///
507    /// Second, if multiple candidates are ranked equally, the voting power is
508    /// first split evenly between them. But if any of those has a keep factor
509    /// lower than 1, then the remaining voting power is not contributed back to
510    /// any of these tied candidates - it is instead distributed to candidates
511    /// ranked afterwards.
512    ///
513    /// This means that with the ballot `a=b c`, if `a` is elected with a keep
514    /// factor k, then `a` will receive `0.5 * k`, `b` will receive `0.5`, and
515    /// `c` will receive `0.5 * (1 - k)`. This is contrary to what one would
516    /// expect: `c` should only receive voting power from this ballot if
517    /// both `a` and `b` are already elected.
518    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        // Fetch the i-th ranking in the ballot, which may contain multiple tied
525        // candidates.
526        let ranking = self.ballot.order_at(i);
527
528        // TODO: skip defeated candidates according to their status.
529        // Number of eligible candidates (with a positive keep factor) in the current
530        // ranking.
531        let filtered_ranking_len = ranking
532            .iter()
533            .filter(|&&candidate| !self.keep_factors[candidate.into()].is_zero())
534            .count();
535        // If all the candidates are defeated in the current ranking, the original
536        // implementation (from Droop.py) doesn't distribute votes any further!
537        if filtered_ranking_len == 0 {
538            return;
539        }
540
541        // Multiple candidates ranked equally. The original implementation (from
542        // Droop.py) starts by splitting the voting power evenly to all these
543        // candidates. If any of those has a non-one keep factor (i.e. is already
544        // elected), then the remaining power (for that candidate) is distributed via
545        // recursion to the next ranking in the ballot, rather than being distributed
546        // back to any other candidate in the same ranking.
547        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    /// Processes a ballot which contains at least a tie, according to the
566    /// following "equalized counting" rules.
567    ///
568    /// In this mode, candidates ranked equally are counted by simulating a
569    /// superposition of all possible permutations of these equally-ranked
570    /// candidates.
571    ///
572    /// For example, the ballot `a b=c` becomes a superposition of `a b c` (with
573    /// weight 1/2) and `a c b` (with weight 1/2). Likewise, the ballot `a
574    /// b=c=d` is counted as a superposition of 6 ballots, each with weight
575    /// 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
576    /// b`.
577    fn process_ballot_equalize(mut self) {
578        // Note: we separate the voting power and the number of occurrences of each
579        // ballot, and multiply by the ballot count only at the end, so that in
580        // order to ensure fairness a repeated ballot is really counted as the sum
581        // of `b.count` identical ballots.
582        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                // Only one candidate at this level. Easy case.
590                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                // Multiple candidates ranked equally. Finer computation.
597                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                // For each candidate, the unused factor is one minus the keep factor (whatever
606                // is not kept).
607                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                // Conservatively, the remaining voting power passed to the next ranking in the
624                // ballot is the product of the unused factors (rounded down). Like for
625                // splitting the voting power for one candidate, we cannot simply let the
626                // remaining power being 1 minus the used power, because that would round up the
627                // remaining power and potentially giving more votes to candidates further in
628                // the ballot.
629                // TODO: Multiplication is not associative for all arithmetic backends!
630                // Calculate this product in a deterministic and fair way.
631                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    /// Increments the votes attributed to a candidate.
641    ///
642    /// Note: we separate the voting power and the number of occurrences of each
643    /// ballot, and multiply by the ballot count only at the end, so that in
644    /// order to ensure fairness a repeated ballot is really counted as the sum
645    /// of `ballot_count` identical ballots.
646    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    /// Splits the input voting power for a candidate into the used power and
653    /// the remaining power, according to the candidate's keep factor.
654    fn split_power_one_candidate(&self, voting_power: &R, candidate: usize) -> (R, R) {
655        let keep_factor = &self.keep_factors[candidate];
656        // The candidate uses only a fraction k of the voting power, equal to its keep
657        // factor.
658        let used_power = voting_power * keep_factor;
659        // The remaining voting power cannot be larger than a `(1 - k)` fraction of the
660        // original voting power. Due to the potential rounding when computing the
661        // multiplication `power * k`, the remaining power needs to be explicilty
662        // computed as `power * (1 - k)`, rather than `power - used_power`.
663        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            // Note: This assertion can fail when using f64.
674            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    /// Helper function to calculate the voting power kept by a candidate in an
689    /// equal ranking, according to the "equalized couting" rules.
690    ///
691    /// Parameters:
692    /// - `ranking_unused_factors`: unused factors of the candidates in the
693    ///   equal ranking (for each candidate, the unused factor is 1 minus the
694    ///   keep factor).
695    /// - `skip`: index of the candidate for which the weight is calculated by
696    ///   this function.
697    /// - `pascal_row`: row of Pascal's triangle with `n` elements, where `n` is
698    ///   the length of the `ranking_unused_factors` array.
699    #[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/// Computes the coefficients of the polynomial `(X + a)*(X + b)*...*(X +
713/// z)`, where `a`, `b`, ..., `z` are the input `coefficients` excluding the
714/// one at index `skip`.
715///
716/// The output poynomial is represented with the most-significant coefficient
717/// first, i.e. the entry at index `i` in the output array represents the
718/// coefficient of degree `n - i`. In other words, the output array `p`
719/// represents the polynomial `p[0]*X^n + p[1]*X^n-1 + ... + p[n-1]*X + p[n]`.
720///
721/// Warning: even though all the input coefficients should in principle play a
722/// symmetric role (except the skipped one), in practice the output will depend
723/// on the order of the input coefficients, if multiplication in [`R`] is not
724/// associative (e.g. due to rounding). For example, the last output coefficient
725/// `p[n]` is computed as `a * b * ... * z` (in this order), so re-ordering `(a,
726/// b, ..., z)` can lead to a different result in case of non-associativity.
727#[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    // One coefficient is excluded, so the degree `n` of the output polynomial is
736    // one less of that.
737    let n = coefficients.len() - 1;
738    // For a polynomial of degree `n`, there are `n + 1` coefficients.
739    let mut poly = vec![R::zero(); n + 1];
740    // We start the computation with a polynomial equal to 1.
741    poly[0] = R::one();
742
743    // Each iteration of the loop multiplies the current polynomial by (X + a),
744    // given the coefficient a.
745    for (i, a) in coefficients.iter().enumerate() {
746        if i == skip {
747            continue;
748        }
749
750        // Optimization: do nothing if a coefficient is zero.
751        if !a.is_zero() {
752            // We start from `P = p[0] X^k + p[1] X^k-1 + ... + p[k]` and want to compute
753            // `Q = P * (X + a)`. The resulting coefficients are given by:
754            //
755            // ```
756            //    p[0] X^k+1 +   p[1] X^k + ... +     p[k] X
757            // +               a*p[0] X^k + ... + a*p[k-1] X + a*p[k]
758            // ------------------------------------------------------
759            // =  q[0] X^k+1 +   q[1] X^k + ... +     q[k] X + q[k+1]
760            // ```
761            //
762            // In other words, for each entry q[j], we take p[j], and add to it p[j-1] * a.
763            // We do that in one pass with a simple loop.
764            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
776/// Computes rows `0..=n` of
777/// [Pascal's triangle](https://en.wikipedia.org/wiki/Pascal%27s_triangle),
778/// defined by the relation `pascal[n][k] = pascal[n-1][k-1] + pascal[n-1][k]`.
779pub 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                    /* threshold = */ &R::from_usize(123),
1003                    /* surplus = */ &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                            /* exhausted = */ &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                            /* exhausted = */ &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        // First candidate takes it all.
1291        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            // Recursive method.
1297            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            // Equalized counting method.
1303            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        // Chain of keep factors.
1310        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            // Recursive method.
1316            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            // Equalized counting method.
1322            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        // Defeated candidate (keep factor is zero).
1329        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            // Recursive method.
1335            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            // Equalized counting method.
1341            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        // Tie to start the ballot.
1348        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                /* keep_factors = */ &[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        // Tie with chaining.
1360        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                /* keep_factors = */ &[R::ratio(1, 2), R::ratio(2, 3), R::ratio(3, 4)],
1364            );
1365
1366            // The last candidate gets 0.5 * (1/2 + 1/3) * 3/4 = 5/6 * 3/8 = 5/16
1367            assert_eq!(sum, vec![R::ratio(1, 4), R::ratio(1, 3), R::ratio(5, 16)]);
1368            // 5/48.
1369            assert_eq!(unused_power, R::one() - R::ratio(43, 48));
1370            assert_eq!(fn_calls, 5);
1371        }
1372
1373        // Tie with defeated candidate.
1374        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                /* keep_factors = */ &[R::zero(), R::ratio(2, 3), R::ratio(3, 4)],
1378            );
1379
1380            // No candidate gets anything (Droop.py's behavior)!
1381            assert_eq!(sum, vec![R::zero(); 3]);
1382            assert_eq!(unused_power, R::one());
1383            assert_eq!(fn_calls, 1);
1384        }
1385
1386        // Chain of multiple ties.
1387        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                /* keep_factors = */
1391                &[
1392                    R::ratio(1, 2),
1393                    R::ratio(2, 3),
1394                    R::ratio(3, 4),
1395                    R::ratio(4, 5),
1396                ],
1397            );
1398
1399            // Candidates ranked second share 0.5 * (1/2 + 1/3) = 5/12.
1400            assert_eq!(
1401                sum,
1402                vec![
1403                    R::ratio(1, 4),
1404                    R::ratio(1, 3),
1405                    // 0.5 * 5/12 * 3/4 = 5/32
1406                    R::ratio(5, 24) * R::ratio(3, 4),
1407                    // 0.5 * 5/12 * 4/5 = 1/6
1408                    R::ratio(1, 6),
1409                ]
1410            );
1411            // Remaining voting power is 0.5 * (1/4 + 1/5) * 5/12 = 9/40 * 5/12 = 3/32.
1412            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                        // Count the ballot once with a multiplier of ballot_count.
1445                        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                        // Count the ballot ballot_count times with a multiplier of one each time.
1459                        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                        // Check that both match.
1475                        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                    // Increment the candidate once with a multiplier of ballot_count.
1489                    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                    // Increment the candidate ballot_count times, with a multiplier of one each
1510                    // time.
1511                    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                    // Check that something was incremented.
1534                    assert_ne!(left_sum[0], R::zero());
1535                    assert_ne!(left_unused_power, R::zero());
1536
1537                    // Check that both match.
1538                    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            // (x + 1)(x + 2)(x + 3)
1633            // = (x^2 + 3x + 2)(x + 3)
1634            // = x^3 + 3x^2 + 2x + 3x^2 + 9x + 6
1635            // = x^3 + 6x^2 + 11x + 6
1636            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            // (x + 2)(x + 3)(x + 4)(x + 5)
1641            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            // ABC + ACB => [1/3, 0, 0]
1702            // BAC => [1/12, 1/12, 0]
1703            // CAB => [1/12, 0, 1/12]
1704            // BCA => [1/24, 1/12, 1/24]
1705            // CBA => [1/24, 1/24, 1/12]
1706            // =====
1707            // Total = [7/12, 5/24, 5/24]
1708            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            // 1/8th of each vote is forwarded to the next rank.
1719            // The kept 7/8th are split in 3.
1720            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}