criterion/stats/univariate/
mod.rs

1//! Univariate analysis
2
3mod bootstrap;
4mod percentiles;
5mod resamples;
6mod sample;
7
8pub mod kde;
9pub mod mixed;
10pub mod outliers;
11
12use crate::stats::float::Float;
13use crate::stats::tuple::{Tuple, TupledDistributionsBuilder};
14#[cfg(feature = "rayon")]
15use rayon::prelude::*;
16use std::cmp;
17
18use self::resamples::Resamples;
19
20pub use self::percentiles::Percentiles;
21pub use self::sample::Sample;
22
23/// Performs a two-sample bootstrap
24///
25/// - Multithreaded
26/// - Time: `O(nresamples)`
27/// - Memory: `O(nresamples)`
28#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
29pub fn bootstrap<A, B, T, S>(
30    a: &Sample<A>,
31    b: &Sample<B>,
32    nresamples: usize,
33    statistic: S,
34) -> T::Distributions
35where
36    A: Float,
37    B: Float,
38    S: Fn(&Sample<A>, &Sample<B>) -> T + Sync,
39    T: Tuple + Send,
40    T::Distributions: Send,
41    T::Builder: Send,
42{
43    let nresamples_sqrt = (nresamples as f64).sqrt().ceil() as usize;
44    let per_chunk = (nresamples + nresamples_sqrt - 1) / nresamples_sqrt;
45
46    #[cfg(feature = "rayon")]
47    {
48        (0..nresamples_sqrt)
49            .into_par_iter()
50            .map_init(
51                || (Resamples::new(a), Resamples::new(b)),
52                |(a_resamples, b_resamples), i| {
53                    let start = i * per_chunk;
54                    let end = cmp::min((i + 1) * per_chunk, nresamples);
55                    let a_resample = a_resamples.next();
56
57                    let mut sub_distributions: T::Builder =
58                        TupledDistributionsBuilder::new(end - start);
59
60                    for _ in start..end {
61                        let b_resample = b_resamples.next();
62                        sub_distributions.push(statistic(a_resample, b_resample));
63                    }
64                    sub_distributions
65                },
66            )
67            .reduce(
68                || T::Builder::new(0),
69                |mut a, mut b| {
70                    a.extend(&mut b);
71                    a
72                },
73            )
74            .complete()
75    }
76    #[cfg(not(feature = "rayon"))]
77    {
78        let mut a_resamples = Resamples::new(a);
79        let mut b_resamples = Resamples::new(b);
80        (0..nresamples_sqrt)
81            .map(|i| {
82                let start = i * per_chunk;
83                let end = cmp::min((i + 1) * per_chunk, nresamples);
84                let a_resample = a_resamples.next();
85
86                let mut sub_distributions: T::Builder =
87                    TupledDistributionsBuilder::new(end - start);
88
89                for _ in start..end {
90                    let b_resample = b_resamples.next();
91                    sub_distributions.push(statistic(a_resample, b_resample));
92                }
93                sub_distributions
94            })
95            .fold(T::Builder::new(0), |mut a, mut b| {
96                a.extend(&mut b);
97                a
98            })
99            .complete()
100    }
101}