blob: d6b845d1ba82ab33ff2058c27ee16fa182642aad [file] [log] [blame]
//! Mixed bootstrap
use crate::stats::float::Float;
use crate::stats::tuple::{Tuple, TupledDistributionsBuilder};
use crate::stats::univariate::Resamples;
use crate::stats::univariate::Sample;
#[cfg(feature = "rayon")]
use rayon::prelude::*;
/// Performs a *mixed* two-sample bootstrap
pub fn bootstrap<A, T, S>(
a: &Sample<A>,
b: &Sample<A>,
nresamples: usize,
statistic: S,
) -> T::Distributions
where
A: Float,
S: Fn(&Sample<A>, &Sample<A>) -> T + Sync,
T: Tuple + Send,
T::Distributions: Send,
T::Builder: Send,
{
let n_a = a.len();
let n_b = b.len();
let mut c = Vec::with_capacity(n_a + n_b);
c.extend_from_slice(a);
c.extend_from_slice(b);
let c = Sample::new(&c);
#[cfg(feature = "rayon")]
{
(0..nresamples)
.into_par_iter()
.map_init(
|| Resamples::new(c),
|resamples, _| {
let resample = resamples.next();
let a: &Sample<A> = Sample::new(&resample[..n_a]);
let b: &Sample<A> = Sample::new(&resample[n_a..]);
statistic(a, b)
},
)
.fold(
|| T::Builder::new(0),
|mut sub_distributions, sample| {
sub_distributions.push(sample);
sub_distributions
},
)
.reduce(
|| T::Builder::new(0),
|mut a, mut b| {
a.extend(&mut b);
a
},
)
.complete()
}
#[cfg(not(feature = "rayon"))]
{
let mut resamples = Resamples::new(c);
(0..nresamples)
.map(|_| {
let resample = resamples.next();
let a: &Sample<A> = Sample::new(&resample[..n_a]);
let b: &Sample<A> = Sample::new(&resample[n_a..]);
statistic(a, b)
})
.fold(T::Builder::new(0), |mut sub_distributions, sample| {
sub_distributions.push(sample);
sub_distributions
})
.complete()
}
}