use crate::rng::Rng64;
pub struct Bst<T, R: Rng64> {
source: Vec<T>,
weights: Vec<f64>,
rng: R,
}
impl<T, R: Rng64> Bst<T, R> {
pub fn new(source: Vec<T>, weights: Vec<f64>, rng: R) -> Self {
if source.len() != weights.len() {
panic!("Source and weights must have the same length");
}
Self {
source,
weights,
rng,
}
}
pub fn search(&mut self) -> usize {
if self.source.is_empty() {
0
} else {
let mut total_weight: f64 = 0.0;
let mut accumulate_weights = Vec::new();
let length = self.weights.len();
for weight in self.weights.iter() {
total_weight += weight;
accumulate_weights.push(total_weight);
}
let point = self.rng.randf(0.0, total_weight);
let mut bottom = 0;
let mut top = length - 1;
while bottom < top {
let middle = (bottom + top) / 2;
if point > accumulate_weights[middle] {
bottom = middle + 1;
} else {
let p = if middle > 0 {
accumulate_weights[middle - 1]
} else {
0.0
};
if point >= p {
return middle;
}
top = middle;
}
}
top
}
}
pub fn choice(&mut self) -> &T {
let index = self.search();
&self.source[index]
}
}