r2rs-nmath 0.1.1

Statistics programming for Rust based on R's nmath package
Documentation
// "Whatever you do, work at it with all your heart, as working for the Lord,
// not for human masters, since you know that you will receive an inheritance
// from the Lord as a reward. It is the Lord Christ you are serving."
// (Col 3:23-24)

mod d;
mod p;
mod q;
mod r;

use strafe_type::{LogProbability64, Natural64, Probability64, Real64};

pub(crate) use self::{d::*, p::*, q::*, r::*};
use crate::traits::{Distribution, RNG};

/// # The Cauchy Distribution
///
/// ## Description:
///
/// Density, distribution function, quantile function and random
/// generation for the Cauchy distribution with location and scale.
///
/// ## Details:
///
/// If ‘location’ or ‘scale’ are not specified, they assume the
/// default values of ‘0’ and ‘1’ respectively.
///
/// The Cauchy distribution with location l and scale s has density
///
/// $f(x) = 1 / (\pi s (1 + (\frac{x-l}{s})^2))$
///
/// for all x.
///
/// ## Density Plot
///
/// ```rust
/// # use r2rs_base::traits::StatisticalSlice;
/// # use r2rs_nmath::{distribution::CauchyBuilder, traits::Distribution};
/// # use strafe_plot::prelude::{IntoDrawingArea, Line, Plot, PlotOptions, SVGBackend, BLACK};
/// # use strafe_type::FloatConstraint;
/// let cauchy = CauchyBuilder::new().build();
/// let x = <[f64]>::sequence(-5.0, 5.0, 1000);
/// let y = x
///     .iter()
///     .map(|x| cauchy.density(x).unwrap())
///     .collect::<Vec<_>>();
///
/// let root = SVGBackend::new("density.svg", (1024, 768)).into_drawing_area();
/// Plot::new()
///     .with_options(PlotOptions {
///         x_axis_label: "x".to_string(),
///         y_axis_label: "density".to_string(),
///         ..Default::default()
///     })
///     .with_plottable(Line {
///         x,
///         y,
///         color: BLACK,
///         ..Default::default()
///     })
///     .plot(&root)
///     .unwrap();
/// # use std::fs::rename;
/// #     drop(root);
/// #     rename(
/// #             format!("density.svg"),
/// #             format!("src/distribution/cauchy/doctest_out/density.svg"),
/// #     )
/// #     .unwrap();
/// ```
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = embed_doc_image::embed_image!("density", "src/distribution/cauchy/doctest_out/density.svg")))]
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = "![Density][density]"))]
///
/// ## Source:
///
/// ‘density’, ‘probability’ and ‘quantile’ are all calculated from
/// numerically stable versions of the definitions.
///
/// ‘random’ uses inversion.
///
/// ## References:
///
/// Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) _The New S
/// Language_.  Wadsworth & Brooks/Cole.
///
/// Johnson, N. L., Kotz, S. and Balakrishnan, N. (1995) _Continuous
/// Univariate Distributions_, volume 1, chapter 16.  Wiley, New York.
///
/// ## See Also:
///
/// Distributions for other standard distributions, including ‘dt’ for
/// the t distribution which generalizes ‘dcauchy(*, l = 0, s = 1)’.
///
/// ## Examples:
///
/// ```rust
/// # use r2rs_nmath::{distribution::CauchyBuilder, traits::Distribution};
/// # use strafe_type::FloatConstraint;
/// let cauchy = CauchyBuilder::new().build();
/// let dens = (-1..=4)
///     .map(|x| cauchy.density(x).unwrap())
///     .collect::<Vec<_>>();
/// println!("{dens:?}");
/// # use std::{fs::File, io::Write};
/// # let mut f = File::create("src/distribution/cauchy/doctest_out/density.md").unwrap();
/// # writeln!(f, "```output").unwrap();
/// # writeln!(f, "{dens:?}").unwrap();
/// # writeln!(f, "```").unwrap();
/// ```
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = include_str!("doctest_out/density.md")))]
pub struct Cauchy {
    location: Real64,
    scale: Natural64,
}

impl Distribution for Cauchy {
    fn density<R: Into<Real64>>(&self, x: R) -> Real64 {
        dcauchy(x, self.location, self.scale, false)
    }

    fn log_density<R: Into<Real64>>(&self, x: R) -> Real64 {
        dcauchy(x, self.location, self.scale, true)
    }

    fn probability<R: Into<Real64>>(&self, q: R, lower_tail: bool) -> Probability64 {
        pcauchy(q, self.location, self.scale, lower_tail)
    }

    fn log_probability<R: Into<Real64>>(&self, q: R, lower_tail: bool) -> LogProbability64 {
        log_pcauchy(q, self.location, self.scale, lower_tail)
    }

    fn quantile<P: Into<Probability64>>(&self, p: P, lower_tail: bool) -> Real64 {
        qcauchy(p, self.location, self.scale, lower_tail)
    }

    fn log_quantile<LP: Into<LogProbability64>>(&self, p: LP, lower_tail: bool) -> Real64 {
        log_qcauchy(p, self.location, self.scale, lower_tail)
    }

    fn random_sample<R: RNG>(&self, rng: &mut R) -> Real64 {
        rcauchy(self.location, self.scale, rng)
    }
}

pub struct CauchyBuilder {
    location: Option<Real64>,
    scale: Option<Natural64>,
}

impl CauchyBuilder {
    pub fn new() -> Self {
        Self {
            location: None,
            scale: None,
        }
    }

    pub fn with_location<R: Into<Real64>>(&mut self, location: R) -> &mut Self {
        self.location = Some(location.into());
        self
    }

    pub fn with_scale<N: Into<Natural64>>(&mut self, scale: N) -> &mut Self {
        self.scale = Some(scale.into());
        self
    }

    pub fn build(&self) -> Cauchy {
        let location = self.location.unwrap_or(0.0.into());
        let scale = self.scale.unwrap_or(1.0.into());

        Cauchy { location, scale }
    }
}

#[cfg(test)]
mod tests;

#[cfg(all(test, feature = "enable_proptest"))]
mod proptests;

#[cfg(all(test, feature = "enable_covtest"))]
mod covtests;