r2rs-nmath 0.1.1

Statistics programming for Rust based on R's nmath package
Documentation
mod c;
mod d;
mod p;
mod q;
mod r;

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

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

/// # Distribution of the Wilcoxon Signed Rank Statistic
///
/// ## Description
///
/// Density, distribution function, quantile function and random generation for the distribution of
/// the Wilcoxon Signed Rank statistic obtained from a sample with size n.
///
/// ## Arguments
///
/// * n: number(s) of observations in the sample(s). A positive integer, or a vector of such integers.
///
/// ## Details
///
/// This distribution is obtained as follows. Let x be a sample of size n from a continuous
/// distribution symmetric about the origin. Then the Wilcoxon signed rank statistic is the
/// sum of the ranks of the absolute values $ x\[i\] $ for which $ x\[i\] $ is positive. This statistic
/// takes values between $ 0 $ and $ n(n+1)/2 $, and its mean and variance are $ n(n+1)/4 $ and
/// $ n(n+1)(2n+1)/24 $, respectively.
///
/// If either of the first two arguments is a vector, the recycling rule is used to do the
/// calculations for all combinations of the two up to the length of the longer vector.
///
/// ## Value
///
/// dsignrank gives the density, psignrank gives the distribution function, qsignrank gives the
/// quantile function, and rsignrank generates random deviates.
///
/// The length of the result is determined by nn for rsignrank, and is the maximum of the lengths
/// of the numerical arguments for the other functions.
///
/// The numerical arguments other than nn are recycled to the length of the result. Only the first
/// elements of the logical arguments are used.
///
/// ## Density Plot
///
/// ```rust
/// # use r2rs_base::traits::StatisticalSlice;
/// # use r2rs_nmath::{distribution::SignedRankBuilder, traits::Distribution};
/// # use strafe_plot::prelude::{IntoDrawingArea, Line, Plot, PlotOptions, SVGBackend, BLACK};
/// # use strafe_type::FloatConstraint;
/// let sgnrank = SignedRankBuilder::new().build();
/// let x = <[f64]>::sequence_by(-1.0, 2.0, 0.001);
/// let y = x
///     .iter()
///     .map(|x| sgnrank.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/signrank/doctest_out/density.svg"),
/// #     )
/// #     .unwrap();
/// ```
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = embed_doc_image::embed_image!("density", "src/distribution/signrank/doctest_out/density.svg")))]
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = "![Density][density]"))]
///
/// ## Author(s)
///
/// Kurt Hornik; efficiency improvement by Ivo Ugrina.
///
/// ## See Also
///
/// wilcox.test to calculate the statistic from data, find p values and so on.
///
/// Distributions for standard distributions, including dwilcox for the distribution of two-sample
/// Wilcoxon rank sum statistic.
///
/// ## Examples
///
/// ```rust
/// # use r2rs_base::traits::StatisticalSlice;
/// # use r2rs_nmath::{distribution::SignedRankBuilder, traits::Distribution};
/// # use strafe_plot::prelude::{IntoDrawingArea, Line, Plot, PlotOptions, SVGBackend, BLACK};
/// # use strafe_type::FloatConstraint;
/// let plot_coords = [
///     [0.0, 0.5, 0.0, 0.5],
///     [0.5, 1.0, 0.0, 0.5],
///     [0.0, 0.5, 0.5, 1.0],
///     [0.5, 1.0, 0.5, 1.0],
/// ];
/// let ns = [4.0, 5.0, 10.0, 40.0];
///
/// let root = SVGBackend::new("densities.svg", (1024, 768)).into_drawing_area();
/// for i in 0..4 {
///     let n = ns[i];
///     let x = <[f64]>::sequence(0.0, n * (n + 1.0) / 2.0, 500);
///     let sgnrank = SignedRankBuilder::new().with_sample_size(n).build();
///     let y = x
///         .iter()
///         .map(|x| sgnrank.density(x).unwrap())
///         .collect::<Vec<_>>();
///
///     Plot::new()
///         .with_options(PlotOptions {
///             x_axis_label: "x".to_string(),
///             y_axis_label: "density".to_string(),
///             title: format!("n={n}"),
///             plot_left: plot_coords[i][0],
///             plot_right: plot_coords[i][1],
///             plot_top: plot_coords[i][2],
///             plot_bottom: plot_coords[i][3],
///             ..Default::default()
///         })
///         .with_plottable(Line {
///             x,
///             y,
///             color: BLACK,
///             ..Default::default()
///         })
///         .plot(&root)
///         .unwrap();
/// }
/// # use std::fs::rename;
/// #     drop(root);
/// #     rename(
/// #             format!("densities.svg"),
/// #             format!("src/distribution/signrank/doctest_out/densities.svg"),
/// #     )
/// #     .unwrap();
/// ```
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = embed_doc_image::embed_image!("densities", "src/distribution/signrank/doctest_out/densities.svg")))]
#[cfg_attr(
    feature = "doc_outputs",
    cfg_attr(all(), doc = "![Densities][densities]")
)]
pub struct SignedRank {
    sample_size: Natural64,
}

impl Distribution for SignedRank {
    fn density<R: Into<Real64>>(&self, x: R) -> Real64 {
        dsignrank(x, self.sample_size, false)
    }

    fn log_density<R: Into<Real64>>(&self, x: R) -> Real64 {
        dsignrank(x, self.sample_size, true)
    }

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

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

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

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

    fn random_sample<R: RNG>(&self, rng: &mut R) -> Real64 {
        rsignrank(self.sample_size, rng)
    }
}

pub struct SignedRankBuilder {
    sample_size: Option<Natural64>,
}

impl SignedRankBuilder {
    pub fn new() -> Self {
        Self { sample_size: None }
    }

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

    pub fn build(&self) -> SignedRank {
        let sample_size = self.sample_size.unwrap_or(1.0.into());

        SignedRank { sample_size }
    }
}

#[cfg(test)]
mod tests;

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

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