1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
mod d;
mod p;
mod q;
mod r;
use strafe_type::{LogProbability64, Probability64, Rational64, Real64};
pub(crate) use self::{d::*, p::*, q::*, r::*};
use crate::traits::{Distribution, RNG};
/// # The Logistic Distribution
///
/// ## Description
///
/// Density, distribution function, quantile function and random generation for the logistic
/// distribution with parameters location and scale.
///
/// ## Arguments
///
/// * location, scale: location and scale parameters.
///
/// ## Details
///
/// If location or scale are omitted, they assume the default values of 0 and 1 respectively.
///
/// The Logistic distribution with location = m and scale = s has distribution function
///
/// $ F(x) = \frac{1}{1 + exp(-\frac{x-m}{s})} $
///
/// and density
///
/// $ f(x) = \frac{1}{s} exp(\frac{x-m}{s}) (1 + exp(\frac{x-m}{s}))^{-2} $.
///
/// It is a long-tailed distribution with mean m and variance $ \frac{\pi^2}{3} s^2 $.
///
/// ## Value
///
/// dlogis gives the density, plogis gives the distribution function, qlogis gives the quantile
/// function, and rlogis generates random deviates.
///
/// The length of the result is determined by n for rlogis, and is the maximum of the lengths of
/// the numerical arguments for the other functions.
///
/// The numerical arguments other than n 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::LogisticBuilder, traits::Distribution};
/// # use strafe_plot::prelude::{IntoDrawingArea, Line, Plot, PlotOptions, SVGBackend, BLACK};
/// # use strafe_type::FloatConstraint;
/// let logis = LogisticBuilder::new().build();
/// let x = <[f64]>::sequence(-6.0, 6.0, 1000);
/// let y = x
/// .iter()
/// .map(|x| logis.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/logis/doctest_out/density.svg"),
/// # )
/// # .unwrap();
/// ```
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = embed_doc_image::embed_image!("density", "src/distribution/logis/doctest_out/density.svg")))]
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = "![Density][density]"))]
///
/// ## Note
///
/// qlogis(p) is the same as the well known ‘logit’ function, $ logit(p) = log(p/(1-p)) $, and
/// plogis(x) has consequently been called the ‘inverse logit’.
///
/// The distribution function is a rescaled hyperbolic tangent, $ plogis(x) == (1+ tanh(x/2))/2 $,
/// and it is called a sigmoid function in contexts such as neural networks.
///
/// ## Source
///
/// \[dpq\]logis are calculated directly from the definitions.
///
/// rlogis 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 2, chapter 23. Wiley, New York.
///
/// ## See Also
///
/// Distributions for other standard distributions.
///
/// ## Examples
///
/// Approximately equal (+/- 3)
/// ```rust
/// # use num_traits::FloatConst;
/// # use r2rs_nmath::{
/// # distribution::LogisticBuilder,
/// # rng::MersenneTwister,
/// # traits::{Distribution, RNG},
/// # };
/// # use r2rs_stats::funcs::variance;
/// # use strafe_type::FloatConstraint;
/// let logis = LogisticBuilder::new()
/// .with_location(0)
/// .with_scale(5)
/// .build();
///
/// let mut rng = MersenneTwister::new();
/// rng.set_seed(1);
///
/// let r = (0..4000)
/// .map(|_| logis.random_sample(&mut rng).unwrap())
/// .collect::<Vec<_>>();
/// println!("{}", variance(&r));
/// println!("{}", f64::PI().powi(2) / 3.0 * 5.0_f64.powi(2));
/// # use std::{fs::File, io::Write};
/// # let mut f = File::create("src/distribution/logis/doctest_out/rand.md").unwrap();
/// # writeln!(f, "```output").unwrap();
/// # writeln!(f, "{}", variance(&r)).unwrap();
/// # writeln!(f, "{}", f64::PI().powi(2) / 3.0 * 5.0_f64.powi(2)).unwrap();
/// # writeln!(f, "```").unwrap();
/// ```
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = include_str!("doctest_out/rand.md")))]
pub struct Logistic {
location: Real64,
scale: Rational64,
}
impl Distribution for Logistic {
fn density<R: Into<Real64>>(&self, x: R) -> Real64 {
dlogis(x, self.location, self.scale, false)
}
fn log_density<R: Into<Real64>>(&self, x: R) -> Real64 {
dlogis(x, self.location, self.scale, true)
}
fn probability<R: Into<Real64>>(&self, q: R, lower_tail: bool) -> Probability64 {
plogis(q, self.location, self.scale, lower_tail)
}
fn log_probability<R: Into<Real64>>(&self, q: R, lower_tail: bool) -> LogProbability64 {
log_plogis(q, self.location, self.scale, lower_tail)
}
fn quantile<P: Into<Probability64>>(&self, p: P, lower_tail: bool) -> Real64 {
qlogis(p, self.location, self.scale, lower_tail)
}
fn log_quantile<LP: Into<LogProbability64>>(&self, p: LP, lower_tail: bool) -> Real64 {
log_qlogis(p, self.location, self.scale, lower_tail)
}
fn random_sample<R: RNG>(&self, rng: &mut R) -> Real64 {
rlogis(self.location, self.scale, rng)
}
}
pub struct LogisticBuilder {
location: Option<Real64>,
scale: Option<Rational64>,
}
impl LogisticBuilder {
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<R: Into<Rational64>>(&mut self, scale: R) -> &mut Self {
self.scale = Some(scale.into());
self
}
pub fn build(&self) -> Logistic {
let location = self.location.unwrap_or(0.0.into());
let scale = self.scale.unwrap_or(1.0.into());
Logistic { location, scale }
}
}
#[cfg(test)]
mod tests;
#[cfg(all(test, feature = "enable_proptest"))]
mod proptests;
#[cfg(all(test, feature = "enable_covtest"))]
mod covtests;