r2rs_nmath/distribution/signrank/
mod.rs

1mod c;
2mod d;
3mod p;
4mod q;
5mod r;
6
7use strafe_type::{LogProbability64, Natural64, Probability64, Real64};
8
9pub use self::{c::*, d::*, p::*, q::*, r::*};
10use crate::traits::{Distribution, RNG};
11
12/// # Distribution of the Wilcoxon Signed Rank Statistic
13///
14/// ## Description
15///
16/// Density, distribution function, quantile function and random generation for the distribution of
17/// the Wilcoxon Signed Rank statistic obtained from a sample with size n.
18///
19/// ## Arguments
20///
21/// * n: number(s) of observations in the sample(s). A positive integer, or a vector of such integers.
22///
23/// ## Details
24///
25/// This distribution is obtained as follows. Let x be a sample of size n from a continuous
26/// distribution symmetric about the origin. Then the Wilcoxon signed rank statistic is the
27/// sum of the ranks of the absolute values $ x\[i\] $ for which $ x\[i\] $ is positive. This statistic
28/// takes values between $ 0 $ and $ n(n+1)/2 $, and its mean and variance are $ n(n+1)/4 $ and
29/// $ n(n+1)(2n+1)/24 $, respectively.
30///
31/// If either of the first two arguments is a vector, the recycling rule is used to do the
32/// calculations for all combinations of the two up to the length of the longer vector.
33///
34/// ## Value
35///
36/// dsignrank gives the density, psignrank gives the distribution function, qsignrank gives the
37/// quantile function, and rsignrank generates random deviates.
38///
39/// The length of the result is determined by nn for rsignrank, and is the maximum of the lengths
40/// of the numerical arguments for the other functions.
41///
42/// The numerical arguments other than nn are recycled to the length of the result. Only the first
43/// elements of the logical arguments are used.
44///
45/// ## Density Plot
46///
47/// ```rust
48/// # use r2rs_base::traits::StatisticalSlice;
49/// # use r2rs_nmath::{distribution::SignedRankBuilder, traits::Distribution};
50/// # use strafe_plot::prelude::{IntoDrawingArea, Line, Plot, PlotOptions, SVGBackend, BLACK};
51/// # use strafe_type::FloatConstraint;
52/// let sgnrank = SignedRankBuilder::new().build();
53/// let x = <[f64]>::sequence_by(-1.0, 2.0, 0.001);
54/// let y = x
55///     .iter()
56///     .map(|x| sgnrank.density(x).unwrap())
57///     .collect::<Vec<_>>();
58///
59/// let root = SVGBackend::new("density.svg", (1024, 768)).into_drawing_area();
60/// Plot::new()
61///     .with_options(PlotOptions {
62///         x_axis_label: "x".to_string(),
63///         y_axis_label: "density".to_string(),
64///         ..Default::default()
65///     })
66///     .with_plottable(Line {
67///         x,
68///         y,
69///         color: BLACK,
70///         ..Default::default()
71///     })
72///     .plot(&root)
73///     .unwrap();
74/// # use std::fs::rename;
75/// #     drop(root);
76/// #     rename(
77/// #             format!("density.svg"),
78/// #             format!("src/distribution/signrank/doctest_out/density.svg"),
79/// #     )
80/// #     .unwrap();
81/// ```
82#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = embed_doc_image::embed_image!("density", "src/distribution/signrank/doctest_out/density.svg")))]
83#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = "![Density][density]"))]
84///
85/// ## Author(s)
86///
87/// Kurt Hornik; efficiency improvement by Ivo Ugrina.
88///
89/// ## See Also
90///
91/// wilcox.test to calculate the statistic from data, find p values and so on.
92///
93/// Distributions for standard distributions, including dwilcox for the distribution of two-sample
94/// Wilcoxon rank sum statistic.
95///
96/// ## Examples
97///
98/// ```rust
99/// # use r2rs_base::traits::StatisticalSlice;
100/// # use r2rs_nmath::{distribution::SignedRankBuilder, traits::Distribution};
101/// # use strafe_plot::prelude::{IntoDrawingArea, Line, Plot, PlotOptions, SVGBackend, BLACK};
102/// # use strafe_type::FloatConstraint;
103/// let plot_coords = [
104///     [0.0, 0.5, 0.0, 0.5],
105///     [0.5, 1.0, 0.0, 0.5],
106///     [0.0, 0.5, 0.5, 1.0],
107///     [0.5, 1.0, 0.5, 1.0],
108/// ];
109/// let ns = [4.0, 5.0, 10.0, 40.0];
110///
111/// let root = SVGBackend::new("densities.svg", (1024, 768)).into_drawing_area();
112/// for i in 0..4 {
113///     let n = ns[i];
114///     let x = <[f64]>::sequence(0.0, n * (n + 1.0) / 2.0, 500);
115///     let sgnrank = SignedRankBuilder::new().with_sample_size(n).build();
116///     let y = x
117///         .iter()
118///         .map(|x| sgnrank.density(x).unwrap())
119///         .collect::<Vec<_>>();
120///
121///     Plot::new()
122///         .with_options(PlotOptions {
123///             x_axis_label: "x".to_string(),
124///             y_axis_label: "density".to_string(),
125///             title: format!("n={n}"),
126///             plot_left: plot_coords[i][0],
127///             plot_right: plot_coords[i][1],
128///             plot_top: plot_coords[i][2],
129///             plot_bottom: plot_coords[i][3],
130///             ..Default::default()
131///         })
132///         .with_plottable(Line {
133///             x,
134///             y,
135///             color: BLACK,
136///             ..Default::default()
137///         })
138///         .plot(&root)
139///         .unwrap();
140/// }
141/// # use std::fs::rename;
142/// #     drop(root);
143/// #     rename(
144/// #             format!("densities.svg"),
145/// #             format!("src/distribution/signrank/doctest_out/densities.svg"),
146/// #     )
147/// #     .unwrap();
148/// ```
149#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = embed_doc_image::embed_image!("densities", "src/distribution/signrank/doctest_out/densities.svg")))]
150#[cfg_attr(
151    feature = "doc_outputs",
152    cfg_attr(all(), doc = "![Densities][densities]")
153)]
154pub struct SignedRank {
155    sample_size: Natural64,
156}
157
158impl Distribution for SignedRank {
159    fn density<R: Into<Real64>>(&self, x: R) -> Real64 {
160        dsignrank(x, self.sample_size, false)
161    }
162
163    fn log_density<R: Into<Real64>>(&self, x: R) -> Real64 {
164        dsignrank(x, self.sample_size, true)
165    }
166
167    fn probability<R: Into<Real64>>(&self, q: R, lower_tail: bool) -> Probability64 {
168        psignrank(q, self.sample_size, lower_tail)
169    }
170
171    fn log_probability<R: Into<Real64>>(&self, q: R, lower_tail: bool) -> LogProbability64 {
172        log_psignrank(q, self.sample_size, lower_tail)
173    }
174
175    fn quantile<P: Into<Probability64>>(&self, p: P, lower_tail: bool) -> Real64 {
176        qsignrank(p, self.sample_size, lower_tail)
177    }
178
179    fn log_quantile<LP: Into<LogProbability64>>(&self, p: LP, lower_tail: bool) -> Real64 {
180        log_qsignrank(p, self.sample_size, lower_tail)
181    }
182
183    fn random_sample<R: RNG>(&self, rng: &mut R) -> Real64 {
184        rsignrank(self.sample_size, rng)
185    }
186}
187
188pub struct SignedRankBuilder {
189    sample_size: Option<Natural64>,
190}
191
192impl SignedRankBuilder {
193    pub fn new() -> Self {
194        Self { sample_size: None }
195    }
196
197    pub fn with_sample_size<N: Into<Natural64>>(&mut self, sample_size: N) -> &mut Self {
198        self.sample_size = Some(sample_size.into());
199        self
200    }
201
202    pub fn build(&self) -> SignedRank {
203        let sample_size = self.sample_size.unwrap_or(1.0.into());
204
205        SignedRank { sample_size }
206    }
207}
208
209#[cfg(test)]
210mod tests;
211
212#[cfg(all(test, feature = "enable_proptest"))]
213mod proptests;
214
215#[cfg(all(test, feature = "enable_covtest"))]
216mod covtests;