extern crate rand;
use self::rand::{thread_rng, ThreadRng, Rng};
pub struct RandomChoice<RNG: Rng> {
rng: RNG,
}
pub fn random_choice() -> RandomChoice<ThreadRng> {
RandomChoice::new(thread_rng())
}
impl<RNG: Rng> RandomChoice<RNG> {
pub fn new(rng: RNG) -> Self {
RandomChoice { rng: rng }
}
pub fn random_choice_f64<'a, T>(&mut self,
samples: &'a [T],
weights: &[f64],
n: usize)
-> Vec<&'a T> {
if weights.len() == 0 || n == 0 {
return Vec::new();
}
let sum: f64 = weights.iter().fold(0.0, |acc, &i| acc + i);
let spoke_gap: f64 = sum / n as f64;
let spin = self.rng.next_f64() * spoke_gap;
let mut i: usize = 0;
let mut accumulated_weights = weights[0];
let mut choices: Vec<&T> = Vec::with_capacity(n);
let mut current_spoke: f64 = spin;
while current_spoke < sum {
while accumulated_weights < current_spoke {
i += 1;
accumulated_weights += weights[i];
}
choices.push(&samples[i]);
current_spoke += spoke_gap;
}
while choices.len() < weights.len() {
choices.push(&samples[i]);
}
choices
}
pub fn random_choice_in_place_f64<T: Clone>(&mut self, samples: &mut [T], weights: &[f64]) {
if weights.len() < 2 {
return;
}
let sum: f64 = weights.iter().fold(0.0, |acc, &i| acc + i);
let n: usize = weights.len();
let spoke_gap: f64 = sum / n as f64;
let spin = self.rng.next_f64() * spoke_gap;
let mut i: usize = 0;
let mut j: usize = 0;
let mut accumulated_weights = weights[0];
let mut current_spoke: f64 = spin;
while current_spoke < sum {
while accumulated_weights < current_spoke {
j += 1;
accumulated_weights += weights[j];
}
samples[i] = samples[j].clone();
current_spoke += spoke_gap;
i += 1
}
while i < weights.len() {
samples[i] = samples[j].clone();
i += 1
}
}
pub fn random_choice_f32<'a, T>(&mut self,
samples: &'a [T],
weights: &[f32],
n: usize)
-> Vec<&'a T> {
if weights.len() == 0 || n == 0 {
return Vec::new();
}
let sum: f64 = weights.iter().fold(0.0, |acc, &i| acc + i as f64);
let spoke_gap: f64 = sum / n as f64;
let spin = self.rng.next_f64() * spoke_gap;
let mut i: usize = 0;
let mut accumulated_weights = weights[0] as f64;
let mut choices: Vec<&T> = Vec::with_capacity(n);
let mut current_spoke: f64 = spin;
while current_spoke < sum {
while accumulated_weights < current_spoke {
i += 1;
accumulated_weights += weights[i] as f64;
}
choices.push(&samples[i]);
current_spoke += spoke_gap;
}
while choices.len() < weights.len() {
choices.push(&samples[i]);
}
choices
}
pub fn random_choice_in_place_f32<T: Clone>(&mut self, samples: &mut [T], weights: &[f32]) {
if weights.len() < 2 {
return;
}
let sum: f64 = weights.iter().fold(0.0, |acc, &i| acc + i as f64);
let n: usize = weights.len();
let spoke_gap: f64 = sum / n as f64;
let spin = self.rng.next_f64() * spoke_gap;
let mut i: usize = 0;
let mut j: usize = 0;
let mut accumulated_weights = weights[0] as f64;
let mut current_spoke: f64 = spin;
while current_spoke < sum {
while accumulated_weights < current_spoke {
j += 1;
accumulated_weights += weights[j] as f64;
}
samples[i] = samples[j].clone();
current_spoke += spoke_gap;
i += 1
}
while i < weights.len() {
samples[i] = samples[j].clone();
i += 1
}
}
}