#[cfg(feature = "alloc")]
use crate::utils::FindChangePoints;
#[cfg(feature = "alloc")]
use rand::distr::weighted::WeightedIndex;
#[cfg(feature = "alloc")]
use rand::prelude::*;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "alloc")]
pub fn get_implied_distribution(f: impl Fn(u64) -> usize) -> (Vec<(u64, usize)>, Vec<f64>) {
let change_points = FindChangePoints::new(f)
.take_while(|(_input, len)| *len <= 128)
.collect::<Vec<_>>();
let probabilities = change_points
.windows(2)
.map(|window| {
let (input, len) = window[0];
let (next_input, _next_len) = window[1];
let prob = 2.0_f64.powi(-(len as i32));
prob * (next_input - input) as f64
})
.collect::<Vec<_>>();
(change_points, probabilities)
}
#[derive(Clone, Copy, Debug)]
pub struct InfiniteIterator;
impl Iterator for InfiniteIterator {
type Item = ();
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
Some(())
}
}
#[cfg(feature = "alloc")]
pub fn sample_implied_distribution(
f: impl Fn(u64) -> usize,
rng: &mut impl Rng,
) -> impl Iterator<Item = u64> + '_ {
let (change_points, probabilities) = get_implied_distribution(f);
let dist = WeightedIndex::new(probabilities).unwrap();
InfiniteIterator.map(move |_| {
let idx = dist.sample(rng);
let (start_input, _len) = change_points[idx];
let (end_input, _len) = change_points[idx + 1];
rng.random_range(start_input..end_input)
})
}