1 //! Univariate analysis
2
3 mod bootstrap;
4 mod percentiles;
5 mod resamples;
6 mod sample;
7
8 pub mod kde;
9 pub mod mixed;
10 pub mod outliers;
11
12 use crate::stats::float::Float;
13 use crate::stats::tuple::{Tuple, TupledDistributionsBuilder};
14 #[cfg(feature = "rayon")]
15 use rayon::prelude::*;
16 use std::cmp;
17
18 use self::resamples::Resamples;
19
20 pub use self::percentiles::Percentiles;
21 pub 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))]
bootstrap<A, B, T, S>( a: &Sample<A>, b: &Sample<B>, nresamples: usize, statistic: S, ) -> T::Distributions where A: Float, B: Float, S: Fn(&Sample<A>, &Sample<B>) -> T + Sync, T: Tuple + Send, T::Distributions: Send, T::Builder: Send,29 pub fn bootstrap<A, B, T, S>(
30 a: &Sample<A>,
31 b: &Sample<B>,
32 nresamples: usize,
33 statistic: S,
34 ) -> T::Distributions
35 where
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 }
102