use crate::{ProbabilityDistribution, StrError};
use rand::Rng;
use rand_distr::{Distribution, Frechet};
use russell_lab::math::gamma;
const FRECHET_MIN_DELTA_X: f64 = 1e-15;
pub struct DistributionFrechet {
location: f64, scale: f64, shape: f64, sampler: Frechet<f64>, }
impl DistributionFrechet {
pub fn new(location: f64, scale: f64, shape: f64) -> Result<Self, StrError> {
Ok(DistributionFrechet {
location,
scale,
shape,
sampler: Frechet::new(location, scale, shape).map_err(|_| "invalid parameters")?,
})
}
}
impl ProbabilityDistribution for DistributionFrechet {
fn pdf(&self, x: f64) -> f64 {
if x - self.location < FRECHET_MIN_DELTA_X {
return 0.0;
}
let z = (x - self.location) / self.scale;
f64::exp(-f64::powf(z, -self.shape)) * f64::powf(z, -1.0 - self.shape) * self.shape / self.scale
}
fn cdf(&self, x: f64) -> f64 {
if x - self.location < FRECHET_MIN_DELTA_X {
return 0.0;
}
let z = (x - self.location) / self.scale;
f64::exp(-f64::powf(z, -self.shape))
}
fn mean(&self) -> f64 {
if self.shape > 1.0 {
return self.location + self.scale * gamma(1.0 - 1.0 / self.shape);
}
f64::INFINITY
}
fn variance(&self) -> f64 {
if self.shape > 2.0 {
let ss = self.scale * self.scale;
return ss * (gamma(1.0 - 2.0 / self.shape) - f64::powi(gamma(1.0 - 1.0 / self.shape), 2));
}
f64::INFINITY
}
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
self.sampler.sample(rng)
}
}
#[cfg(test)]
mod tests {
use crate::{get_rng, DistributionFrechet, ProbabilityDistribution};
use russell_lab::approx_eq;
#[test]
fn frechet_handles_errors() {
assert_eq!(
DistributionFrechet::new(2.0, 3.0, f64::INFINITY).err(),
Some("invalid parameters")
);
}
#[test]
fn frechet_works() {
#[rustfmt::skip]
let data = [
[0.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 1.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[5.00000000000000e-01, 0.00000000000000e+00, 1.00000000000000e+00, 1.00000000000000e+00, 5.41341132946451e-01, 1.35335283236613e-01],
[1.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 1.00000000000000e+00, 3.67879441171442e-01, 3.67879441171442e-01],
[1.50000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 1.00000000000000e+00, 2.28185386236708e-01, 5.13417119032592e-01],
[2.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 1.00000000000000e+00, 1.51632664928158e-01, 6.06530659712633e-01],
[2.50000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 1.00000000000000e+00, 1.07251207365702e-01, 6.70320046035639e-01],
[3.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 1.00000000000000e+00, 7.96145900637543e-02, 7.16531310573789e-01],
[3.50000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 1.00000000000000e+00, 6.13450851490029e-02, 7.51477293075286e-01],
[4.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 1.00000000000000e+00, 4.86750489419628e-02, 7.78800783071405e-01],
[0.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 2.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[5.00000000000000e-01, 0.00000000000000e+00, 1.00000000000000e+00, 2.00000000000000e+00, 2.93050222219747e-01, 1.83156388887342e-02],
[1.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 2.00000000000000e+00, 7.35758882342885e-01, 3.67879441171442e-01],
[1.50000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 2.00000000000000e+00, 3.79958748699232e-01, 6.41180388429955e-01],
[2.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 2.00000000000000e+00, 1.94700195767851e-01, 7.78800783071405e-01],
[2.50000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 2.00000000000000e+00, 1.09074404987675e-01, 8.52143788966211e-01],
[3.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 2.00000000000000e+00, 6.62843938381015e-02, 8.94839316814370e-01],
[3.50000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 2.00000000000000e+00, 4.29905748010600e-02, 9.21610447297725e-01],
[4.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 2.00000000000000e+00, 2.93566582129211e-02, 9.39413062813476e-01],
[0.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 3.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[5.00000000000000e-01, 0.00000000000000e+00, 1.00000000000000e+00, 3.00000000000000e+00, 1.61022061393206e-02, 3.35462627902512e-04],
[1.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 3.00000000000000e+00, 1.10363832351433e+00, 3.67879441171442e-01],
[1.50000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 3.00000000000000e+00, 4.40632343233130e-01, 7.43567079205906e-01],
[2.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 3.00000000000000e+00, 1.65468169234612e-01, 8.82496902584595e-01],
[2.50000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 3.00000000000000e+00, 7.20387839639600e-02, 9.38004999530729e-01],
[3.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 3.00000000000000e+00, 3.56903868259736e-02, 9.63640444301286e-01],
[3.50000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 3.00000000000000e+00, 1.95307877314814e-02, 9.76946277985140e-01],
[4.00000000000000e+00, 0.00000000000000e+00, 1.00000000000000e+00, 3.00000000000000e+00, 1.15370676211571e-02, 9.84496437005408e-01],
[0.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 1.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[5.00000000000000e-01, 0.00000000000000e+00, 2.00000000000000e+00, 1.00000000000000e+00, 1.46525111109873e-01, 1.83156388887342e-02],
[1.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 1.00000000000000e+00, 2.70670566473225e-01, 1.35335283236613e-01],
[1.50000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 1.00000000000000e+00, 2.34308567213979e-01, 2.63597138115727e-01],
[2.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 1.00000000000000e+00, 1.83939720585721e-01, 3.67879441171442e-01],
[2.50000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 1.00000000000000e+00, 1.43785268517511e-01, 4.49328964117222e-01],
[3.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 1.00000000000000e+00, 1.14092693118354e-01, 5.13417119032592e-01],
[3.50000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 1.00000000000000e+00, 9.21988770624913e-02, 5.64718122007759e-01],
[4.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 1.00000000000000e+00, 7.58163324640792e-02, 6.06530659712633e-01],
[0.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 2.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[5.00000000000000e-01, 0.00000000000000e+00, 2.00000000000000e+00, 2.00000000000000e+00, 7.20225118203259e-06, 1.12535174719259e-07],
[1.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 2.00000000000000e+00, 1.46525111109873e-01, 1.83156388887342e-02],
[1.50000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 2.00000000000000e+00, 4.00624155036601e-01, 1.69013315406066e-01],
[2.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 2.00000000000000e+00, 3.67879441171442e-01, 3.67879441171442e-01],
[2.50000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 2.00000000000000e+00, 2.69973721110041e-01, 5.27292424043049e-01],
[3.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 2.00000000000000e+00, 1.89979374349616e-01, 6.41180388429955e-01],
[3.50000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 2.00000000000000e+00, 1.34609406946660e-01, 7.21422290354756e-01],
[4.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 2.00000000000000e+00, 9.73500978839256e-02, 7.78800783071405e-01],
[0.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 3.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[5.00000000000000e-01, 0.00000000000000e+00, 2.00000000000000e+00, 3.00000000000000e+00, 6.15863381970675e-26, 1.60381089054864e-28],
[1.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 3.00000000000000e+00, 8.05110306966028e-03, 3.35462627902512e-04],
[1.50000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 3.00000000000000e+00, 4.43003781677631e-01, 9.34461101976254e-02],
[2.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 3.00000000000000e+00, 5.51819161757164e-01, 3.67879441171442e-01],
[2.50000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 3.00000000000000e+00, 3.68207332052299e-01, 5.99295787845538e-01],
[3.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 3.00000000000000e+00, 2.20316171616565e-01, 7.43567079205906e-01],
[3.50000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 3.00000000000000e+00, 1.32710267758176e-01, 8.29784773144222e-01],
[4.00000000000000e+00, 0.00000000000000e+00, 2.00000000000000e+00, 3.00000000000000e+00, 8.27340846173058e-02, 8.82496902584595e-01],
[0.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 1.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[5.00000000000000e-01, 5.00000000000000e-01, 1.00000000000000e+00, 1.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[1.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 1.00000000000000e+00, 5.41341132946451e-01, 1.35335283236613e-01],
[1.50000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 1.00000000000000e+00, 3.67879441171442e-01, 3.67879441171442e-01],
[2.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 1.00000000000000e+00, 2.28185386236708e-01, 5.13417119032592e-01],
[2.50000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 1.00000000000000e+00, 1.51632664928158e-01, 6.06530659712633e-01],
[3.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 1.00000000000000e+00, 1.07251207365702e-01, 6.70320046035639e-01],
[3.50000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 1.00000000000000e+00, 7.96145900637543e-02, 7.16531310573789e-01],
[4.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 1.00000000000000e+00, 6.13450851490029e-02, 7.51477293075286e-01],
[0.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 2.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[5.00000000000000e-01, 5.00000000000000e-01, 1.00000000000000e+00, 2.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[1.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 2.00000000000000e+00, 2.93050222219747e-01, 1.83156388887342e-02],
[1.50000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 2.00000000000000e+00, 7.35758882342885e-01, 3.67879441171442e-01],
[2.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 2.00000000000000e+00, 3.79958748699232e-01, 6.41180388429955e-01],
[2.50000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 2.00000000000000e+00, 1.94700195767851e-01, 7.78800783071405e-01],
[3.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 2.00000000000000e+00, 1.09074404987675e-01, 8.52143788966211e-01],
[3.50000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 2.00000000000000e+00, 6.62843938381015e-02, 8.94839316814370e-01],
[4.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 2.00000000000000e+00, 4.29905748010600e-02, 9.21610447297725e-01],
[0.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 3.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[5.00000000000000e-01, 5.00000000000000e-01, 1.00000000000000e+00, 3.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[1.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 3.00000000000000e+00, 1.61022061393206e-02, 3.35462627902512e-04],
[1.50000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 3.00000000000000e+00, 1.10363832351433e+00, 3.67879441171442e-01],
[2.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 3.00000000000000e+00, 4.40632343233130e-01, 7.43567079205906e-01],
[2.50000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 3.00000000000000e+00, 1.65468169234612e-01, 8.82496902584595e-01],
[3.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 3.00000000000000e+00, 7.20387839639600e-02, 9.38004999530729e-01],
[3.50000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 3.00000000000000e+00, 3.56903868259736e-02, 9.63640444301286e-01],
[4.00000000000000e+00, 5.00000000000000e-01, 1.00000000000000e+00, 3.00000000000000e+00, 1.95307877314814e-02, 9.76946277985140e-01],
[0.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 1.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[5.00000000000000e-01, 5.00000000000000e-01, 2.00000000000000e+00, 1.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[1.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 1.00000000000000e+00, 1.46525111109873e-01, 1.83156388887342e-02],
[1.50000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 1.00000000000000e+00, 2.70670566473225e-01, 1.35335283236613e-01],
[2.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 1.00000000000000e+00, 2.34308567213979e-01, 2.63597138115727e-01],
[2.50000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 1.00000000000000e+00, 1.83939720585721e-01, 3.67879441171442e-01],
[3.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 1.00000000000000e+00, 1.43785268517511e-01, 4.49328964117222e-01],
[3.50000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 1.00000000000000e+00, 1.14092693118354e-01, 5.13417119032592e-01],
[4.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 1.00000000000000e+00, 9.21988770624913e-02, 5.64718122007759e-01],
[0.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 2.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[5.00000000000000e-01, 5.00000000000000e-01, 2.00000000000000e+00, 2.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[1.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 2.00000000000000e+00, 7.20225118203259e-06, 1.12535174719259e-07],
[1.50000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 2.00000000000000e+00, 1.46525111109873e-01, 1.83156388887342e-02],
[2.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 2.00000000000000e+00, 4.00624155036601e-01, 1.69013315406066e-01],
[2.50000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 2.00000000000000e+00, 3.67879441171442e-01, 3.67879441171442e-01],
[3.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 2.00000000000000e+00, 2.69973721110041e-01, 5.27292424043049e-01],
[3.50000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 2.00000000000000e+00, 1.89979374349616e-01, 6.41180388429955e-01],
[4.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 2.00000000000000e+00, 1.34609406946660e-01, 7.21422290354756e-01],
[0.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 3.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[5.00000000000000e-01, 5.00000000000000e-01, 2.00000000000000e+00, 3.00000000000000e+00, 0.00000000000000e+00, 0.00000000000000e+00],
[1.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 3.00000000000000e+00, 6.15863381970675e-26, 1.60381089054864e-28],
[1.50000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 3.00000000000000e+00, 8.05110306966028e-03, 3.35462627902512e-04],
[2.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 3.00000000000000e+00, 4.43003781677631e-01, 9.34461101976254e-02],
[2.50000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 3.00000000000000e+00, 5.51819161757164e-01, 3.67879441171442e-01],
[3.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 3.00000000000000e+00, 3.68207332052299e-01, 5.99295787845538e-01],
[3.50000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 3.00000000000000e+00, 2.20316171616565e-01, 7.43567079205906e-01],
[4.00000000000000e+00, 5.00000000000000e-01, 2.00000000000000e+00, 3.00000000000000e+00, 1.32710267758176e-01, 8.29784773144222e-01],
];
for row in data {
let [x, location, scale, shape, pdf, cdf] = row;
let d = DistributionFrechet::new(location, scale, shape).unwrap();
approx_eq(d.pdf(x), pdf, 1e-14);
approx_eq(d.cdf(x), cdf, 1e-14);
}
}
#[test]
fn mean_and_variance_work() {
let location = 8.782275;
let scale = 1.0;
let shape = 4.095645;
let d = DistributionFrechet::new(location, scale, shape).unwrap();
approx_eq(d.mean(), 10.0, 1e-6);
approx_eq(d.variance(), 0.25, 1e-6);
let d = DistributionFrechet::new(location, scale, 1.0).unwrap();
assert_eq!(d.mean(), f64::INFINITY);
assert_eq!(d.variance(), f64::INFINITY);
}
#[test]
fn sample_works() {
let d = DistributionFrechet::new(1.0, 2.0, 3.0).unwrap();
let mut rng = get_rng();
d.sample(&mut rng);
}
}