Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,9 @@ features = ["macros"]
level = "warn"
# Set by cargo-llvm-cov when running on nightly
check-cfg = ['cfg(coverage_nightly)']

[package.metadata.docs.rs]
rustdoc-args = [
"--html-in-header",
"./katex-header.html"
]
4 changes: 4 additions & 0 deletions Makefile.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[tasks.doc-katex]
env = { "RUSTDOCFLAGS" = "--html-in-header katex-header.html" }
command = "cargo"
args = ["doc", "--no-deps"]
13 changes: 13 additions & 0 deletions katex-header.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/katex.min.css" integrity="sha384-9eLZqc9ds8eNjO3TmqPeYcDj8n+Qfa4nuSiGYa6DjLNcv9BtN69ZIulL9+8CqC9Y" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/katex.min.js" integrity="sha384-K3vbOmF2BtaVai+Qk37uypf7VrgBubhQreNQe9aGsz9lB63dIFiQVlJbr92dw2Lx" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/katex@0.10.0/dist/contrib/auto-render.min.js" integrity="sha384-kmZOZB5ObwgQnS/DuDg6TScgOiWWBiVt0plIRkZCmE6rDZGrEOQeHM5PcHi+nyqe" crossorigin="anonymous"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
delimiters: [
{left: "\\(", right: "\\)", display: false},
{left: "\\[", right: "\\]", display: true},
]
});
});
</script>
2 changes: 1 addition & 1 deletion src/distribution/geometric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl std::fmt::Display for Geometric {
#[cfg(feature = "rand")]
impl ::rand::distributions::Distribution<f64> for Geometric {
fn sample<R: ::rand::Rng + ?Sized>(&self, r: &mut R) -> f64 {
use ::rand::distributions::OpenClosed01;
use rand::distributions::OpenClosed01;

if ulps_eq!(self.p, 1.0) {
1.0
Expand Down
10 changes: 5 additions & 5 deletions src/distribution/laplace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,8 +553,8 @@ mod tests {
#[cfg(feature = "rand")]
#[test]
fn test_sample() {
use ::rand::distributions::Distribution;
use ::rand::thread_rng;
use rand::distributions::Distribution;
use rand::thread_rng;

let l = create_ok(0.1, 0.5);
l.sample(&mut thread_rng());
Expand All @@ -563,9 +563,9 @@ mod tests {
#[cfg(feature = "rand")]
#[test]
fn test_sample_distribution() {
use ::rand::distributions::Distribution;
use ::rand::rngs::StdRng;
use ::rand::SeedableRng;
use rand::distributions::Distribution;
use rand::rngs::StdRng;
use rand::SeedableRng;

// sanity check sampling
let location = 0.0;
Expand Down
9 changes: 6 additions & 3 deletions src/distribution/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
//! Defines common interfaces for interacting with statistical distributions
//! and provides
//! concrete implementations for a variety of distributions.
use super::statistics::{Max, Min};
use ::num_traits::{Float, Num};
use num_traits::NumAssignOps;
use crate::statistics::{Max, Min};
use num_traits::{Float, Num, NumAssignOps};

pub use self::bernoulli::Bernoulli;
pub use self::beta::{Beta, BetaError};
Expand Down Expand Up @@ -41,6 +40,8 @@ pub use self::triangular::{Triangular, TriangularError};
pub use self::uniform::{Uniform, UniformError};
pub use self::weibull::{Weibull, WeibullError};

pub use self::noncentral_students_t::{NoncentralStudentsT, NoncentralStudentsTError};

mod bernoulli;
mod beta;
mod binomial;
Expand Down Expand Up @@ -83,6 +84,8 @@ mod ziggurat;
#[cfg(feature = "rand")]
mod ziggurat_tables;

mod noncentral_students_t;

/// The `ContinuousCDF` trait is used to specify an interface for univariate
/// distributions for which cdf float arguments are sensible.
pub trait ContinuousCDF<K: Float, T: Float>: Min<K> + Max<K> {
Expand Down
190 changes: 190 additions & 0 deletions src/distribution/noncentral_students_t.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
use crate::distribution::{Continuous, ContinuousCDF};
use crate::function::{beta, gamma};
use crate::statistics::{Max, Min};

/// the non-central students T distribution
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct NoncentralStudentsT {
location: f64,
scale: f64,
freedom: f64,
}

/// Represents the errors that can occur when creating a [`NoncentralStudentsT`].
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
#[non_exhaustive]
pub enum NoncentralStudentsTError {
/// The location is NaN.
LocationInvalid,

/// The scale is NaN, zero or less than zero.
ScaleInvalid,

/// The degrees of freedom are NaN, zero or less than zero.
FreedomInvalid,
}

impl std::fmt::Display for NoncentralStudentsTError {
#[cfg_attr(coverage_nightly, coverage(off))]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
NoncentralStudentsTError::LocationInvalid => write!(f, "Location is NaN"),
NoncentralStudentsTError::ScaleInvalid => {
write!(f, "Scale is NaN, zero or less than zero")
}
NoncentralStudentsTError::FreedomInvalid => {
write!(f, "Degrees of freedom are NaN, zero or less than zero")
}
}
}
}

impl std::error::Error for NoncentralStudentsTError {}

impl NoncentralStudentsT {
/// Constructs a new student's t-distribution with location `location`,
/// scale `scale`, and `freedom` freedom.
///
/// # Errors
///
/// Returns an error if any of `location`, `scale`, or `freedom` are `NaN`.
/// Returns an error if `scale <= 0.0` or `freedom <= 0.0`.
///
/// # Examples
///
/// ```
/// use statrs::distribution::NoncentralStudentsT;
///
/// let mut result = NoncentralStudentsT::new(0.0, 1.0, 2.0);
/// assert!(result.is_ok());
///
/// result = NoncentralStudentsT::new(0.0, 0.0, 0.0);
/// assert!(result.is_err());
/// ```
pub fn new(
location: f64,
scale: f64,
freedom: f64,
) -> Result<NoncentralStudentsT, NoncentralStudentsTError> {
if location.is_nan() {
return Err(NoncentralStudentsTError::LocationInvalid);
}

if scale.is_nan() || scale <= 0.0 {
return Err(NoncentralStudentsTError::ScaleInvalid);
}

if freedom.is_nan() || freedom <= 0.0 {
return Err(NoncentralStudentsTError::FreedomInvalid);
}

Ok(NoncentralStudentsT {
location,
scale,
freedom,
})
}

/// Returns the location of the student's t-distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::NoncentralStudentsT;
///
/// let n = NoncentralStudentsT::new(0.0, 1.0, 2.0).unwrap();
/// assert_eq!(n.location(), 0.0);
/// ```
pub fn location(&self) -> f64 {
self.location
}

/// Returns the scale of the student's t-distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::NoncentralStudentsT;
///
/// let n = NoncentralStudentsT::new(0.0, 1.0, 2.0).unwrap();
/// assert_eq!(n.scale(), 1.0);
/// ```
pub fn scale(&self) -> f64 {
self.scale
}

/// Returns the freedom of the student's t-distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::NoncentralStudentsT;
///
/// let n = NoncentralStudentsT::new(0.0, 1.0, 2.0).unwrap();
/// assert_eq!(n.freedom(), 2.0);
/// ```
pub fn freedom(&self) -> f64 {
self.freedom
}
}

impl std::fmt::Display for NoncentralStudentsT {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "t_{}({},{})", self.freedom, self.location, self.scale)
}
}

impl ContinuousCDF<f64, f64> for NoncentralStudentsT {
/// Calculates the cumulative distribution function for the noncentral students t distribution at `t`
///
/// # Definition
/// \\(F(t;\nu,\delta) = \textrm{Prob}(t_\nu(\delta) < t)\\)
/// \\[
/// \Phi(-\delta) + \frac{1}{2}\sum\_{i=0}^\infty{[P\_i I\_x(i+1/2,n/2) + Q\_i I\_x(i+1/2,n/2)]}\textrm{ where}\\\\\[1.5em\]
/// x = \frac{t^2}{\nu + t^2}, \quad
/// P_i = e^{-\delta^2/2}\\,\frac{(\delta^2/2)^i}{i!}, \quad
/// Q_i = e^{-\delta^2/2}\\,\frac{(\delta^2/2)^i}{\Gamma(i + 3/2)}
/// \\]
/// where \\(I_x\\) denotes the incomplete regularized beta function, same as \\(I_x(a,b)\\) [here](https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function), unregularized is implemented as [`beta_inc`](crate::function::beta::beta_inc)
fn cdf(&self, t: f64) -> f64 {
unimplemented!()
}
}

impl Continuous<f64, f64> for NoncentralStudentsT {
fn pdf(&self, x: f64) -> f64 {
unimplemented!()
}

fn ln_pdf(&self, x: f64) -> f64 {
self.pdf(x).ln()
}
}

impl Min<f64> for NoncentralStudentsT {
/// Returns the minimum value in the domain of the student's t-distribution
/// representable by a double precision float
///
/// # Formula
///
/// ```text
/// f64::NEG_INFINITY
/// ```
fn min(&self) -> f64 {
f64::NEG_INFINITY
}
}

impl Max<f64> for NoncentralStudentsT {
/// Returns the maximum value in the domain of the student's t-distribution
/// representable by a double precision float
///
/// # Formula
///
/// ```text
/// f64::INFINITY
/// ```
fn max(&self) -> f64 {
f64::INFINITY
}
}
11 changes: 10 additions & 1 deletion src/function/beta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ pub fn checked_ln_beta(a: f64, b: f64) -> Result<f64> {
/// where `a` is the first beta parameter
/// and `b` is the second beta parameter.
///
/// # Definition
/// $$
/// B(a,b) = \int\_0^1{t^{a-1}(1-t)^{b-1}}\textrm{d}t
/// $$
///
///
/// # Panics
///
Expand All @@ -64,10 +69,14 @@ pub fn checked_beta(a: f64, b: f64) -> Result<f64> {
}

/// Computes the lower incomplete (unregularized) beta function
/// `B(a,b,x) = int(t^(a-1)*(1-t)^(b-1),t=0..x)` for `a > 0, b > 0, 1 >= x >= 0`
/// where `a` is the first beta parameter, `b` is the second beta parameter, and
/// `x` is the upper limit of the integral
///
/// # Definition
/// ```math
/// B(x;a,b) = B\_x(a,b) = \int\_0^x t^{a-1}*(1-t)^{b-1} \textrm{d}t
/// x \in [0,1] \textrm{ and } a,b > 0
/// ```
/// # Panics
///
/// If `a <= 0.0`, `b <= 0.0`, `x < 0.0`, or `x > 1.0`
Expand Down
2 changes: 1 addition & 1 deletion src/statistics/traits.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use ::num_traits::float::Float;
use num_traits::float::Float;

/// The `Min` trait specifies than an object has a minimum value
pub trait Min<T> {
Expand Down