use crate::prelude::*;
use rand::Rng;
use std::cell::{Ref, RefCell, RefMut};
use weighted_rand::builder::*;
#[cfg(not(feature = "eq_float"))]
pub trait ChooseRand:
IntoIterator<Item = RefCell<<Self as ChooseRand>::Item>>
+ std::ops::Index<usize, Output = RefCell<<Self as ChooseRand>::Item>>
+ Sized
+ Clone
{
type Item: Probable;
fn choose_rand(&self, rng: &mut impl Rng) -> Result<Ref<<Self as ChooseRand>::Item>> {
let weights: Vec<_> = self
.clone()
.into_iter() .map(|p| p.borrow().probability())
.collect();
if weights.iter().sum::<f32>() != 1. {
return Err(Error::ProbabilitySum);
}
let wt = WalkerTableBuilder::new(&weights).build();
let i = wt.next_rng(rng);
Ok(self[i].borrow())
}
fn choose_rand_mut(
&mut self,
rng: &mut impl Rng,
) -> Result<RefMut<<Self as ChooseRand>::Item>> {
let weights: Vec<_> = self
.clone()
.into_iter()
.map(|p| p.borrow().probability())
.collect();
if weights.iter().sum::<f32>() != 1. {
return Err(Error::ProbabilitySum);
}
let wt = WalkerTableBuilder::new(&weights).build();
let i = wt.next_rng(rng);
Ok(self[i].borrow_mut())
}
}
#[cfg(feature = "eq_float")]
pub trait ChooseRand:
IntoIterator<Item = RefCell<<Self as ChooseRand>::Item>>
+ std::ops::Index<usize, Output = RefCell<<Self as ChooseRand>::Item>>
+ Sized
+ Clone
{
type Item: Probable;
fn choose_rand(&self, rng: &mut impl Rng) -> Result<Ref<<Self as ChooseRand>::Item>> {
let weights: Vec<_> = self
.clone()
.into_iter() .map(|p| p.borrow().probability())
.collect();
if weights.iter().sum::<eq_float::F32>() != eq_float::F32(1.) {
return Err(Error::ProbabilitySum);
}
let wt = WalkerTableBuilder::new(&weights).build();
let i = wt.next_rng(rng);
Ok(self[i].borrow())
}
fn choose_rand_mut(
&mut self,
rng: &mut impl Rng,
) -> Result<RefMut<<Self as ChooseRand>::Item>> {
let weights: Vec<_> = self
.clone()
.into_iter()
.map(|p| p.borrow().probability())
.collect();
if weights.iter().sum::<f32>() != 1. {
return Err(Error::ProbabilitySum);
}
let wt = WalkerTableBuilder::new(&weights).build();
let i = wt.next_rng(rng);
Ok(self[i].borrow_mut())
}
}
impl<T, V> ChooseRand for T
where
T: IntoIterator<Item = RefCell<V>>
+ std::ops::Index<usize, Output = RefCell<V>>
+ Sized
+ Clone,
V: Probable,
{
type Item = V;
}
#[cfg(not(feature = "eq_float"))]
pub trait Probable {
fn probability(&self) -> f32;
}
#[cfg(feature = "eq_float")]
pub trait Probable {
fn probability(&self) -> eq_float::F32;
}