1//! Mixed bootstrap
2
3use crate::stats::float::Float;
4use crate::stats::tuple::{Tuple, TupledDistributionsBuilder};
5use crate::stats::univariate::Resamples;
6use crate::stats::univariate::Sample;
7#[cfg(feature = "rayon")]
8use rayon::prelude::*;
9
10/// Performs a *mixed* two-sample bootstrap
11pub fn bootstrap<A, T, S>(
12 a: &Sample<A>,
13 b: &Sample<A>,
14 nresamples: usize,
15 statistic: S,
16) -> T::Distributions
17where
18 A: Float,
19 S: Fn(&Sample<A>, &Sample<A>) -> T + Sync,
20 T: Tuple + Send,
21 T::Distributions: Send,
22 T::Builder: Send,
23{
24 let n_a = a.len();
25 let n_b = b.len();
26 let mut c = Vec::with_capacity(n_a + n_b);
27 c.extend_from_slice(a);
28 c.extend_from_slice(b);
29 let c = Sample::new(&c);
30
31 #[cfg(feature = "rayon")]
32 {
33 (0..nresamples)
34 .into_par_iter()
35 .map_init(
36 || Resamples::new(c),
37 |resamples, _| {
38 let resample = resamples.next();
39 let a: &Sample<A> = Sample::new(&resample[..n_a]);
40 let b: &Sample<A> = Sample::new(&resample[n_a..]);
41
42 statistic(a, b)
43 },
44 )
45 .fold(
46 || T::Builder::new(0),
47 |mut sub_distributions, sample| {
48 sub_distributions.push(sample);
49 sub_distributions
50 },
51 )
52 .reduce(
53 || T::Builder::new(0),
54 |mut a, mut b| {
55 a.extend(&mut b);
56 a
57 },
58 )
59 .complete()
60 }
61 #[cfg(not(feature = "rayon"))]
62 {
63 let mut resamples = Resamples::new(c);
64 (0..nresamples)
65 .map(|_| {
66 let resample = resamples.next();
67 let a: &Sample<A> = Sample::new(&resample[..n_a]);
68 let b: &Sample<A> = Sample::new(&resample[n_a..]);
69
70 statistic(a, b)
71 })
72 .fold(T::Builder::new(0), |mut sub_distributions, sample| {
73 sub_distributions.push(sample);
74 sub_distributions
75 })
76 .complete()
77 }
78}
79