extern crate rand;
use std::convert::From;
use std::default::Default;
use std::iter::FromIterator;
use std::iter::repeat;
use std::collections::VecDeque;
use self::rand::Rng;
pub struct RouletteWheel<T> {
proba_sum: f32,
cards: VecDeque<(f32, T)>
}
impl<T: Clone> Clone for RouletteWheel<T> {
fn clone(&self) -> RouletteWheel<T> {
RouletteWheel {
proba_sum: self.proba_sum,
cards: self.cards.clone()
}
}
}
impl<T> Default for RouletteWheel<T> {
fn default() -> Self {
Self::new()
}
}
impl<'a, T: Clone> From<&'a [T]> for RouletteWheel<T> {
fn from(s: &'a [T]) -> RouletteWheel<T> {
RouletteWheel {
proba_sum: s.len() as f32,
cards: VecDeque::from_iter(repeat(1.0).zip(s.iter().cloned()))
}
}
}
impl<T> RouletteWheel<T> {
pub fn from_vec(vector: Vec<T>) -> RouletteWheel<T> {
RouletteWheel {
proba_sum: vector.len() as f32,
cards: repeat(1.0).into_iter().zip(vector).collect()
}
}
pub fn new() -> RouletteWheel<T> {
RouletteWheel {
proba_sum: 0.0,
cards: VecDeque::new()
}
}
pub fn with_capacity(n: usize) -> RouletteWheel<T> {
RouletteWheel {
proba_sum: 0.0,
cards: VecDeque::with_capacity(n)
}
}
pub fn reserve(&mut self, additional: usize) {
self.cards.reserve(additional);
}
pub fn capacity(&self) -> usize {
self.cards.capacity()
}
pub fn len(&self) -> usize {
self.cards.len()
}
pub fn clear(&mut self) {
self.cards.clear()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn push(&mut self, proba: f32, data: T) {
assert!(proba > 0.0, "proba {} is lower or equal to zero!", proba);
self.cards.push_back((proba, data));
self.proba_sum += proba;
if self.proba_sum.is_infinite() {
panic!("Probability sum reached an Inf value!");
}
}
pub fn compute_proba_sum(&mut self) {
self.proba_sum = 0.0;
for &(proba, _) in self.cards.iter() {
assert!(proba > 0.0, "proba '{}' is lower or equal to zero!", proba);
self.proba_sum += proba;
}
if self.proba_sum.is_infinite() {
panic!("Probability sum reached an Inf value!");
}
}
pub fn proba_sum(&self) -> f32 {
self.proba_sum
}
fn gen_random_dist(&self) -> f32 {
match self.proba_sum {
sum if sum > 0. => rand::thread_rng().gen_range(0., sum),
_ => 0.
}
}
fn get_random_index(&self) -> Option<usize> {
if self.is_empty() == false {
let mut dist = self.gen_random_dist();
for (id, &(ref proba, _)) in self.cards.iter().enumerate() {
dist -= *proba;
if dist <= 0. {
return Some(id);
}
}
None
}
else { None }
}
pub fn peek(&self) -> Option<(f32, &T)> {
if let Some(index) = self.get_random_index() {
if let Some(&(proba, ref data)) = self.cards.get(index) {
Some((proba, data))
}
else { None }
}
else { None }
}
pub fn peek_mut(&mut self) -> Option<(f32, &mut T)> {
if let Some(index) = self.get_random_index() {
if let Some(&mut (proba, ref mut data)) = self.cards.get_mut(index) {
Some((proba, data))
}
else { None }
}
else { None }
}
pub fn pop(&mut self) -> Option<(f32, T)> {
if let Some(index) = self.get_random_index() {
if let Some((proba, data)) = self.cards.remove(index) {
self.proba_sum -= proba;
Some((proba, data))
}
else { None }
}
else { None }
}
}