use numrs2::stats::distributions::*;
const TOL: f64 = 1e-6;
const LOOSER_TOL: f64 = 1e-4;
#[test]
fn test_beta_pdf_basic() {
let pdf: f64 = beta_pdf(0.5, 2.0, 3.0).expect("beta_pdf should succeed");
assert!((pdf - 1.5).abs() < TOL, "Beta(2,3) PDF at 0.5 = {}", pdf);
}
#[test]
fn test_beta_pdf_edge_cases() {
let pdf: f64 = beta_pdf(0.0, 2.0, 3.0).expect("beta_pdf should succeed");
assert_eq!(pdf, 0.0, "Beta PDF at x=0 should be 0");
let pdf: f64 = beta_pdf(1.0, 2.0, 3.0).expect("beta_pdf should succeed");
assert_eq!(pdf, 0.0, "Beta PDF at x=1 should be 0");
let pdf: f64 = beta_pdf(1.5, 2.0, 3.0).expect("beta_pdf should succeed");
assert_eq!(pdf, 0.0, "Beta PDF outside [0,1] should be 0");
}
#[test]
fn test_beta_cdf_properties() {
let cdf: f64 = beta_cdf(0.0, 2.0, 3.0).expect("beta_cdf should succeed");
assert!((cdf - 0.0).abs() < TOL, "Beta CDF at 0 = {}", cdf);
let cdf: f64 = beta_cdf(1.0, 2.0, 3.0).expect("beta_cdf should succeed");
assert!((cdf - 1.0).abs() < TOL, "Beta CDF at 1 = {}", cdf);
let cdf1 = beta_cdf(0.3, 2.0, 3.0).expect("beta_cdf should succeed");
let cdf2 = beta_cdf(0.5, 2.0, 3.0).expect("beta_cdf should succeed");
let cdf3 = beta_cdf(0.7, 2.0, 3.0).expect("beta_cdf should succeed");
assert!(cdf1 < cdf2 && cdf2 < cdf3, "Beta CDF should be increasing");
}
#[test]
fn test_beta_ppf_cdf_inverse() {
let x = 0.5;
let cdf: f64 = beta_cdf(x, 2.0, 3.0).expect("beta_cdf should succeed");
let ppf: f64 = beta_ppf(cdf, 2.0, 3.0).expect("beta_ppf should succeed");
assert!(
(ppf - x).abs() < LOOSER_TOL,
"Beta PPF(CDF(x)) ≈ x, got {}",
ppf
);
}
#[test]
fn test_beta_logpdf_consistency() {
let x = 0.5;
let a = 2.0;
let b = 3.0;
let pdf: f64 = beta_pdf(x, a, b).expect("beta_pdf should succeed");
let logpdf = beta_logpdf(x, a, b).expect("beta_logpdf should succeed");
assert!(
(logpdf - pdf.ln()).abs() < TOL,
"log PDF should match ln(PDF)"
);
}
#[test]
fn test_gamma_pdf_basic() {
let pdf: f64 = gamma_pdf(0.0001, 1.0, 1.0).expect("gamma_pdf should succeed");
assert!((pdf - 1.0).abs() < 0.01, "Gamma(1,1) PDF at x≈0 ≈ 1.0");
}
#[test]
fn test_gamma_pdf_edge_cases() {
let pdf: f64 = gamma_pdf(0.0, 2.0, 1.0).expect("gamma_pdf should succeed");
assert_eq!(pdf, 0.0, "Gamma PDF at x=0 should be 0");
let pdf: f64 = gamma_pdf(-1.0, 2.0, 1.0).expect("gamma_pdf should succeed");
assert_eq!(pdf, 0.0, "Gamma PDF at x<0 should be 0");
}
#[test]
fn test_gamma_cdf_properties() {
let cdf: f64 = gamma_cdf(0.0, 2.0, 1.0).expect("gamma_cdf should succeed");
assert!((cdf - 0.0).abs() < TOL, "Gamma CDF at 0 = {}", cdf);
let cdf1 = gamma_cdf(1.0, 2.0, 1.0).expect("gamma_cdf should succeed");
let cdf2 = gamma_cdf(2.0, 2.0, 1.0).expect("gamma_cdf should succeed");
let cdf3 = gamma_cdf(3.0, 2.0, 1.0).expect("gamma_cdf should succeed");
assert!(cdf1 < cdf2 && cdf2 < cdf3, "Gamma CDF should be increasing");
}
#[test]
fn test_gamma_ppf_cdf_inverse() {
let x = 2.0;
let cdf: f64 = gamma_cdf(x, 2.0, 1.0).expect("gamma_cdf should succeed");
let ppf: f64 = gamma_ppf(cdf, 2.0, 1.0).expect("gamma_ppf should succeed");
assert!(
(ppf - x).abs() < LOOSER_TOL,
"Gamma PPF(CDF(x)) ≈ x, got {}",
ppf
);
}
#[test]
fn test_gamma_logpdf_consistency() {
let x = 2.0;
let shape = 2.0;
let scale = 1.0;
let pdf: f64 = gamma_pdf(x, shape, scale).expect("gamma_pdf should succeed");
let logpdf = gamma_logpdf(x, shape, scale).expect("gamma_logpdf should succeed");
assert!(
(logpdf - pdf.ln()).abs() < TOL,
"log PDF should match ln(PDF)"
);
}
#[test]
fn test_student_t_pdf_basic() {
let pdf: f64 = student_t_pdf(0.0, 10.0).expect("student_t_pdf should succeed");
assert!(pdf > 0.0, "Student's t PDF at 0 should be positive");
let pdf_pos: f64 = student_t_pdf(1.5, 10.0).expect("student_t_pdf should succeed");
let pdf_neg: f64 = student_t_pdf(-1.5, 10.0).expect("student_t_pdf should succeed");
assert!(
(pdf_pos - pdf_neg).abs() < TOL,
"Student's t PDF should be symmetric"
);
}
#[test]
fn test_student_t_cdf_properties() {
let cdf: f64 = student_t_cdf(0.0, 10.0).expect("student_t_cdf should succeed");
assert!((cdf - 0.5).abs() < TOL, "Student's t CDF at 0 = {}", cdf);
let cdf1 = student_t_cdf(-1.0, 10.0).expect("student_t_cdf should succeed");
let cdf2 = student_t_cdf(0.0, 10.0).expect("student_t_cdf should succeed");
let cdf3 = student_t_cdf(1.0, 10.0).expect("student_t_cdf should succeed");
assert!(
cdf1 < cdf2 && cdf2 < cdf3,
"Student's t CDF should be increasing"
);
}
#[test]
fn test_student_t_ppf_cdf_inverse() {
let x = 1.5;
let cdf: f64 = student_t_cdf(x, 10.0).expect("student_t_cdf should succeed");
let ppf: f64 = student_t_ppf(cdf, 10.0).expect("student_t_ppf should succeed");
assert!(
(ppf - x).abs() < LOOSER_TOL,
"Student's t PPF(CDF(x)) ≈ x, got {}",
ppf
);
}
#[test]
fn test_student_t_critical_values() {
let upper: f64 = student_t_ppf(0.975, 10.0).expect("student_t_ppf should succeed");
assert!(
(upper - 2.228).abs() < 0.01,
"t(10) 97.5% quantile ≈ 2.228, got {}",
upper
);
}
#[test]
fn test_cauchy_pdf_basic() {
let pdf: f64 = cauchy_pdf(0.0, 0.0, 1.0).expect("cauchy_pdf should succeed");
let expected = 1.0 / std::f64::consts::PI;
assert!((pdf - expected).abs() < TOL, "Cauchy PDF at 0 = {}", pdf);
let pdf_pos: f64 = cauchy_pdf(2.0, 0.0, 1.0).expect("cauchy_pdf should succeed");
let pdf_neg: f64 = cauchy_pdf(-2.0, 0.0, 1.0).expect("cauchy_pdf should succeed");
assert!(
(pdf_pos - pdf_neg).abs() < TOL,
"Cauchy PDF should be symmetric"
);
}
#[test]
fn test_cauchy_cdf_properties() {
let cdf: f64 = cauchy_cdf(0.0, 0.0, 1.0).expect("cauchy_cdf should succeed");
assert!((cdf - 0.5).abs() < TOL, "Cauchy CDF at median = {}", cdf);
let cdf1 = cauchy_cdf(-2.0, 0.0, 1.0).expect("cauchy_cdf should succeed");
let cdf2 = cauchy_cdf(0.0, 0.0, 1.0).expect("cauchy_cdf should succeed");
let cdf3 = cauchy_cdf(2.0, 0.0, 1.0).expect("cauchy_cdf should succeed");
assert!(
cdf1 < cdf2 && cdf2 < cdf3,
"Cauchy CDF should be increasing"
);
}
#[test]
fn test_cauchy_ppf_cdf_inverse() {
let x = 1.5;
let cdf: f64 = cauchy_cdf(x, 0.0, 1.0).expect("cauchy_cdf should succeed");
let ppf: f64 = cauchy_ppf(cdf, 0.0, 1.0).expect("cauchy_ppf should succeed");
assert!((ppf - x).abs() < TOL, "Cauchy PPF(CDF(x)) ≈ x, got {}", ppf);
}
#[test]
fn test_laplace_pdf_basic() {
let pdf: f64 = laplace_pdf(0.0, 0.0, 1.0).expect("laplace_pdf should succeed");
assert!((pdf - 0.5).abs() < TOL, "Laplace PDF at mean = {}", pdf);
let pdf_pos: f64 = laplace_pdf(1.5, 0.0, 1.0).expect("laplace_pdf should succeed");
let pdf_neg: f64 = laplace_pdf(-1.5, 0.0, 1.0).expect("laplace_pdf should succeed");
assert!(
(pdf_pos - pdf_neg).abs() < TOL,
"Laplace PDF should be symmetric"
);
}
#[test]
fn test_laplace_cdf_properties() {
let cdf: f64 = laplace_cdf(0.0, 0.0, 1.0).expect("laplace_cdf should succeed");
assert!((cdf - 0.5).abs() < TOL, "Laplace CDF at mean = {}", cdf);
let cdf1 = laplace_cdf(-2.0, 0.0, 1.0).expect("laplace_cdf should succeed");
let cdf2 = laplace_cdf(0.0, 0.0, 1.0).expect("laplace_cdf should succeed");
let cdf3 = laplace_cdf(2.0, 0.0, 1.0).expect("laplace_cdf should succeed");
assert!(
cdf1 < cdf2 && cdf2 < cdf3,
"Laplace CDF should be increasing"
);
}
#[test]
fn test_laplace_ppf_cdf_inverse() {
let x = 1.0;
let cdf: f64 = laplace_cdf(x, 0.0, 1.0).expect("laplace_cdf should succeed");
let ppf: f64 = laplace_ppf(cdf, 0.0, 1.0).expect("laplace_ppf should succeed");
assert!(
(ppf - x).abs() < TOL,
"Laplace PPF(CDF(x)) ≈ x, got {}",
ppf
);
}
#[test]
fn test_logistic_pdf_basic() {
let pdf: f64 = logistic_pdf(0.0, 0.0, 1.0).expect("logistic_pdf should succeed");
assert!(
(pdf - 0.25_f64).abs() < TOL,
"Logistic PDF at mean = {}",
pdf
);
let pdf_pos: f64 = logistic_pdf(1.5, 0.0, 1.0).expect("logistic_pdf should succeed");
let pdf_neg: f64 = logistic_pdf(-1.5, 0.0, 1.0).expect("logistic_pdf should succeed");
assert!(
(pdf_pos - pdf_neg).abs() < TOL,
"Logistic PDF should be symmetric"
);
}
#[test]
fn test_logistic_cdf_properties() {
let cdf: f64 = logistic_cdf(0.0, 0.0, 1.0).expect("logistic_cdf should succeed");
assert!((cdf - 0.5).abs() < TOL, "Logistic CDF at mean = {}", cdf);
let cdf1 = logistic_cdf(-2.0, 0.0, 1.0).expect("logistic_cdf should succeed");
let cdf2 = logistic_cdf(0.0, 0.0, 1.0).expect("logistic_cdf should succeed");
let cdf3 = logistic_cdf(2.0, 0.0, 1.0).expect("logistic_cdf should succeed");
assert!(
cdf1 < cdf2 && cdf2 < cdf3,
"Logistic CDF should be increasing"
);
}
#[test]
fn test_logistic_ppf_cdf_inverse() {
let x = 1.0;
let cdf: f64 = logistic_cdf(x, 0.0, 1.0).expect("logistic_cdf should succeed");
let ppf: f64 = logistic_ppf(cdf, 0.0, 1.0).expect("logistic_ppf should succeed");
assert!(
(ppf - x).abs() < TOL,
"Logistic PPF(CDF(x)) ≈ x, got {}",
ppf
);
}
#[test]
fn test_pareto_pdf_basic() {
let pdf: f64 = pareto_pdf(2.0, 2.0, 1.0).expect("pareto_pdf should succeed");
assert!((pdf - 0.25).abs() < TOL, "Pareto(2,1) PDF at x=2 = {}", pdf);
let pdf: f64 = pareto_pdf(0.5, 2.0, 1.0).expect("pareto_pdf should succeed");
assert_eq!(pdf, 0.0, "Pareto PDF below xm should be 0");
}
#[test]
fn test_pareto_cdf_properties() {
let cdf: f64 = pareto_cdf(1.0, 2.0, 1.0).expect("pareto_cdf should succeed");
assert!((cdf - 0.0).abs() < TOL, "Pareto CDF at xm = {}", cdf);
let cdf: f64 = pareto_cdf(2.0, 2.0, 1.0).expect("pareto_cdf should succeed");
assert!((cdf - 0.75).abs() < TOL, "Pareto(2,1) CDF at x=2 = {}", cdf);
let cdf1 = pareto_cdf(1.5, 2.0, 1.0).expect("pareto_cdf should succeed");
let cdf2 = pareto_cdf(2.0, 2.0, 1.0).expect("pareto_cdf should succeed");
let cdf3 = pareto_cdf(3.0, 2.0, 1.0).expect("pareto_cdf should succeed");
assert!(
cdf1 < cdf2 && cdf2 < cdf3,
"Pareto CDF should be increasing"
);
}
#[test]
fn test_pareto_ppf_cdf_inverse() {
let x = 2.0;
let cdf: f64 = pareto_cdf(x, 2.0, 1.0).expect("pareto_cdf should succeed");
let ppf: f64 = pareto_ppf(cdf, 2.0, 1.0).expect("pareto_ppf should succeed");
assert!((ppf - x).abs() < TOL, "Pareto PPF(CDF(x)) ≈ x, got {}", ppf);
}
#[test]
fn test_numerical_stability() {
let pdf: f64 = beta_pdf(0.5, 0.1, 0.1).expect("beta_pdf should succeed");
assert!(
pdf.is_finite(),
"Beta PDF should be finite for small parameters"
);
let pdf: f64 = gamma_pdf(10.0, 100.0, 1.0).expect("gamma_pdf should succeed");
assert!(
pdf.is_finite(),
"Gamma PDF should be finite for large shape"
);
let pdf: f64 = student_t_pdf(0.0, 1.0).expect("student_t_pdf should succeed");
assert!(pdf.is_finite(), "Student's t PDF should be finite for df=1");
let pdf: f64 = student_t_pdf(0.0, 1000.0).expect("student_t_pdf should succeed");
assert!(
pdf.is_finite(),
"Student's t PDF should be finite for large df"
);
}
#[test]
fn test_error_handling() {
assert!(
beta_pdf(0.5, -1.0, 3.0).is_err(),
"Beta PDF should reject negative alpha"
);
assert!(
beta_pdf(0.5, 2.0, 0.0).is_err(),
"Beta PDF should reject zero beta"
);
assert!(
gamma_pdf(1.0, 0.0, 1.0).is_err(),
"Gamma PDF should reject zero shape"
);
assert!(
gamma_pdf(1.0, 2.0, -1.0).is_err(),
"Gamma PDF should reject negative scale"
);
assert!(
student_t_pdf(0.0, 0.0).is_err(),
"Student's t PDF should reject zero df"
);
assert!(
student_t_pdf(0.0, -5.0).is_err(),
"Student's t PDF should reject negative df"
);
assert!(
cauchy_pdf(0.0, 0.0, 0.0).is_err(),
"Cauchy PDF should reject zero scale"
);
assert!(
laplace_pdf(0.0, 0.0, -1.0).is_err(),
"Laplace PDF should reject negative scale"
);
assert!(
logistic_pdf(0.0, 0.0, 0.0).is_err(),
"Logistic PDF should reject zero scale"
);
assert!(
pareto_pdf(2.0, 0.0, 1.0).is_err(),
"Pareto PDF should reject zero alpha"
);
assert!(
pareto_pdf(2.0, 2.0, -1.0).is_err(),
"Pareto PDF should reject negative xm"
);
assert!(beta_ppf(1.5, 2.0, 3.0).is_err(), "PPF should reject p > 1");
assert!(
gamma_ppf(-0.1, 2.0, 1.0).is_err(),
"PPF should reject p < 0"
);
}
#[test]
fn test_pdf_cdf_consistency() {
let a = 2.0;
let b = 3.0;
let x = 0.6;
let n = 1000;
let dx = x / n as f64;
let mut integral = 0.0;
for i in 1..n {
let xi = i as f64 * dx;
let pdf_val = beta_pdf(xi, a, b).expect("beta_pdf should succeed");
integral += pdf_val * dx;
}
let cdf: f64 = beta_cdf(x, a, b).expect("beta_cdf should succeed");
assert!((integral - cdf).abs() < 0.01, "Integral of Beta PDF ≈ CDF");
}
#[test]
fn test_distribution_relationships() {
for x in &[0.0, 0.5, 1.0, 2.0] {
let cauchy: f64 = cauchy_pdf(*x, 0.0, 1.0).expect("cauchy_pdf should succeed");
let t1: f64 = student_t_pdf(*x, 1.0).expect("student_t_pdf should succeed");
let diff = (cauchy - t1).abs();
assert!(
diff < TOL,
"Cauchy(0,1) ≈ t(1) at x={}: cauchy={}, t1={}, diff={}, TOL={}",
x,
cauchy,
t1,
diff,
TOL
);
}
}