From 71dc1e4252d6fb21c2f75d0197a044420b89a190 Mon Sep 17 00:00:00 2001 From: FreezyLemon Date: Wed, 7 Aug 2024 11:46:23 +0200 Subject: [PATCH] Remove `StatsError` type; use Option instead --- src/distribution/bernoulli.rs | 11 +-- src/distribution/beta.rs | 11 +-- src/distribution/binomial.rs | 15 ++- src/distribution/categorical.rs | 15 ++- src/distribution/cauchy.rs | 15 ++- src/distribution/chi.rs | 15 ++- src/distribution/chi_squared.rs | 9 +- src/distribution/dirac.rs | 15 ++- src/distribution/dirichlet.rs | 22 ++--- src/distribution/discrete_uniform.rs | 15 ++- src/distribution/empirical.rs | 7 +- src/distribution/erlang.rs | 11 +-- src/distribution/exponential.rs | 15 ++- src/distribution/fisher_snedecor.rs | 15 ++- src/distribution/gamma.rs | 11 +-- src/distribution/geometric.rs | 15 ++- src/distribution/hypergeometric.rs | 15 ++- src/distribution/internal.rs | 4 +- src/distribution/inverse_gamma.rs | 21 ++--- src/distribution/laplace.rs | 15 ++- src/distribution/log_normal.rs | 16 ++-- src/distribution/mod.rs | 2 - src/distribution/multinomial.rs | 15 ++- src/distribution/multivariate_normal.rs | 15 ++- src/distribution/negative_binomial.rs | 15 ++- src/distribution/normal.rs | 16 ++-- src/distribution/pareto.rs | 15 ++- src/distribution/poisson.rs | 15 ++- src/distribution/students_t.rs | 11 +-- src/distribution/triangular.rs | 19 ++-- src/distribution/uniform.rs | 27 +++--- src/distribution/weibull.rs | 33 ++++--- src/error.rs | 120 ------------------------ src/function/beta.rs | 58 +++++------- src/function/exponential.rs | 16 ++-- src/function/factorial.rs | 10 +- src/function/gamma.rs | 72 +++++++------- src/function/logistic.rs | 13 +-- src/lib.rs | 8 -- src/statistics/iter_statistics.rs | 9 +- src/stats_tests/fisher.rs | 29 +++--- tests/nist_tests.rs | 11 +-- 42 files changed, 321 insertions(+), 496 deletions(-) delete mode 100644 src/error.rs diff --git a/src/distribution/bernoulli.rs b/src/distribution/bernoulli.rs index 61499ebd..ae0970b0 100644 --- a/src/distribution/bernoulli.rs +++ b/src/distribution/bernoulli.rs @@ -1,6 +1,5 @@ use crate::distribution::{Binomial, Discrete, DiscreteCDF}; use crate::statistics::*; -use crate::Result; use rand::Rng; /// Implements the @@ -40,12 +39,12 @@ impl Bernoulli { /// use statrs::distribution::Bernoulli; /// /// let mut result = Bernoulli::new(0.5); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Bernoulli::new(-0.5); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(p: f64) -> Result { + pub fn new(p: f64) -> Option { Binomial::new(p, 1).map(|b| Bernoulli { b }) } @@ -271,7 +270,7 @@ mod testing { fn try_create(p: f64) -> Bernoulli { let n = Bernoulli::new(p); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -282,7 +281,7 @@ mod testing { fn bad_create_case(p: f64) { let n = Bernoulli::new(p); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(p: f64, eval: F) -> T diff --git a/src/distribution/beta.rs b/src/distribution/beta.rs index b3cfdcf4..3afc875d 100644 --- a/src/distribution/beta.rs +++ b/src/distribution/beta.rs @@ -2,7 +2,6 @@ use crate::distribution::{Continuous, ContinuousCDF}; use crate::function::{beta, gamma}; use crate::is_zero; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; /// Implements the [Beta](https://en.wikipedia.org/wiki/Beta_distribution) @@ -40,21 +39,21 @@ impl Beta { /// use statrs::distribution::Beta; /// /// let mut result = Beta::new(2.0, 2.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Beta::new(0.0, 0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(shape_a: f64, shape_b: f64) -> Result { + pub fn new(shape_a: f64, shape_b: f64) -> Option { if shape_a.is_nan() || shape_b.is_nan() || shape_a.is_infinite() && shape_b.is_infinite() || shape_a <= 0.0 || shape_b <= 0.0 { - return Err(StatsError::BadParams); + return None; }; - Ok(Beta { shape_a, shape_b }) + Some(Beta { shape_a, shape_b }) } /// Returns the shapeA (α) of the beta distribution diff --git a/src/distribution/binomial.rs b/src/distribution/binomial.rs index 2b56e6fc..8fa833c6 100644 --- a/src/distribution/binomial.rs +++ b/src/distribution/binomial.rs @@ -2,7 +2,6 @@ use crate::distribution::{Discrete, DiscreteCDF}; use crate::function::{beta, factorial}; use crate::is_zero; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; use std::f64; @@ -43,16 +42,16 @@ impl Binomial { /// use statrs::distribution::Binomial; /// /// let mut result = Binomial::new(0.5, 5); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Binomial::new(-0.5, 5); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(p: f64, n: u64) -> Result { + pub fn new(p: f64, n: u64) -> Option { if p.is_nan() || !(0.0..=1.0).contains(&p) { - Err(StatsError::BadParams) + None } else { - Ok(Binomial { p, n }) + Some(Binomial { p, n }) } } @@ -336,7 +335,7 @@ mod tests { fn try_create(p: f64, n: u64) -> Binomial { let n = Binomial::new(p, n); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -348,7 +347,7 @@ mod tests { fn bad_create_case(p: f64, n: u64) { let n = Binomial::new(p, n); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(p: f64, n: u64, eval: F) -> T diff --git a/src/distribution/categorical.rs b/src/distribution/categorical.rs index 31bccf8b..f50f4c29 100644 --- a/src/distribution/categorical.rs +++ b/src/distribution/categorical.rs @@ -1,6 +1,5 @@ use crate::distribution::{Discrete, DiscreteCDF}; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; use std::f64; @@ -48,14 +47,14 @@ impl Categorical { /// use statrs::distribution::Categorical; /// /// let mut result = Categorical::new(&[0.0, 1.0, 2.0]); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Categorical::new(&[0.0, -1.0, 2.0]); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(prob_mass: &[f64]) -> Result { + pub fn new(prob_mass: &[f64]) -> Option { if !super::internal::is_valid_multinomial(prob_mass, true) { - Err(StatsError::BadParams) + None } else { // extract un-normalized cdf let cdf = prob_mass_to_cdf(prob_mass); @@ -68,7 +67,7 @@ impl Categorical { .iter_mut() .zip(prob_mass.iter()) .for_each(|(np, pm)| *np = *pm / sum); - Ok(Categorical { norm_pmf, cdf, sf }) + Some(Categorical { norm_pmf, cdf, sf }) } } @@ -359,7 +358,7 @@ mod tests { fn try_create(prob_mass: &[f64]) -> Categorical { let n = Categorical::new(prob_mass); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -369,7 +368,7 @@ mod tests { fn bad_create_case(prob_mass: &[f64]) { let n = Categorical::new(prob_mass); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(prob_mass: &[f64], eval: F) -> T diff --git a/src/distribution/cauchy.rs b/src/distribution/cauchy.rs index b3f40bda..9f5d3460 100644 --- a/src/distribution/cauchy.rs +++ b/src/distribution/cauchy.rs @@ -1,6 +1,5 @@ use crate::distribution::{Continuous, ContinuousCDF}; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; use std::f64; @@ -37,16 +36,16 @@ impl Cauchy { /// use statrs::distribution::Cauchy; /// /// let mut result = Cauchy::new(0.0, 1.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Cauchy::new(0.0, -1.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(location: f64, scale: f64) -> Result { + pub fn new(location: f64, scale: f64) -> Option { if location.is_nan() || scale.is_nan() || scale <= 0.0 { - Err(StatsError::BadParams) + None } else { - Ok(Cauchy { location, scale }) + Some(Cauchy { location, scale }) } } @@ -240,7 +239,7 @@ mod tests { fn try_create(location: f64, scale: f64) -> Cauchy { let n = Cauchy::new(location, scale); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -252,7 +251,7 @@ mod tests { fn bad_create_case(location: f64, scale: f64) { let n = Cauchy::new(location, scale); - assert!(n.is_err()); + assert!(n.is_none()); } fn test_case(location: f64, scale: f64, expected: f64, eval: F) diff --git a/src/distribution/chi.rs b/src/distribution/chi.rs index 205cca11..7e54bdee 100644 --- a/src/distribution/chi.rs +++ b/src/distribution/chi.rs @@ -1,7 +1,6 @@ use crate::distribution::{Continuous, ContinuousCDF}; use crate::function::gamma; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; use std::f64; @@ -39,16 +38,16 @@ impl Chi { /// use statrs::distribution::Chi; /// /// let mut result = Chi::new(2.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Chi::new(0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(freedom: f64) -> Result { + pub fn new(freedom: f64) -> Option { if freedom.is_nan() || freedom <= 0.0 { - Err(StatsError::BadParams) + None } else { - Ok(Chi { freedom }) + Some(Chi { freedom }) } } @@ -332,7 +331,7 @@ mod tests { fn try_create(freedom: f64) -> Chi { let n = Chi::new(freedom); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -343,7 +342,7 @@ mod tests { fn bad_create_case(freedom: f64) { let n = Chi::new(freedom); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(freedom: f64, eval: F) -> f64 diff --git a/src/distribution/chi_squared.rs b/src/distribution/chi_squared.rs index 1c6b42b0..2872b722 100644 --- a/src/distribution/chi_squared.rs +++ b/src/distribution/chi_squared.rs @@ -1,6 +1,5 @@ use crate::distribution::{Continuous, ContinuousCDF, Gamma}; use crate::statistics::*; -use crate::Result; use rand::Rng; use std::f64; @@ -43,12 +42,12 @@ impl ChiSquared { /// use statrs::distribution::ChiSquared; /// /// let mut result = ChiSquared::new(3.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = ChiSquared::new(0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(freedom: f64) -> Result { + pub fn new(freedom: f64) -> Option { Gamma::new(freedom / 2.0, 0.5).map(|g| ChiSquared { freedom, g }) } @@ -297,7 +296,7 @@ mod tests { fn try_create(freedom: f64) -> ChiSquared { let n = ChiSquared::new(freedom); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } diff --git a/src/distribution/dirac.rs b/src/distribution/dirac.rs index 4fa6a390..7496bc58 100644 --- a/src/distribution/dirac.rs +++ b/src/distribution/dirac.rs @@ -1,6 +1,5 @@ use crate::distribution::{Continuous, ContinuousCDF}; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; /// Implements the [Dirac Delta](https://en.wikipedia.org/wiki/Dirac_delta_function#As_a_distribution) @@ -31,16 +30,16 @@ impl Dirac { /// use statrs::distribution::Dirac; /// /// let mut result = Dirac::new(0.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Dirac::new(f64::NAN); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(v: f64) -> Result { + pub fn new(v: f64) -> Option { if v.is_nan() { - Err(StatsError::BadParams) + None } else { - Ok(Dirac(v)) + Some(Dirac(v)) } } } @@ -198,7 +197,7 @@ mod tests { fn try_create(v: f64) -> Dirac { let d = Dirac::new(v); - assert!(d.is_ok()); + assert!(d.is_some()); d.unwrap() } @@ -209,7 +208,7 @@ mod tests { fn bad_create_case(v: f64) { let d = Dirac::new(v); - assert!(d.is_err()); + assert!(d.is_none()); } fn test_case(v: f64, expected: f64, eval: F) diff --git a/src/distribution/dirichlet.rs b/src/distribution/dirichlet.rs index 55795a7a..ebfc7b63 100644 --- a/src/distribution/dirichlet.rs +++ b/src/distribution/dirichlet.rs @@ -1,7 +1,7 @@ use crate::distribution::Continuous; use crate::function::gamma; +use crate::prec; use crate::statistics::*; -use crate::{prec, Result, StatsError}; use nalgebra::DMatrix; use nalgebra::DVector; use nalgebra::{ @@ -48,18 +48,18 @@ impl Dirichlet { /// /// let alpha_ok = vec![1.0, 2.0, 3.0]; /// let mut result = Dirichlet::new(alpha_ok); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// let alpha_err = vec![0.0]; /// result = Dirichlet::new(alpha_err); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(alpha: Vec) -> Result { + pub fn new(alpha: Vec) -> Option { if !is_valid_alpha(&alpha) { - Err(StatsError::BadParams) + None } else { // let vec = alpha.to_vec(); - Ok(Dirichlet { + Some(Dirichlet { alpha: DVector::from_vec(alpha.to_vec()), }) } @@ -79,12 +79,12 @@ impl Dirichlet { /// use statrs::distribution::Dirichlet; /// /// let mut result = Dirichlet::new_with_param(1.0, 3); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Dirichlet::new_with_param(0.0, 1); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new_with_param(alpha: f64, n: usize) -> Result { + pub fn new_with_param(alpha: f64, n: usize) -> Option { Self::new(vec![alpha; n]) } @@ -324,7 +324,7 @@ mod tests { fn try_create(alpha: &[f64]) -> Dirichlet { let n = Dirichlet::new(alpha.to_vec()); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -340,7 +340,7 @@ mod tests { fn bad_create_case(alpha: &[f64]) { let n = Dirichlet::new(alpha.to_vec()); - assert!(n.is_err()); + assert!(n.is_none()); } #[test] diff --git a/src/distribution/discrete_uniform.rs b/src/distribution/discrete_uniform.rs index 361cadd8..a5431c54 100644 --- a/src/distribution/discrete_uniform.rs +++ b/src/distribution/discrete_uniform.rs @@ -1,6 +1,5 @@ use crate::distribution::{Discrete, DiscreteCDF}; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; /// Implements the [Discrete @@ -37,16 +36,16 @@ impl DiscreteUniform { /// use statrs::distribution::DiscreteUniform; /// /// let mut result = DiscreteUniform::new(0, 5); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = DiscreteUniform::new(5, 0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(min: i64, max: i64) -> Result { + pub fn new(min: i64, max: i64) -> Option { if max < min { - Err(StatsError::BadParams) + None } else { - Ok(DiscreteUniform { min, max }) + Some(DiscreteUniform { min, max }) } } } @@ -262,7 +261,7 @@ mod tests { fn try_create(min: i64, max: i64) -> DiscreteUniform { let n = DiscreteUniform::new(min, max); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -274,7 +273,7 @@ mod tests { fn bad_create_case(min: i64, max: i64) { let n = DiscreteUniform::new(min, max); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(min: i64, max: i64, eval: F) -> T diff --git a/src/distribution/empirical.rs b/src/distribution/empirical.rs index 9afd7022..fce0852e 100644 --- a/src/distribution/empirical.rs +++ b/src/distribution/empirical.rs @@ -1,6 +1,5 @@ use crate::distribution::{Continuous, ContinuousCDF, Uniform}; use crate::statistics::*; -use crate::{Result, StatsError}; use ::num_traits::float::Float; use core::cmp::Ordering; use rand::Rng; @@ -55,10 +54,10 @@ impl Empirical { /// use statrs::distribution::Empirical; /// /// let mut result = Empirical::new(); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// ``` - pub fn new() -> Result { - Ok(Empirical { + pub fn new() -> Option { + Some(Empirical { sum: 0., mean_and_var: None, data: BTreeMap::new(), diff --git a/src/distribution/erlang.rs b/src/distribution/erlang.rs index 1213baef..3663d4e9 100644 --- a/src/distribution/erlang.rs +++ b/src/distribution/erlang.rs @@ -1,6 +1,5 @@ use crate::distribution::{Continuous, ContinuousCDF, Gamma}; use crate::statistics::*; -use crate::Result; use rand::Rng; /// Implements the [Erlang](https://en.wikipedia.org/wiki/Erlang_distribution) @@ -40,12 +39,12 @@ impl Erlang { /// use statrs::distribution::Erlang; /// /// let mut result = Erlang::new(3, 1.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Erlang::new(0, 0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(shape: u64, rate: f64) -> Result { + pub fn new(shape: u64, rate: f64) -> Option { Gamma::new(shape as f64, rate).map(|g| Erlang { g }) } @@ -283,7 +282,7 @@ mod tests { fn try_create(shape: u64, rate: f64) -> Erlang { let n = Erlang::new(shape, rate); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -295,7 +294,7 @@ mod tests { fn bad_create_case(shape: u64, rate: f64) { let n = Erlang::new(shape, rate); - assert!(n.is_err()); + assert!(n.is_none()); } #[test] diff --git a/src/distribution/exponential.rs b/src/distribution/exponential.rs index 978ae638..378b59dd 100644 --- a/src/distribution/exponential.rs +++ b/src/distribution/exponential.rs @@ -1,6 +1,5 @@ use crate::distribution::{ziggurat, Continuous, ContinuousCDF}; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; use std::f64; @@ -39,16 +38,16 @@ impl Exp { /// use statrs::distribution::Exp; /// /// let mut result = Exp::new(1.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Exp::new(-1.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(rate: f64) -> Result { + pub fn new(rate: f64) -> Option { if rate.is_nan() || rate <= 0.0 { - Err(StatsError::BadParams) + None } else { - Ok(Exp { rate }) + Some(Exp { rate }) } } @@ -286,7 +285,7 @@ mod tests { fn try_create(rate: f64) -> Exp { let n = Exp::new(rate); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -297,7 +296,7 @@ mod tests { fn bad_create_case(rate: f64) { let n = Exp::new(rate); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(rate: f64, eval: F) -> f64 diff --git a/src/distribution/fisher_snedecor.rs b/src/distribution/fisher_snedecor.rs index d54a1bef..9025af49 100644 --- a/src/distribution/fisher_snedecor.rs +++ b/src/distribution/fisher_snedecor.rs @@ -1,7 +1,6 @@ use crate::distribution::{Continuous, ContinuousCDF}; use crate::function::beta; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; use std::f64; @@ -41,17 +40,17 @@ impl FisherSnedecor { /// use statrs::distribution::FisherSnedecor; /// /// let mut result = FisherSnedecor::new(1.0, 1.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = FisherSnedecor::new(0.0, 0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(freedom_1: f64, freedom_2: f64) -> Result { + pub fn new(freedom_1: f64, freedom_2: f64) -> Option { if !freedom_1.is_finite() || freedom_1 <= 0.0 || !freedom_2.is_finite() || freedom_2 <= 0.0 { - Err(StatsError::BadParams) + None } else { - Ok(FisherSnedecor { + Some(FisherSnedecor { freedom_1, freedom_2, }) @@ -369,7 +368,7 @@ mod tests { fn try_create(freedom_1: f64, freedom_2: f64) -> FisherSnedecor { let n = FisherSnedecor::new(freedom_1, freedom_2); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -381,7 +380,7 @@ mod tests { fn bad_create_case(freedom_1: f64, freedom_2: f64) { let n = FisherSnedecor::new(freedom_1, freedom_2); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(freedom_1: f64, freedom_2: f64, eval: F) -> f64 diff --git a/src/distribution/gamma.rs b/src/distribution/gamma.rs index 166ebb72..b5942f21 100644 --- a/src/distribution/gamma.rs +++ b/src/distribution/gamma.rs @@ -2,7 +2,6 @@ use crate::distribution::{Continuous, ContinuousCDF}; use crate::function::gamma; use crate::prec; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; /// Implements the [Gamma](https://en.wikipedia.org/wiki/Gamma_distribution) @@ -40,21 +39,21 @@ impl Gamma { /// use statrs::distribution::Gamma; /// /// let mut result = Gamma::new(3.0, 1.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Gamma::new(0.0, 0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(shape: f64, rate: f64) -> Result { + pub fn new(shape: f64, rate: f64) -> Option { if shape.is_nan() || rate.is_nan() || shape.is_infinite() && rate.is_infinite() || shape <= 0.0 || rate <= 0.0 { - return Err(StatsError::BadParams); + return None; } - Ok(Gamma { shape, rate }) + Some(Gamma { shape, rate }) } /// Returns the shape (α) of the gamma distribution diff --git a/src/distribution/geometric.rs b/src/distribution/geometric.rs index 4df623ed..9ceaba82 100644 --- a/src/distribution/geometric.rs +++ b/src/distribution/geometric.rs @@ -1,6 +1,5 @@ use crate::distribution::{Discrete, DiscreteCDF}; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::distributions::OpenClosed01; use rand::Rng; use std::f64; @@ -39,16 +38,16 @@ impl Geometric { /// use statrs::distribution::Geometric; /// /// let mut result = Geometric::new(0.5); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Geometric::new(0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(p: f64) -> Result { + pub fn new(p: f64) -> Option { if p <= 0.0 || p > 1.0 || p.is_nan() { - Err(StatsError::BadParams) + None } else { - Ok(Geometric { p }) + Some(Geometric { p }) } } @@ -280,7 +279,7 @@ mod tests { fn try_create(p: f64) -> Geometric { let n = Geometric::new(p); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -291,7 +290,7 @@ mod tests { fn bad_create_case(p: f64) { let n = Geometric::new(p); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(p: f64, eval: F) -> T diff --git a/src/distribution/hypergeometric.rs b/src/distribution/hypergeometric.rs index 8b6d8500..12771333 100644 --- a/src/distribution/hypergeometric.rs +++ b/src/distribution/hypergeometric.rs @@ -1,7 +1,6 @@ use crate::distribution::{Discrete, DiscreteCDF}; use crate::function::factorial; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; use std::cmp; use std::f64; @@ -37,16 +36,16 @@ impl Hypergeometric { /// use statrs::distribution::Hypergeometric; /// /// let mut result = Hypergeometric::new(2, 2, 2); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Hypergeometric::new(2, 3, 2); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(population: u64, successes: u64, draws: u64) -> Result { + pub fn new(population: u64, successes: u64, draws: u64) -> Option { if successes > population || draws > population { - Err(StatsError::BadParams) + None } else { - Ok(Hypergeometric { + Some(Hypergeometric { population, successes, draws, @@ -385,7 +384,7 @@ mod tests { fn try_create(population: u64, successes: u64, draws: u64) -> Hypergeometric { let n = Hypergeometric::new(population, successes, draws); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -398,7 +397,7 @@ mod tests { fn bad_create_case(population: u64, successes: u64, draws: u64) { let n = Hypergeometric::new(population, successes, draws); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(population: u64, successes: u64, draws: u64, eval: F) -> T diff --git a/src/distribution/internal.rs b/src/distribution/internal.rs index 15c24c10..88cd8ec2 100644 --- a/src/distribution/internal.rs +++ b/src/distribution/internal.rs @@ -66,13 +66,13 @@ pub mod test { ($($arg_name:ident: $arg_ty:ty),+; $dist:ty) => { fn try_create($($arg_name: $arg_ty),+) -> $dist { let n = <$dist>::new($($arg_name),+); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } fn bad_create_case($($arg_name: $arg_ty),+) { let n = <$dist>::new($($arg_name),+); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value($($arg_name: $arg_ty),+, eval: F) -> T diff --git a/src/distribution/inverse_gamma.rs b/src/distribution/inverse_gamma.rs index d22d2239..d9f7d182 100644 --- a/src/distribution/inverse_gamma.rs +++ b/src/distribution/inverse_gamma.rs @@ -1,7 +1,6 @@ use crate::distribution::{Continuous, ContinuousCDF}; use crate::function::gamma; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; use std::f64; @@ -41,20 +40,18 @@ impl InverseGamma { /// use statrs::distribution::InverseGamma; /// /// let mut result = InverseGamma::new(3.0, 1.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = InverseGamma::new(0.0, 0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(shape: f64, rate: f64) -> Result { + pub fn new(shape: f64, rate: f64) -> Option { let is_nan = shape.is_nan() || rate.is_nan(); match (shape, rate, is_nan) { - (_, _, true) => Err(StatsError::BadParams), - (_, _, false) if shape <= 0.0 || rate <= 0.0 => Err(StatsError::BadParams), - (_, _, false) if shape.is_infinite() || rate.is_infinite() => { - Err(StatsError::BadParams) - } - (_, _, false) => Ok(InverseGamma { shape, rate }), + (_, _, true) => None, + (_, _, false) if shape <= 0.0 || rate <= 0.0 => None, + (_, _, false) if shape.is_infinite() || rate.is_infinite() => None, + (_, _, false) => Some(InverseGamma { shape, rate }), } } @@ -319,7 +316,7 @@ mod tests { fn try_create(shape: f64, rate: f64) -> InverseGamma { let n = InverseGamma::new(shape, rate); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -331,7 +328,7 @@ mod tests { fn bad_create_case(shape: f64, rate: f64) { let n = InverseGamma::new(shape, rate); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(shape: f64, rate: f64, eval: F) -> f64 diff --git a/src/distribution/laplace.rs b/src/distribution/laplace.rs index 1ed74132..7e6686de 100644 --- a/src/distribution/laplace.rs +++ b/src/distribution/laplace.rs @@ -1,6 +1,5 @@ use crate::distribution::{Continuous, ContinuousCDF}; use crate::statistics::{Distribution, Max, Median, Min, Mode}; -use crate::{Result, StatsError}; use rand::Rng; use std::f64; @@ -37,16 +36,16 @@ impl Laplace { /// use statrs::distribution::Laplace; /// /// let mut result = Laplace::new(0.0, 1.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Laplace::new(0.0, -1.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(location: f64, scale: f64) -> Result { + pub fn new(location: f64, scale: f64) -> Option { if location.is_nan() || scale.is_nan() || scale <= 0.0 { - Err(StatsError::BadParams) + None } else { - Ok(Laplace { location, scale }) + Some(Laplace { location, scale }) } } @@ -304,13 +303,13 @@ mod tests { fn try_create(location: f64, scale: f64) -> Laplace { let n = Laplace::new(location, scale); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } fn bad_create_case(location: f64, scale: f64) { let n = Laplace::new(location, scale); - assert!(n.is_err()); + assert!(n.is_none()); } fn test_case(location: f64, scale: f64, expected: f64, eval: F) diff --git a/src/distribution/log_normal.rs b/src/distribution/log_normal.rs index b6dbff6f..4f20b652 100644 --- a/src/distribution/log_normal.rs +++ b/src/distribution/log_normal.rs @@ -1,7 +1,7 @@ +use crate::consts; use crate::distribution::{Continuous, ContinuousCDF}; use crate::function::erf; use crate::statistics::*; -use crate::{consts, Result, StatsError}; use rand::Rng; use std::f64; @@ -41,16 +41,16 @@ impl LogNormal { /// use statrs::distribution::LogNormal; /// /// let mut result = LogNormal::new(0.0, 1.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = LogNormal::new(0.0, 0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(location: f64, scale: f64) -> Result { + pub fn new(location: f64, scale: f64) -> Option { if location.is_nan() || scale.is_nan() || scale <= 0.0 { - Err(StatsError::BadParams) + None } else { - Ok(LogNormal { location, scale }) + Some(LogNormal { location, scale }) } } } @@ -311,13 +311,13 @@ mod tests { fn try_create(mean: f64, std_dev: f64) -> LogNormal { let n = LogNormal::new(mean, std_dev); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } fn bad_create_case(mean: f64, std_dev: f64) { let n = LogNormal::new(mean, std_dev); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(mean: f64, std_dev: f64, eval: F) -> f64 diff --git a/src/distribution/mod.rs b/src/distribution/mod.rs index 56deb09a..72cc854d 100644 --- a/src/distribution/mod.rs +++ b/src/distribution/mod.rs @@ -71,8 +71,6 @@ mod weibull; mod ziggurat; mod ziggurat_tables; -use crate::Result; - /// The `ContinuousCDF` trait is used to specify an interface for univariate /// distributions for which cdf float arguments are sensible. pub trait ContinuousCDF: Min + Max { diff --git a/src/distribution/multinomial.rs b/src/distribution/multinomial.rs index dd17d2f0..3fd9cf8e 100644 --- a/src/distribution/multinomial.rs +++ b/src/distribution/multinomial.rs @@ -1,7 +1,6 @@ use crate::distribution::Discrete; use crate::function::factorial; use crate::statistics::*; -use crate::{Result, StatsError}; use ::nalgebra::{DMatrix, DVector}; use rand::Rng; @@ -46,16 +45,16 @@ impl Multinomial { /// use statrs::distribution::Multinomial; /// /// let mut result = Multinomial::new(&[0.0, 1.0, 2.0], 3); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Multinomial::new(&[0.0, -1.0, 2.0], 3); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(p: &[f64], n: u64) -> Result { + pub fn new(p: &[f64], n: u64) -> Option { if !super::internal::is_valid_multinomial(p, true) { - Err(StatsError::BadParams) + None } else { - Ok(Multinomial { p: p.to_vec(), n }) + Some(Multinomial { p: p.to_vec(), n }) } } @@ -253,7 +252,7 @@ impl<'a> Discrete<&'a [u64], f64> for Multinomial { // fn try_create(p: &[f64], n: u64) -> Multinomial { // let dist = Multinomial::new(p, n); -// assert!(dist.is_ok()); +// assert!(dist.is_some()); // dist.unwrap() // } @@ -265,7 +264,7 @@ impl<'a> Discrete<&'a [u64], f64> for Multinomial { // fn bad_create_case(p: &[f64], n: u64) { // let dist = Multinomial::new(p, n); -// assert!(dist.is_err()); +// assert!(dist.is_none()); // } // fn test_case(p: &[f64], n: u64, expected: &[f64], eval: F) diff --git a/src/distribution/multivariate_normal.rs b/src/distribution/multivariate_normal.rs index 993bb9ba..614d2103 100644 --- a/src/distribution/multivariate_normal.rs +++ b/src/distribution/multivariate_normal.rs @@ -1,7 +1,6 @@ use crate::distribution::Continuous; use crate::distribution::Normal; use crate::statistics::{Max, MeanN, Min, Mode, VarianceN}; -use crate::{Result, StatsError}; use nalgebra::{ base::allocator::Allocator, Cholesky, Const, DMatrix, DVector, DefaultAllocator, Dim, DimMin, Dyn, OMatrix, OVector, @@ -47,7 +46,7 @@ impl MultivariateNormal { /// /// Returns an error if the given covariance matrix is not /// symmetric or positive-definite - pub fn new(mean: Vec, cov: Vec) -> Result { + pub fn new(mean: Vec, cov: Vec) -> Option { let mean = DVector::from_vec(mean); let cov = DMatrix::from_vec(mean.len(), mean.len(), cov); MultivariateNormal::new_from_nalgebra(mean, cov) @@ -69,7 +68,7 @@ where /// /// Returns an error if the given covariance matrix is not /// symmetric or positive-definite - pub fn new_from_nalgebra(mean: OVector, cov: OMatrix) -> Result { + pub fn new_from_nalgebra(mean: OVector, cov: OMatrix) -> Option { // Check that the provided covariance matrix is symmetric if cov.lower_triangle() != cov.upper_triangle().transpose() // Check that mean and covariance do not contain NaN @@ -78,7 +77,7 @@ where // Check that the dimensions match || mean.nrows() != cov.nrows() || cov.nrows() != cov.ncols() { - return Err(StatsError::BadParams); + return None; } let cov_det = cov.determinant(); let pdf_const = ((2. * PI).powi(mean.nrows() as i32) * cov_det.abs()) @@ -87,10 +86,10 @@ where // Store the Cholesky decomposition of the covariance matrix // for sampling match Cholesky::new(cov.clone()) { - None => Err(StatsError::BadParams), + None => None, Some(cholesky_decomp) => { let precision = cholesky_decomp.inverse(); - Ok(MultivariateNormal { + Some(MultivariateNormal { cov_chol_decomp: cholesky_decomp.unpack(), mu: mean, cov, @@ -313,7 +312,7 @@ mod tests { + nalgebra::allocator::Allocator<(usize, usize), D>, { let mvn = MultivariateNormal::new_from_nalgebra(mean, covariance); - assert!(mvn.is_ok()); + assert!(mvn.is_some()); mvn.unwrap() } @@ -337,7 +336,7 @@ mod tests { + nalgebra::allocator::Allocator<(usize, usize), D>, { let mvn = MultivariateNormal::new_from_nalgebra(mean, covariance); - assert!(mvn.is_err()); + assert!(mvn.is_none()); } fn test_case( diff --git a/src/distribution/negative_binomial.rs b/src/distribution/negative_binomial.rs index 065c2239..fbc2855f 100644 --- a/src/distribution/negative_binomial.rs +++ b/src/distribution/negative_binomial.rs @@ -1,7 +1,6 @@ use crate::distribution::{self, poisson, Discrete, DiscreteCDF}; use crate::function::{beta, gamma}; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; use std::f64; @@ -59,16 +58,16 @@ impl NegativeBinomial { /// use statrs::distribution::NegativeBinomial; /// /// let mut result = NegativeBinomial::new(4.0, 0.5); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = NegativeBinomial::new(-0.5, 5.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(r: f64, p: f64) -> Result { + pub fn new(r: f64, p: f64) -> Option { if p.is_nan() || !(0.0..=1.0).contains(&p) || r.is_nan() || r < 0.0 { - Err(StatsError::BadParams) + None } else { - Ok(NegativeBinomial { r, p }) + Some(NegativeBinomial { r, p }) } } @@ -298,7 +297,7 @@ mod tests { fn try_create(r: f64, p: f64) -> NegativeBinomial { let r = NegativeBinomial::new(r, p); - assert!(r.is_ok()); + assert!(r.is_some()); r.unwrap() } @@ -310,7 +309,7 @@ mod tests { fn bad_create_case(r: f64, p: f64) { let r = NegativeBinomial::new(r, p); - assert!(r.is_err()); + assert!(r.is_none()); } fn get_value(r: f64, p: f64, eval: F) -> T diff --git a/src/distribution/normal.rs b/src/distribution/normal.rs index 94e8c6b6..5fef7e1e 100644 --- a/src/distribution/normal.rs +++ b/src/distribution/normal.rs @@ -1,7 +1,7 @@ +use crate::consts; use crate::distribution::{ziggurat, Continuous, ContinuousCDF}; use crate::function::erf; use crate::statistics::*; -use crate::{consts, Result, StatsError}; use rand::Rng; use std::f64; @@ -39,16 +39,16 @@ impl Normal { /// use statrs::distribution::Normal; /// /// let mut result = Normal::new(0.0, 1.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Normal::new(0.0, 0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(mean: f64, std_dev: f64) -> Result { + pub fn new(mean: f64, std_dev: f64) -> Option { if mean.is_nan() || std_dev.is_nan() || std_dev <= 0.0 { - Err(StatsError::BadParams) + None } else { - Ok(Normal { mean, std_dev }) + Some(Normal { mean, std_dev }) } } @@ -340,7 +340,7 @@ mod tests { fn try_create(mean: f64, std_dev: f64) -> Normal { let n = Normal::new(mean, std_dev); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -352,7 +352,7 @@ mod tests { fn bad_create_case(mean: f64, std_dev: f64) { let n = Normal::new(mean, std_dev); - assert!(n.is_err()); + assert!(n.is_none()); } fn test_case(mean: f64, std_dev: f64, expected: f64, eval: F) diff --git a/src/distribution/pareto.rs b/src/distribution/pareto.rs index 55df13a5..4f9e36dd 100644 --- a/src/distribution/pareto.rs +++ b/src/distribution/pareto.rs @@ -1,6 +1,5 @@ use crate::distribution::{Continuous, ContinuousCDF}; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::distributions::OpenClosed01; use rand::Rng; use std::f64; @@ -40,17 +39,17 @@ impl Pareto { /// use statrs::distribution::Pareto; /// /// let mut result = Pareto::new(1.0, 2.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Pareto::new(0.0, 0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(scale: f64, shape: f64) -> Result { + pub fn new(scale: f64, shape: f64) -> Option { let is_nan = scale.is_nan() || shape.is_nan(); if is_nan || scale <= 0.0 || shape <= 0.0 { - Err(StatsError::BadParams) + None } else { - Ok(Pareto { scale, shape }) + Some(Pareto { scale, shape }) } } @@ -342,7 +341,7 @@ mod tests { fn try_create(scale: f64, shape: f64) -> Pareto { let p = Pareto::new(scale, shape); - assert!(p.is_ok()); + assert!(p.is_some()); p.unwrap() } @@ -354,7 +353,7 @@ mod tests { fn bad_create_case(scale: f64, shape: f64) { let p = Pareto::new(scale, shape); - assert!(p.is_err()); + assert!(p.is_none()); } fn get_value(scale: f64, shape: f64, eval: F) -> T diff --git a/src/distribution/poisson.rs b/src/distribution/poisson.rs index 7653ed20..a5d93aa5 100644 --- a/src/distribution/poisson.rs +++ b/src/distribution/poisson.rs @@ -1,7 +1,6 @@ use crate::distribution::{Discrete, DiscreteCDF}; use crate::function::{factorial, gamma}; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; use std::f64; @@ -38,16 +37,16 @@ impl Poisson { /// use statrs::distribution::Poisson; /// /// let mut result = Poisson::new(1.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Poisson::new(0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(lambda: f64) -> Result { + pub fn new(lambda: f64) -> Option { if lambda.is_nan() || lambda <= 0.0 { - Err(StatsError::BadParams) + None } else { - Ok(Poisson { lambda }) + Some(Poisson { lambda }) } } @@ -311,7 +310,7 @@ mod tests { fn try_create(lambda: f64) -> Poisson { let n = Poisson::new(lambda); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -322,7 +321,7 @@ mod tests { fn bad_create_case(lambda: f64) { let n = Poisson::new(lambda); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(lambda: f64, eval: F) -> T diff --git a/src/distribution/students_t.rs b/src/distribution/students_t.rs index af7d7356..4e841074 100644 --- a/src/distribution/students_t.rs +++ b/src/distribution/students_t.rs @@ -2,7 +2,6 @@ use crate::distribution::{Continuous, ContinuousCDF}; use crate::function::{beta, gamma}; use crate::is_zero; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; use std::f64; @@ -43,17 +42,17 @@ impl StudentsT { /// use statrs::distribution::StudentsT; /// /// let mut result = StudentsT::new(0.0, 1.0, 2.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = StudentsT::new(0.0, 0.0, 0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(location: f64, scale: f64, freedom: f64) -> Result { + pub fn new(location: f64, scale: f64, freedom: f64) -> Option { let is_nan = location.is_nan() || scale.is_nan() || freedom.is_nan(); if is_nan || scale <= 0.0 || freedom <= 0.0 { - Err(StatsError::BadParams) + None } else { - Ok(StudentsT { + Some(StudentsT { location, scale, freedom, diff --git a/src/distribution/triangular.rs b/src/distribution/triangular.rs index 5fa89b70..c2f32abb 100644 --- a/src/distribution/triangular.rs +++ b/src/distribution/triangular.rs @@ -1,6 +1,5 @@ use crate::distribution::{Continuous, ContinuousCDF}; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::Rng; use std::f64; @@ -40,22 +39,22 @@ impl Triangular { /// use statrs::distribution::Triangular; /// /// let mut result = Triangular::new(0.0, 5.0, 2.5); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Triangular::new(2.5, 1.5, 0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(min: f64, max: f64, mode: f64) -> Result { + pub fn new(min: f64, max: f64, mode: f64) -> Option { if !min.is_finite() || !max.is_finite() || !mode.is_finite() { - return Err(StatsError::BadParams); + return None; } if max < mode || mode < min { - return Err(StatsError::BadParams); + return None; } if ulps_eq!(max, min, max_ulps = 0) { - return Err(StatsError::BadParams); + return None; } - Ok(Triangular { min, max, mode }) + Some(Triangular { min, max, mode }) } } @@ -326,7 +325,7 @@ mod tests { fn try_create(min: f64, max: f64, mode: f64) -> Triangular { let n = Triangular::new(min, max, mode); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -339,7 +338,7 @@ mod tests { fn bad_create_case(min: f64, max: f64, mode: f64) { let n = Triangular::new(min, max, mode); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(min: f64, max: f64, mode: f64, eval: F) -> T diff --git a/src/distribution/uniform.rs b/src/distribution/uniform.rs index 04578a58..53939f3d 100644 --- a/src/distribution/uniform.rs +++ b/src/distribution/uniform.rs @@ -1,6 +1,5 @@ use crate::distribution::{Continuous, ContinuousCDF}; use crate::statistics::*; -use crate::{Result, StatsError}; use rand::distributions::Uniform as RandUniform; use rand::Rng; use std::f64; @@ -41,25 +40,23 @@ impl Uniform { /// use std::f64; /// /// let mut result = Uniform::new(0.0, 1.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Uniform::new(f64::NAN, f64::NAN); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// /// result = Uniform::new(f64::NEG_INFINITY, 1.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(min: f64, max: f64) -> Result { - if min.is_nan() || max.is_nan() { - return Err(StatsError::BadParams); + pub fn new(min: f64, max: f64) -> Option { + if !min.is_finite() || !max.is_finite() { + return None; } - match (min.is_finite(), max.is_finite(), min < max) { - (false, false, _) => Err(StatsError::ArgFinite("min and max")), - (false, true, _) => Err(StatsError::ArgFinite("min")), - (true, false, _) => Err(StatsError::ArgFinite("max")), - (true, true, false) => Err(StatsError::ArgLteArg("min", "max")), - (true, true, true) => Ok(Uniform { min, max }), + if min < max { + Some(Uniform { min, max }) + } else { + None } } @@ -290,7 +287,7 @@ mod tests { fn try_create(min: f64, max: f64) -> Uniform { let n = Uniform::new(min, max); - assert!(n.is_ok(), "failed create over interval [{}, {}]", min, max); + assert!(n.is_some(), "failed create over interval [{}, {}]", min, max); n.unwrap() } @@ -302,7 +299,7 @@ mod tests { fn bad_create_case(min: f64, max: f64) { let n = Uniform::new(min, max); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(min: f64, max: f64, eval: F) -> f64 diff --git a/src/distribution/weibull.rs b/src/distribution/weibull.rs index 49dbc4d8..60be9086 100644 --- a/src/distribution/weibull.rs +++ b/src/distribution/weibull.rs @@ -1,8 +1,8 @@ +use crate::consts; use crate::distribution::{Continuous, ContinuousCDF}; use crate::function::gamma; use crate::is_zero; use crate::statistics::*; -use crate::{consts, Result, StatsError}; use rand::Rng; use std::f64; @@ -43,22 +43,25 @@ impl Weibull { /// use statrs::distribution::Weibull; /// /// let mut result = Weibull::new(10.0, 1.0); - /// assert!(result.is_ok()); + /// assert!(result.is_some()); /// /// result = Weibull::new(0.0, 0.0); - /// assert!(result.is_err()); + /// assert!(result.is_none()); /// ``` - pub fn new(shape: f64, scale: f64) -> Result { - let is_nan = shape.is_nan() || scale.is_nan(); - match (shape, scale, is_nan) { - (_, _, true) => Err(StatsError::BadParams), - (_, _, false) if shape <= 0.0 || scale <= 0.0 => Err(StatsError::BadParams), - (_, _, false) => Ok(Weibull { - shape, - scale, - scale_pow_shape_inv: scale.powf(-shape), - }), + pub fn new(shape: f64, scale: f64) -> Option { + if shape.is_nan() || scale.is_nan() { + return None; } + + if shape <= 0.0 || scale <= 0.0 { + return None; + } + + Some(Weibull { + shape, + scale, + scale_pow_shape_inv: scale.powf(-shape), + }) } /// Returns the shape of the weibull distribution @@ -339,7 +342,7 @@ mod tests { fn try_create(shape: f64, scale: f64) -> Weibull { let n = Weibull::new(shape, scale); - assert!(n.is_ok()); + assert!(n.is_some()); n.unwrap() } @@ -351,7 +354,7 @@ mod tests { fn bad_create_case(shape: f64, scale: f64) { let n = Weibull::new(shape, scale); - assert!(n.is_err()); + assert!(n.is_none()); } fn get_value(shape: f64, scale: f64, eval: F) -> f64 diff --git a/src/error.rs b/src/error.rs deleted file mode 100644 index e6f7ca40..00000000 --- a/src/error.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::error::Error; -use std::fmt; - -/// Enumeration of possible errors thrown within the `statrs` library -#[derive(Clone, PartialEq, Debug)] -pub enum StatsError { - /// Generic bad input parameter error - BadParams, - /// An argument must be finite - ArgFinite(&'static str), - /// An argument should have been positive and was not - ArgMustBePositive(&'static str), - /// An argument should have been non-negative and was not - ArgNotNegative(&'static str), - /// An argument should have fallen between an inclusive range but didn't - ArgIntervalIncl(&'static str, f64, f64), - /// An argument should have fallen between an exclusive range but didn't - ArgIntervalExcl(&'static str, f64, f64), - /// An argument should have fallen in a range excluding the min but didn't - ArgIntervalExclMin(&'static str, f64, f64), - /// An argument should have falled in a range excluding the max but didn't - ArgIntervalExclMax(&'static str, f64, f64), - /// An argument must have been greater than a value but wasn't - ArgGt(&'static str, f64), - /// An argument must have been greater than another argument but wasn't - ArgGtArg(&'static str, &'static str), - /// An argument must have been greater than or equal to a value but wasn't - ArgGte(&'static str, f64), - /// An argument must have been greater than or equal to another argument - /// but wasn't - ArgGteArg(&'static str, &'static str), - /// An argument must have been less than a value but wasn't - ArgLt(&'static str, f64), - /// An argument must have been less than another argument but wasn't - ArgLtArg(&'static str, &'static str), - /// An argument must have been less than or equal to a value but wasn't - ArgLte(&'static str, f64), - /// An argument must have been less than or equal to another argument but - /// wasn't - ArgLteArg(&'static str, &'static str), - /// Containers of the same length were expected - ContainersMustBeSameLength, - /// Computation failed to converge, - ComputationFailedToConverge, - /// Elements in a container were expected to sum to a value but didn't - ContainerExpectedSum(&'static str, f64), - /// Elements in a container were expected to sum to a variable but didn't - ContainerExpectedSumVar(&'static str, &'static str), - /// Special case exception - SpecialCase(&'static str), -} - -impl Error for StatsError {} - -impl fmt::Display for StatsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - StatsError::BadParams => write!(f, "Bad distribution parameters"), - StatsError::ArgFinite(s) => write!(f, "Argument {} must be finite", s), - StatsError::ArgMustBePositive(s) => write!(f, "Argument {} must be positive", s), - StatsError::ArgNotNegative(s) => write!(f, "Argument {} must be non-negative", s), - StatsError::ArgIntervalIncl(s, min, max) => { - write!(f, "Argument {} not within interval [{}, {}]", s, min, max) - } - StatsError::ArgIntervalExcl(s, min, max) => { - write!(f, "Argument {} not within interval ({}, {})", s, min, max) - } - StatsError::ArgIntervalExclMin(s, min, max) => { - write!(f, "Argument {} not within interval ({}, {}]", s, min, max) - } - StatsError::ArgIntervalExclMax(s, min, max) => { - write!(f, "Argument {} not within interval [{}, {})", s, min, max) - } - StatsError::ArgGt(s, val) => write!(f, "Argument {} must be greater than {}", s, val), - StatsError::ArgGtArg(s, val) => { - write!(f, "Argument {} must be greater than {}", s, val) - } - StatsError::ArgGte(s, val) => { - write!(f, "Argument {} must be greater than or equal to {}", s, val) - } - StatsError::ArgGteArg(s, val) => { - write!(f, "Argument {} must be greater than or equal to {}", s, val) - } - StatsError::ArgLt(s, val) => write!(f, "Argument {} must be less than {}", s, val), - StatsError::ArgLtArg(s, val) => write!(f, "Argument {} must be less than {}", s, val), - StatsError::ArgLte(s, val) => { - write!(f, "Argument {} must be less than or equal to {}", s, val) - } - StatsError::ArgLteArg(s, val) => { - write!(f, "Argument {} must be less than or equal to {}", s, val) - } - StatsError::ContainersMustBeSameLength => { - write!(f, "Expected containers of same length") - } - StatsError::ComputationFailedToConverge => write!(f, "Computation failed to converge"), - StatsError::ContainerExpectedSum(s, sum) => { - write!(f, "Elements in container {} expected to sum to {}", s, sum) - } - StatsError::ContainerExpectedSumVar(s, sum) => { - write!(f, "Elements in container {} expected to sum to {}", s, sum) - } - StatsError::SpecialCase(s) => write!(f, "{}", s), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn assert_sync() {} - fn assert_send() {} - - #[test] - fn test_sync_send() { - // Error types should implement Sync and Send - assert_sync::(); - assert_send::(); - } -} diff --git a/src/function/beta.rs b/src/function/beta.rs index 128406c7..f3bd3123 100644 --- a/src/function/beta.rs +++ b/src/function/beta.rs @@ -1,11 +1,9 @@ //! Provides the [beta](https://en.wikipedia.org/wiki/Beta_function) and related //! function -use crate::error::StatsError; use crate::function::gamma; use crate::is_zero; use crate::prec; -use crate::Result; use std::f64; /// Computes the natural logarithm @@ -30,13 +28,11 @@ pub fn ln_beta(a: f64, b: f64) -> f64 { /// # Errors /// /// if `a <= 0.0` or `b <= 0.0` -pub fn checked_ln_beta(a: f64, b: f64) -> Result { - if a <= 0.0 { - Err(StatsError::ArgMustBePositive("a")) - } else if b <= 0.0 { - Err(StatsError::ArgMustBePositive("b")) +pub fn checked_ln_beta(a: f64, b: f64) -> Option { + if a <= 0.0 || b <= 0.0 { + None } else { - Ok(gamma::ln_gamma(a) + gamma::ln_gamma(b) - gamma::ln_gamma(a + b)) + Some(gamma::ln_gamma(a) + gamma::ln_gamma(b) - gamma::ln_gamma(a + b)) } } @@ -60,7 +56,7 @@ pub fn beta(a: f64, b: f64) -> f64 { /// # Errors /// /// if `a <= 0.0` or `b <= 0.0` -pub fn checked_beta(a: f64, b: f64) -> Result { +pub fn checked_beta(a: f64, b: f64) -> Option { checked_ln_beta(a, b).map(|x| x.exp()) } @@ -84,7 +80,7 @@ pub fn beta_inc(a: f64, b: f64, x: f64) -> f64 { /// # Errors /// /// If `a <= 0.0`, `b <= 0.0`, `x < 0.0`, or `x > 1.0` -pub fn checked_beta_inc(a: f64, b: f64, x: f64) -> Result { +pub fn checked_beta_inc(a: f64, b: f64, x: f64) -> Option { checked_beta_reg(a, b, x).and_then(|x| checked_beta(a, b).map(|y| x * y)) } @@ -110,13 +106,9 @@ pub fn beta_reg(a: f64, b: f64, x: f64) -> f64 { /// # Errors /// /// if `a <= 0.0`, `b <= 0.0`, `x < 0.0`, or `x > 1.0` -pub fn checked_beta_reg(a: f64, b: f64, x: f64) -> Result { - if a <= 0.0 { - Err(StatsError::ArgMustBePositive("a")) - } else if b <= 0.0 { - Err(StatsError::ArgMustBePositive("b")) - } else if !(0.0..=1.0).contains(&x) { - Err(StatsError::ArgIntervalIncl("x", 0.0, 1.0)) +pub fn checked_beta_reg(a: f64, b: f64, x: f64) -> Option { + if a <= 0.0 || b <= 0.0 || !(0.0..=1.0).contains(&x) { + None } else { let bt = if is_zero(x) || ulps_eq!(x, 1.0) { 0.0 @@ -188,17 +180,17 @@ pub fn checked_beta_reg(a: f64, b: f64, x: f64) -> Result { if (del - 1.0).abs() <= eps { return if symm_transform { - Ok(1.0 - bt * h / a) + Some(1.0 - bt * h / a) } else { - Ok(bt * h / a) + Some(bt * h / a) }; } } if symm_transform { - Ok(1.0 - bt * h / a) + Some(1.0 - bt * h / a) } else { - Ok(bt * h / a) + Some(bt * h / a) } } } @@ -424,12 +416,12 @@ mod tests { #[test] fn test_checked_ln_beta_a_lte_0() { - assert!(super::checked_ln_beta(0.0, 0.5).is_err()); + assert!(super::checked_ln_beta(0.0, 0.5).is_none()); } #[test] fn test_checked_ln_beta_b_lte_0() { - assert!(super::checked_ln_beta(0.5, 0.0).is_err()); + assert!(super::checked_ln_beta(0.5, 0.0).is_none()); } #[test] @@ -446,12 +438,12 @@ mod tests { #[test] fn test_checked_beta_a_lte_0() { - assert!(super::checked_beta(0.0, 0.5).is_err()); + assert!(super::checked_beta(0.0, 0.5).is_none()); } #[test] fn test_checked_beta_b_lte_0() { - assert!(super::checked_beta(0.5, 0.0).is_err()); + assert!(super::checked_beta(0.5, 0.0).is_none()); } #[test] @@ -515,22 +507,22 @@ mod tests { #[test] fn test_checked_beta_inc_a_lte_0() { - assert!(super::checked_beta_inc(0.0, 1.0, 1.0).is_err()); + assert!(super::checked_beta_inc(0.0, 1.0, 1.0).is_none()); } #[test] fn test_checked_beta_inc_b_lte_0() { - assert!(super::checked_beta_inc(1.0, 0.0, 1.0).is_err()); + assert!(super::checked_beta_inc(1.0, 0.0, 1.0).is_none()); } #[test] fn test_checked_beta_inc_x_lt_0() { - assert!(super::checked_beta_inc(1.0, 1.0, -1.0).is_err()); + assert!(super::checked_beta_inc(1.0, 1.0, -1.0).is_none()); } #[test] fn test_checked_beta_inc_x_gt_1() { - assert!(super::checked_beta_inc(1.0, 1.0, 2.0).is_err()); + assert!(super::checked_beta_inc(1.0, 1.0, 2.0).is_none()); } #[test] @@ -581,21 +573,21 @@ mod tests { #[test] fn test_checked_beta_reg_a_lte_0() { - assert!(super::checked_beta_reg(0.0, 1.0, 1.0).is_err()); + assert!(super::checked_beta_reg(0.0, 1.0, 1.0).is_none()); } #[test] fn test_checked_beta_reg_b_lte_0() { - assert!(super::checked_beta_reg(1.0, 0.0, 1.0).is_err()); + assert!(super::checked_beta_reg(1.0, 0.0, 1.0).is_none()); } #[test] fn test_checked_beta_reg_x_lt_0() { - assert!(super::checked_beta_reg(1.0, 1.0, -1.0).is_err()); + assert!(super::checked_beta_reg(1.0, 1.0, -1.0).is_none()); } #[test] fn test_checked_beta_reg_x_gt_1() { - assert!(super::checked_beta_reg(1.0, 1.0, 2.0).is_err()); + assert!(super::checked_beta_reg(1.0, 1.0, 2.0).is_none()); } } diff --git a/src/function/exponential.rs b/src/function/exponential.rs index 1124c55c..dfc2316a 100644 --- a/src/function/exponential.rs +++ b/src/function/exponential.rs @@ -1,6 +1,6 @@ //! Provides functions related to exponential calculations -use crate::{consts, Result, StatsError}; +use crate::consts; /// Computes the generalized Exponential Integral function /// where `x` is the argument and `n` is the integer power of the @@ -34,7 +34,7 @@ use crate::{consts, Result, StatsError}; /// /// ``` /// ``` -pub fn integral(x: f64, n: u64) -> Result { +pub fn integral(x: f64, n: u64) -> Option { let eps = 0.00000000000000001; let max_iter = 100; let nf64 = n as f64; @@ -42,10 +42,10 @@ pub fn integral(x: f64, n: u64) -> Result { // special cases if n == 0 { - return Ok((-1.0 * x).exp() / x); + return Some((-1.0 * x).exp() / x); } if x == 0.0 { - return Ok(1.0 / (nf64 - 1.0)); + return Some(1.0 / (nf64 - 1.0)); } if x > 1.0 { @@ -61,10 +61,10 @@ pub fn integral(x: f64, n: u64) -> Result { let del = c * d; h *= del; if (del - 1.0).abs() < eps { - return Ok(h * (-x).exp()); + return Some(h * (-x).exp()); } } - Err(StatsError::ComputationFailedToConverge) + None } else { let mut factorial = 1.0; let mut result = if n - 1 != 0 { @@ -85,10 +85,10 @@ pub fn integral(x: f64, n: u64) -> Result { }; result += del; if del.abs() < result.abs() * eps { - return Ok(result); + return Some(result); } } - Err(StatsError::ComputationFailedToConverge) + None } } diff --git a/src/function/factorial.rs b/src/function/factorial.rs index 77bcaa5b..c7033e5a 100644 --- a/src/function/factorial.rs +++ b/src/function/factorial.rs @@ -1,9 +1,7 @@ //! Provides functions related to factorial calculations (e.g. binomial //! coefficient, factorial, multinomial) -use crate::error::StatsError; use crate::function::gamma; -use crate::Result; /// The maximum factorial representable /// by a 64-bit floating point without @@ -77,14 +75,14 @@ pub fn multinomial(n: u64, ni: &[u64]) -> f64 { /// # Errors /// /// If the elements in `ni` do not sum to `n` -pub fn checked_multinomial(n: u64, ni: &[u64]) -> Result { +pub fn checked_multinomial(n: u64, ni: &[u64]) -> Option { let (sum, ret) = ni.iter().fold((0, ln_factorial(n)), |acc, &x| { (acc.0 + x, acc.1 - ln_factorial(x)) }); if sum != n { - Err(StatsError::ContainerExpectedSumVar("ni", "n")) + None } else { - Ok((0.5 + ret.exp()).floor()) + Some((0.5 + ret.exp()).floor()) } } @@ -179,6 +177,6 @@ mod tests { #[test] fn test_checked_multinomial_bad_ni() { - assert!(checked_multinomial(1, &[1, 1]).is_err()); + assert!(checked_multinomial(1, &[1, 1]).is_none()); } } diff --git a/src/function/gamma.rs b/src/function/gamma.rs index 9d5124f9..0391c3ca 100644 --- a/src/function/gamma.rs +++ b/src/function/gamma.rs @@ -2,10 +2,8 @@ //! related functions use crate::consts; -use crate::error::StatsError; use crate::is_zero; use crate::prec; -use crate::Result; use std::f64; /// Auxiliary variable when evaluating the `gamma_ln` function @@ -105,7 +103,7 @@ pub fn gamma_ui(a: f64, x: f64) -> f64 { /// # Errors /// /// if `a` or `x` are not in `(0, +inf)` -pub fn checked_gamma_ui(a: f64, x: f64) -> Result { +pub fn checked_gamma_ui(a: f64, x: f64) -> Option { checked_gamma_ur(a, x).map(|x| x * gamma(a)) } @@ -131,7 +129,7 @@ pub fn gamma_li(a: f64, x: f64) -> f64 { /// # Errors /// /// if `a` or `x` are not in `(0, +inf)` -pub fn checked_gamma_li(a: f64, x: f64) -> Result { +pub fn checked_gamma_li(a: f64, x: f64) -> Option { checked_gamma_lr(a, x).map(|x| x * gamma(a)) } @@ -163,15 +161,15 @@ pub fn gamma_ur(a: f64, x: f64) -> f64 { /// # Errors /// /// if `a` or `x` are not in `(0, +inf)` -pub fn checked_gamma_ur(a: f64, x: f64) -> Result { +pub fn checked_gamma_ur(a: f64, x: f64) -> Option { if a.is_nan() || x.is_nan() { - return Ok(f64::NAN); + return Some(f64::NAN); } if a <= 0.0 || a == f64::INFINITY { - return Err(StatsError::ArgIntervalExcl("a", 0.0, f64::INFINITY)); + return None; } if x <= 0.0 || x == f64::INFINITY { - return Err(StatsError::ArgIntervalExcl("x", 0.0, f64::INFINITY)); + return None; } let eps = 0.000000000000001; @@ -179,12 +177,12 @@ pub fn checked_gamma_ur(a: f64, x: f64) -> Result { let big_inv = 2.22044604925031308085e-16; if x < 1.0 || x <= a { - return Ok(1.0 - gamma_lr(a, x)); + return Some(1.0 - gamma_lr(a, x)); } let mut ax = a * x.ln() - x - ln_gamma(a); if ax < -709.78271289338399 { - return if a < x { Ok(0.0) } else { Ok(1.0) }; + return if a < x { Some(0.0) } else { Some(1.0) }; } ax = ax.exp(); @@ -226,7 +224,7 @@ pub fn checked_gamma_ur(a: f64, x: f64) -> Result { } } } - Ok(ans * ax) + Some(ans * ax) } /// Computes the lower incomplete regularized gamma function @@ -257,15 +255,15 @@ pub fn gamma_lr(a: f64, x: f64) -> f64 { /// # Errors /// /// if `a` or `x` are not in `(0, +inf)` -pub fn checked_gamma_lr(a: f64, x: f64) -> Result { +pub fn checked_gamma_lr(a: f64, x: f64) -> Option { if a.is_nan() || x.is_nan() { - return Ok(f64::NAN); + return Some(f64::NAN); } if a <= 0.0 || a == f64::INFINITY { - return Err(StatsError::ArgIntervalExcl("a", 0.0, f64::INFINITY)); + return None; } if x <= 0.0 || x == f64::INFINITY { - return Err(StatsError::ArgIntervalExcl("x", 0.0, f64::INFINITY)); + return None; } let eps = 0.000000000000001; @@ -273,18 +271,18 @@ pub fn checked_gamma_lr(a: f64, x: f64) -> Result { let big_inv = 2.22044604925031308085e-16; if prec::almost_eq(a, 0.0, prec::DEFAULT_F64_ACC) { - return Ok(1.0); + return Some(1.0); } if prec::almost_eq(x, 0.0, prec::DEFAULT_F64_ACC) { - return Ok(0.0); + return Some(0.0); } let ax = a * x.ln() - x - ln_gamma(a); if ax < -709.78271289338399 { if a < x { - return Ok(1.0); + return Some(1.0); } - return Ok(0.0); + return Some(0.0); } if x <= 1.0 || x <= a { let mut r2 = a; @@ -299,7 +297,7 @@ pub fn checked_gamma_lr(a: f64, x: f64) -> Result { break; } } - return Ok(ax.exp() * ans2 / a); + return Some(ax.exp() * ans2 / a); } let mut y = 1.0 - a; @@ -343,7 +341,7 @@ pub fn checked_gamma_lr(a: f64, x: f64) -> Result { } } } - Ok(1.0 - ax.exp() * ans) + Some(1.0 - ax.exp() * ans) } /// Computes the Digamma function which is defined as the derivative of @@ -546,22 +544,22 @@ mod tests { #[test] fn test_checked_gamma_lr_a_lower_bound() { - assert!(super::checked_gamma_lr(-1.0, 1.0).is_err()); + assert!(super::checked_gamma_lr(-1.0, 1.0).is_none()); } #[test] fn test_checked_gamma_lr_a_upper_bound() { - assert!(super::checked_gamma_lr(f64::INFINITY, 1.0).is_err()); + assert!(super::checked_gamma_lr(f64::INFINITY, 1.0).is_none()); } #[test] fn test_checked_gamma_lr_x_lower_bound() { - assert!(super::checked_gamma_lr(1.0, -1.0).is_err()); + assert!(super::checked_gamma_lr(1.0, -1.0).is_none()); } #[test] fn test_checked_gamma_lr_x_upper_bound() { - assert!(super::checked_gamma_lr(1.0, f64::INFINITY).is_err()); + assert!(super::checked_gamma_lr(1.0, f64::INFINITY).is_none()); } #[test] @@ -607,22 +605,22 @@ mod tests { #[test] fn test_checked_gamma_li_a_lower_bound() { - assert!(super::checked_gamma_li(-1.0, 1.0).is_err()); + assert!(super::checked_gamma_li(-1.0, 1.0).is_none()); } #[test] fn test_checked_gamma_li_a_upper_bound() { - assert!(super::checked_gamma_li(f64::INFINITY, 1.0).is_err()); + assert!(super::checked_gamma_li(f64::INFINITY, 1.0).is_none()); } #[test] fn test_checked_gamma_li_x_lower_bound() { - assert!(super::checked_gamma_li(1.0, -1.0).is_err()); + assert!(super::checked_gamma_li(1.0, -1.0).is_none()); } #[test] fn test_checked_gamma_li_x_upper_bound() { - assert!(super::checked_gamma_li(1.0, f64::INFINITY).is_err()); + assert!(super::checked_gamma_li(1.0, f64::INFINITY).is_none()); } // TODO: precision testing could be more accurate, borrowed wholesale from Math.NET @@ -685,22 +683,22 @@ mod tests { #[test] fn test_checked_gamma_ur_a_lower_bound() { - assert!(super::checked_gamma_ur(-1.0, 1.0).is_err()); + assert!(super::checked_gamma_ur(-1.0, 1.0).is_none()); } #[test] fn test_checked_gamma_ur_a_upper_bound() { - assert!(super::checked_gamma_ur(f64::INFINITY, 1.0).is_err()); + assert!(super::checked_gamma_ur(f64::INFINITY, 1.0).is_none()); } #[test] fn test_checked_gamma_ur_x_lower_bound() { - assert!(super::checked_gamma_ur(1.0, -1.0).is_err()); + assert!(super::checked_gamma_ur(1.0, -1.0).is_none()); } #[test] fn test_checked_gamma_ur_x_upper_bound() { - assert!(super::checked_gamma_ur(1.0, f64::INFINITY).is_err()); + assert!(super::checked_gamma_ur(1.0, f64::INFINITY).is_none()); } #[test] @@ -746,22 +744,22 @@ mod tests { #[test] fn test_checked_gamma_ui_a_lower_bound() { - assert!(super::checked_gamma_ui(-1.0, 1.0).is_err()); + assert!(super::checked_gamma_ui(-1.0, 1.0).is_none()); } #[test] fn test_checked_gamma_ui_a_upper_bound() { - assert!(super::checked_gamma_ui(f64::INFINITY, 1.0).is_err()); + assert!(super::checked_gamma_ui(f64::INFINITY, 1.0).is_none()); } #[test] fn test_checked_gamma_ui_x_lower_bound() { - assert!(super::checked_gamma_ui(1.0, -1.0).is_err()); + assert!(super::checked_gamma_ui(1.0, -1.0).is_none()); } #[test] fn test_checked_gamma_ui_x_upper_bound() { - assert!(super::checked_gamma_ui(1.0, f64::INFINITY).is_err()); + assert!(super::checked_gamma_ui(1.0, f64::INFINITY).is_none()); } // TODO: precision testing could be more accurate diff --git a/src/function/logistic.rs b/src/function/logistic.rs index 8adc8b79..09f3c131 100644 --- a/src/function/logistic.rs +++ b/src/function/logistic.rs @@ -1,9 +1,6 @@ //! Provides the [logistic](http://en.wikipedia.org/wiki/Logistic_function) and //! related functions -use crate::error::StatsError; -use crate::Result; - /// Computes the logistic function pub fn logistic(p: f64) -> f64 { 1.0 / ((-p).exp() + 1.0) @@ -23,11 +20,11 @@ pub fn logit(p: f64) -> f64 { /// # Errors /// /// If `p < 0.0` or `p > 1.0` -pub fn checked_logit(p: f64) -> Result { +pub fn checked_logit(p: f64) -> Option { if !(0.0..=1.0).contains(&p) { - Err(StatsError::ArgIntervalIncl("p", 0.0, 1.0)) + None } else { - Ok((p / (1.0 - p)).ln()) + Some((p / (1.0 - p)).ln()) } } @@ -76,11 +73,11 @@ mod tests { #[test] fn test_checked_logit_p_lt_0() { - assert!(super::checked_logit(-1.0).is_err()); + assert!(super::checked_logit(-1.0).is_none()); } #[test] fn test_checked_logit_p_gt_1() { - assert!(super::checked_logit(2.0).is_err()); + assert!(super::checked_logit(2.0).is_none()); } } diff --git a/src/lib.rs b/src/lib.rs index a87f8ef9..9297cf3f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,16 +75,8 @@ pub mod prec; pub mod statistics; pub mod stats_tests; -mod error; - // function to silence clippy on the special case when comparing to zero. #[inline(always)] pub(crate) fn is_zero(x: f64) -> bool { ulps_eq!(x, 0.0, max_ulps = 0) } - -pub use crate::error::StatsError; - -/// Result type for the statrs library package that returns -/// either a result type `T` or a `StatsError` -pub type Result = std::result::Result; diff --git a/src/statistics/iter_statistics.rs b/src/statistics/iter_statistics.rs index e568e531..f4793a6d 100644 --- a/src/statistics/iter_statistics.rs +++ b/src/statistics/iter_statistics.rs @@ -1,4 +1,3 @@ -use crate::error::StatsError; use crate::statistics::*; use std::borrow::Borrow; use std::f64; @@ -175,7 +174,7 @@ where for x in self { let borrow = *x.borrow(); let borrow2 = match iter.next() { - None => panic!("{}", StatsError::ContainersMustBeSameLength), + None => panic!("Containers must be of the same length"), Some(x) => *x.borrow(), }; let old_mean2 = mean2; @@ -185,7 +184,7 @@ where comoment += (borrow - mean1) * (borrow2 - old_mean2); } if iter.next().is_some() { - panic!("{}", StatsError::ContainersMustBeSameLength); + panic!("Containers must be of the same length"); } if n > 1.0 { @@ -205,7 +204,7 @@ where for x in self { let borrow = *x.borrow(); let borrow2 = match iter.next() { - None => panic!("{}", StatsError::ContainersMustBeSameLength), + None => panic!("Containers must be of the same length"), Some(x) => *x.borrow(), }; let old_mean2 = mean2; @@ -215,7 +214,7 @@ where comoment += (borrow - mean1) * (borrow2 - old_mean2); } if iter.next().is_some() { - panic!("{}", StatsError::ContainersMustBeSameLength) + panic!("Containers must be of the same length"); } if n > 0.0 { comoment / n diff --git a/src/stats_tests/fisher.rs b/src/stats_tests/fisher.rs index a18c821d..e3b88caf 100644 --- a/src/stats_tests/fisher.rs +++ b/src/stats_tests/fisher.rs @@ -1,6 +1,5 @@ use super::Alternative; use crate::distribution::{Discrete, DiscreteCDF, Hypergeometric}; -use crate::StatsError; const EPSILON: f64 = 1.0 - 1e-4; @@ -112,12 +111,12 @@ fn binary_search( pub fn fishers_exact_with_odds_ratio( table: &[u64; 4], alternative: Alternative, -) -> Result<(f64, f64), StatsError> { +) -> Option<(f64, f64)> { // If both values in a row or column are zero, p-value is 1 and odds ratio is NaN. match table { - [0, _, 0, _] | [_, 0, _, 0] => return Ok((f64::NAN, 1.0)), // both 0 in a row - [0, 0, _, _] | [_, _, 0, 0] => return Ok((f64::NAN, 1.0)), // both 0 in a column - _ => (), // continue + [0, _, 0, _] | [_, 0, _, 0] => return Some((f64::NAN, 1.0)), // both 0 in a row + [0, 0, _, _] | [_, _, 0, 0] => return Some((f64::NAN, 1.0)), // both 0 in a column + _ => (), // continue } let odds_ratio = { @@ -129,7 +128,7 @@ pub fn fishers_exact_with_odds_ratio( }; let p_value = fishers_exact(table, alternative)?; - Ok((odds_ratio, p_value)) + Some((odds_ratio, p_value)) } /// Perform a Fisher exact test on a 2x2 contingency table. @@ -144,12 +143,12 @@ pub fn fishers_exact_with_odds_ratio( /// let table = [3, 5, 4, 50]; /// let p_value = fishers_exact(&table, Alternative::Less).unwrap(); /// ``` -pub fn fishers_exact(table: &[u64; 4], alternative: Alternative) -> Result { +pub fn fishers_exact(table: &[u64; 4], alternative: Alternative) -> Option { // If both values in a row or column are zero, the p-value is 1 and the odds ratio is NaN. match table { - [0, _, 0, _] | [_, 0, _, 0] => return Ok(1.0), // both 0 in a row - [0, 0, _, _] | [_, _, 0, 0] => return Ok(1.0), // both 0 in a column - _ => (), // continue + [0, _, 0, _] | [_, 0, _, 0] => return Some(1.0), // both 0 in a row + [0, 0, _, _] | [_, _, 0, 0] => return Some(1.0), // both 0 in a column + _ => (), // continue } let n1 = table[0] + table[1]; @@ -180,21 +179,21 @@ pub fn fishers_exact(table: &[u64; 4], alternative: Alternative) -> Result p_exact / EPSILON { - return Ok(p_lower); + return Some(p_lower); } let guess = binary_search(n, n1, n2, mode, p_exact, EPSILON, true); - return Ok(p_lower + 1.0 - dist.cdf(guess - 1)); + return Some(p_lower + 1.0 - dist.cdf(guess - 1)); } let p_upper = 1.0 - dist.cdf(table[0] - 1); if dist.pmf(0) > p_exact / EPSILON { - return Ok(p_upper); + return Some(p_upper); } let guess = binary_search(n, n1, n2, mode, p_exact, EPSILON, false); @@ -203,7 +202,7 @@ pub fn fishers_exact(table: &[u64; 4], alternative: Alternative) -> Result Result { +fn parse_certified_value(line: String) -> f64 { line.chars() .skip_while(|&c| c != ':') .skip(1) // skip through ':' delimiter @@ -104,7 +103,7 @@ fn parse_certified_value(line: String) -> Result { .take_while(|&c| matches!(c, '0'..='9' | '-' | '.')) .collect::() .parse::() - .map_err(|e| e.into()) + .expect("can parse value as f64") } fn parse_file(path: impl AsRef) -> anyhow::Result { @@ -112,9 +111,9 @@ fn parse_file(path: impl AsRef) -> anyhow::Result { let reader = BufReader::new(f); let mut lines = reader.lines(); - let mean = parse_certified_value(lines.next().expect("file should not be exhausted")?)?; - let std_dev = parse_certified_value(lines.next().expect("file should not be exhausted")?)?; - let corr = parse_certified_value(lines.next().expect("file should not be exhausted")?)?; + let mean = parse_certified_value(lines.next().expect("file should not be exhausted")?); + let std_dev = parse_certified_value(lines.next().expect("file should not be exhausted")?); + let corr = parse_certified_value(lines.next().expect("file should not be exhausted")?); Ok(TestCase { certified: CertifiedValues {