use libm::{exp, log, pow};
use crate::dist::distutils::*;
use rand_chacha::ChaCha8Rng;
use rand::SeedableRng;
use rand::Rng;
#[derive(Clone, Copy)]
pub struct GEV {
pub loc: f64,
pub scale: f64,
pub shape: f64,
}
impl GEV {
#[inline]
pub fn new(loc: f64, scale: f64, shape: f64) -> Self {
domain!(scale > 0.0);
GEV{loc, scale, shape}
}
#[inline(always)]
pub fn loc(&self) -> f64 {
self.loc
}
#[inline(always)]
pub fn scale(&self) -> f64 {
self.scale
}
#[inline(always)]
pub fn shape(&self) -> f64 {
self.shape
}
#[inline(always)]
fn t_func(&self, x: f64) -> f64 {
let y: f64 = (x - self.loc) / self.scale;
if self.shape == 0.0 {
exp(- y)
} else {
pow(1.0 + self.shape * y , - 1.0 / self.shape)
}
}
}
impl DistQuant for GEV {
fn cdf(&self, x: f64) -> f64 {
domain!(1.0 + self.shape * ( (x - self.loc ) / self.scale ) > 0.0 && self.scale > 0.0); let t_val: f64 = self.t_func(x);
exp(- t_val)
}
fn pdf(&self, x: f64) -> f64 {
domain!(1.0 + self.shape * ( (x - self.loc ) / self.scale ) > 0.0 && self.scale > 0.0); let mult_const: f64 = 1.0 / self.scale;
let t_val: f64 = self.t_func(x);
mult_const * pow(t_val, self.shape + 1.0) * exp(- t_val)
}
fn quantile(&self, x: f64) -> f64 {
domain!(x >= 0.0 && x <= 1.0);
if self.shape == 0.0 {
- self.scale * log( - log(x)) + self.loc
} else {
let mult_const: f64 = self.scale / self.shape;
mult_const * pow(- log(x) , - self.shape) - mult_const + self.loc
}
}
fn random(&self, seed: RandomSeed) -> f64 {
let mut rng = match seed {
RandomSeed::Empty => ChaCha8Rng::from_entropy(),
RandomSeed::Seed(val) => ChaCha8Rng::seed_from_u64(val), };
let rand_quant: f64 = rng.gen::<f64>(); self.quantile(rand_quant) }
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! new_gev(
($loc:expr, $scale:expr, $shape:expr) => (GEV::new($loc, $scale, $shape));
);
#[test]
fn gev_cdf_test_one() {
let gev: GEV = new_gev!(2.0, 2.0, 2.0);
let ans: f64 = 0.49306869139523984;
let cdf_gev: f64 = gev.cdf(3.0);
assert_eq!(ans, cdf_gev);
}
#[test]
fn gev_pdf_test_one() {
let gev: GEV = new_gev!(2.0, 2.0, 2.0);
let ans: f64 = 0.08716305381908777;
let pdf_gev: f64 = gev.pdf(3.0);
assert_eq!(ans, pdf_gev);
}
#[test]
fn gev_quantile_test_one() {
let gev: GEV = new_gev!(2.0, 2.0, 2.0);
let ans: f64 = 8.860583704300595;
let quant_gev: f64 = gev.quantile(0.7);
assert_eq!(ans, quant_gev);
}
#[test]
fn gev_cdf_test_two() {
let gev: GEV = new_gev!(2.0, 2.0, 0.0);
let ans: f64 = 0.545239211892605;
let cdf_gev: f64 = gev.cdf(3.0);
assert_eq!(ans, cdf_gev);
}
#[test]
fn gev_pdf_test_two() {
let gev: GEV = new_gev!(2.0, 2.0, 0.0);
let ans: f64 = 0.16535214944520904;
let pdf_gev: f64 = gev.pdf(3.0);
assert_eq!(ans, pdf_gev);
}
#[test]
fn gev_quantile_test_two() {
let gev: GEV = new_gev!(2.0, 2.0, 0.0);
let ans: f64 = 4.061860866317446;
let quant_gev: f64 = gev.quantile(0.7);
assert_eq!(ans, quant_gev);
}
}