#[cfg(feature="dist_mode")]
use std::mem;
#[cfg(feature="dist_mode")]
use libc::*;
use rand::prelude::*;
pub type GeneratorBox = Box<dyn FnMut() -> f64>;
#[cfg(feature="dist_mode")]
#[repr(C)]
#[derive(Copy, Clone)]
struct GeneratorTraitObject {
field1: *mut c_void,
field2: *mut c_void
}
#[cfg(feature="dist_mode")]
#[repr(C)]
pub struct GeneratorRepr {
delete: unsafe extern "C" fn(obj: *mut GeneratorTraitObject),
callback: unsafe extern "C" fn(obj: *mut GeneratorTraitObject) -> f64,
trait_object: GeneratorTraitObject
}
#[cfg(feature="dist_mode")]
impl Drop for GeneratorRepr {
fn drop(&mut self) {
unsafe {
(self.delete)(&mut self.trait_object);
}
}
}
#[cfg(feature="dist_mode")]
impl GeneratorRepr {
#[inline]
pub fn into_repr(gen: GeneratorBox) -> GeneratorRepr {
unsafe {
GeneratorRepr {
delete: delete_generator_repr,
callback: call_generator_repr,
trait_object: mem::transmute(gen)
}
}
}
#[inline]
pub fn call(&mut self) -> f64 {
unsafe {
(self.callback)(&mut self.trait_object)
}
}
}
#[cfg(feature="dist_mode")]
unsafe extern "C" fn call_generator_repr(gen: *mut GeneratorTraitObject) -> f64 {
let mut gen: GeneratorBox = mem::transmute(*gen);
let x = gen();
mem::forget(gen);
x
}
#[cfg(feature="dist_mode")]
unsafe extern "C" fn delete_generator_repr(gen: *mut GeneratorTraitObject) {
let _: GeneratorBox = mem::transmute(*gen);
}
#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
pub struct GeneratorRepr {
gen: GeneratorBox
}
#[cfg(any(feature="seq_mode", feature="wasm_mode"))]
impl GeneratorRepr {
#[inline]
pub fn into_repr(gen: GeneratorBox) -> GeneratorRepr {
GeneratorRepr { gen: gen }
}
#[inline]
pub fn call(&mut self) -> f64 {
(self.gen)()
}
}
pub fn uniform_generator() -> GeneratorRepr {
let mut rng = rand::thread_rng();
let gen = Box::new(move || {
rng.gen()
});
GeneratorRepr::into_repr(gen)
}
pub fn uniform_generator_with_seed(seed: [u8; 32]) -> GeneratorRepr {
let mut rng = StdRng::from_seed(seed);
let gen = Box::new(move || {
rng.gen()
});
GeneratorRepr::into_repr(gen)
}
pub fn normal_generator(gen: GeneratorRepr) -> GeneratorRepr {
let mut gen = gen;
let mut next = 0.0;
let mut flag = false;
let gen = Box::new(move || {
if flag {
flag = false;
next
} else {
let mut xi1 = 0.0;
let mut xi2 = 0.0;
let mut psi = 0.0;
loop {
if psi >= 1.0 || psi == 0.0 {
let g1 = gen.call();
let g2 = gen.call();
xi1 = 2.0 * g1 - 1.0;
xi2 = 2.0 * g2 - 1.0;
psi = xi1 * xi1 + xi2 * xi2;
} else {
psi = (- 2.0 * psi.ln() / psi).sqrt();
break;
}
}
flag = true;
next = xi2 * psi;
xi1 * psi
}
});
GeneratorRepr::into_repr(gen)
}
#[inline]
pub fn generate_uniform(gen: &mut GeneratorRepr, min: f64, max: f64) -> f64 {
let x = gen.call();
min + x * (max - min)
}
pub fn generate_int_uniform(gen: &mut GeneratorRepr, min: isize, max: isize) -> isize {
let x = gen.call();
let min2 = (min as f64) - 0.5;
let max2 = (max as f64) + 0.5;
let z = (min2 + x * (max2 - min2)).round() as isize;
if z < min {
min
} else if z > max {
max
} else {
z
}
}
pub fn generate_triangular(gen: &mut GeneratorRepr, min: f64, median: f64, max: f64) -> f64 {
let x = gen.call();
if x <= (median - min) / (max - min) {
min + ((median - min) * (max - min) * x).sqrt()
} else {
max - ((max - median) * (max - min) * (1.0 - x)).sqrt()
}
}
#[inline]
pub fn generate_normal(gen: &mut GeneratorRepr, mu: f64, nu: f64) -> f64 {
let x = gen.call();
mu + nu * x
}
#[inline]
pub fn generate_log_normal(gen: &mut GeneratorRepr, mu: f64, nu: f64) -> f64 {
let x = gen.call();
(mu + nu * x).exp()
}
#[inline]
pub fn generate_exponential(gen: &mut GeneratorRepr, mu: f64) -> f64 {
let x = gen.call();
- x.ln() * mu
}
pub fn generate_erlang(gen: &mut GeneratorRepr, scale: f64, shape: isize) -> f64 {
assert!(shape >= 0, "Negative shape");
let mut y = 1.0;
for _ in 0..shape {
let x = gen.call();
y *= x;
}
- y.ln() * scale
}
pub fn generate_poisson(gen: &mut GeneratorRepr, mu: f64) -> isize {
let mut prob = gen.call();
let mut prod = (- mu).exp();
let mut acc = 0;
loop {
if prob <= prod {
return acc;
} else {
let prob2 = prob - prod;
let prod2 = prod * mu / ((acc + 1) as f64);
let acc2 = acc + 1;
prob = prob2;
prod = prod2;
acc = acc2;
}
}
}
pub fn generate_binomial(gen: &mut GeneratorRepr, prob: f64, trials: isize) -> isize {
assert!(trials >= 0, "Negative number of trials");
let mut acc = 0;
for _ in 0..trials {
let x = gen.call();
if x <= prob {
acc += 1;
}
}
acc
}
#[allow(unconditional_recursion)]
pub fn generate_gamma(genn: &mut GeneratorRepr, genu: &mut GeneratorRepr, kappa: f64, theta: f64) -> f64 {
if kappa <= 0.0 {
panic!("The shape parameter (kappa) must be positive")
} else if kappa > 1.0 {
let d = kappa - 1.0 / 3.0;
let c = 1.0 / (9.0 * d).sqrt();
loop {
let z = genn.call();
if z > - (1.0 / c) {
let v = (1.0 + c * z).powi(3);
let u = genu.call();
if u.ln() <= 0.5 * z * z + d - d * v + d * v.ln() {
return d * v * theta
}
}
}
} else {
let x = generate_gamma(genn, genu, 1.0 + kappa, theta);
let u = genu.call();
x * u.powf(1.0 / kappa)
}
}
#[inline]
pub fn generate_beta(genn: &mut GeneratorRepr, genu: &mut GeneratorRepr, alpha: f64, beta: f64) -> f64 {
let g1 = generate_gamma(genn, genu, alpha, 1.0);
let g2 = generate_gamma(genn, genu, beta, 1.0);
g1 / (g1 + g2)
}
#[inline]
pub fn generate_weibull(gen: &mut GeneratorRepr, alpha: f64, beta: f64) -> f64 {
let x = gen.call();
beta * (- x.ln()).powf(1.0 / alpha)
}
pub fn generate_discrete<'a, T>(gen: &mut GeneratorRepr, dpdf: &'a [(T, f64)]) -> &'a T {
assert!(dpdf.len() > 0, "Empty discrete probability density");
let x = gen.call();
let mut acc = 0.0;
let mut dpdf = dpdf;
loop {
if dpdf.len() == 1 {
let a = &dpdf[0].0;
return a;
} else {
let p = dpdf[0].1;
if x <= acc + p {
let a = &dpdf[0].0;
return a;
} else {
acc += p;
dpdf = &dpdf[1..];
}
}
}
}