blob: 923669d594389b4fe8c05f398396928b0663bbd2 [file] [log] [blame]
use std::mem;
use crate::stats::float::Float;
use crate::stats::rand_util::{new_rng, Rng};
use crate::stats::univariate::Sample;
pub struct Resamples<'a, A>
where
A: Float,
{
rng: Rng,
sample: &'a [A],
stage: Option<Vec<A>>,
}
#[cfg_attr(feature = "cargo-clippy", allow(clippy::should_implement_trait))]
impl<'a, A> Resamples<'a, A>
where
A: 'a + Float,
{
pub fn new(sample: &'a Sample<A>) -> Resamples<'a, A> {
let slice = sample;
Resamples {
rng: new_rng(),
sample: slice,
stage: None,
}
}
pub fn next(&mut self) -> &Sample<A> {
let n = self.sample.len();
let rng = &mut self.rng;
match self.stage {
None => {
let mut stage = Vec::with_capacity(n);
for _ in 0..n {
let idx = rng.rand_range(0u64..(self.sample.len() as u64));
stage.push(self.sample[idx as usize])
}
self.stage = Some(stage);
}
Some(ref mut stage) => {
for elem in stage.iter_mut() {
let idx = rng.rand_range(0u64..(self.sample.len() as u64));
*elem = self.sample[idx as usize]
}
}
}
if let Some(ref v) = self.stage {
unsafe { mem::transmute::<&[_], _>(v) }
} else {
unreachable!();
}
}
}
#[cfg(test)]
mod test {
use quickcheck::quickcheck;
use quickcheck::TestResult;
use std::collections::HashSet;
use crate::stats::univariate::resamples::Resamples;
use crate::stats::univariate::Sample;
// Check that the resample is a subset of the sample
quickcheck! {
fn subset(size: u8, nresamples: u8) -> TestResult {
let size = size as usize;
let nresamples = nresamples as usize;
if size > 1 {
let v: Vec<_> = (0..size).map(|i| i as f32).collect();
let sample = Sample::new(&v);
let mut resamples = Resamples::new(sample);
let sample = v.iter().map(|&x| x as i64).collect::<HashSet<_>>();
TestResult::from_bool((0..nresamples).all(|_| {
let resample = resamples.next()
.iter()
.map(|&x| x as i64)
.collect::<HashSet<_>>();
resample.is_subset(&sample)
}))
} else {
TestResult::discard()
}
}
}
#[test]
fn different_subsets() {
let size = 1000;
let v: Vec<_> = (0..size).map(|i| i as f32).collect();
let sample = Sample::new(&v);
let mut resamples = Resamples::new(sample);
// Hypothetically, we might see one duplicate, but more than one is likely to be a bug.
let mut num_duplicated = 0;
for _ in 0..1000 {
let sample_1 = resamples.next().iter().cloned().collect::<Vec<_>>();
let sample_2 = resamples.next().iter().cloned().collect::<Vec<_>>();
if sample_1 == sample_2 {
num_duplicated += 1;
}
}
if num_duplicated > 1 {
panic!("Found {} duplicate samples", num_duplicated);
}
}
}