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
mod d;
mod p;
mod q;
mod r;
use strafe_type::{LogProbability64, Positive64, Probability64, Real64};
pub(crate) use self::{d::*, p::*, q::*, r::*};
use crate::traits::{Distribution, RNG};
/// # The Log Normal Distribution
///
/// ## Description
/// Density, distribution function, quantile function and random generation for the log normal
/// distribution whose logarithm has mean equal to meanlog and standard deviation equal to sdlog.
///
/// ## Arguments
///
/// * meanlog, sdlog: mean and standard deviation of the distribution on the log scale with default
/// values of 0 and 1 respectively.
///
/// ## Details
///
/// The log normal distribution has density
///
/// $ f(x) = 1/(\sqrt(2 \pi) \sigma x) e^-((log x - \mu)^2 / (2 \mu^2)) $
///
/// where $ \mu $ and $ \sigma $ are the mean and standard deviation of the logarithm. The mean is
/// $ E(X) = exp(\mu + 1/2 \sigma^2) $, the median is $ med(X) = exp(\mu) $, and the variance
/// $ Var(X) = exp(2*\mu + \sigma^2)*(exp(\sigma^2) - 1) $ and hence the coefficient of variation
/// is $ \sqrt(exp(\sigma^2) - 1) $ which is approximately $ \sigma $ when that is small (e.g.,
/// $ \sigma < 1/2 $).
///
/// ## Density Plot
///
/// ```rust
/// # use r2rs_base::traits::StatisticalSlice;
/// # use r2rs_nmath::{distribution::LogNormalBuilder, traits::Distribution};
/// # use strafe_plot::prelude::{IntoDrawingArea, Line, Plot, PlotOptions, SVGBackend, BLACK};
/// # use strafe_type::FloatConstraint;
/// let lnorm = LogNormalBuilder::new().build();
/// let x = <[f64]>::sequence(-1.0, 8.0, 1000);
/// let y = x
/// .iter()
/// .map(|x| lnorm.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/lnorm/doctest_out/density.svg"),
/// # )
/// # .unwrap();
/// ```
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = embed_doc_image::embed_image!("density", "src/distribution/lnorm/doctest_out/density.svg")))]
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = "![Density][density]"))]
///
/// ## Note
///
/// The cumulative hazard $ H(t) = - \log(1 - F(t)) $ is
/// $ -plnorm(t, r, lower = FALSE, log = TRUE) $.
///
/// ## Source
///
/// dlnorm is calculated from the definition (in ‘Details’).
/// \[pqr\]lnorm are based on the relationship to the normal.
///
/// Consequently, they model a single point mass at exp(meanlog) for the boundary case sdlog = 0.
///
/// ## 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 14. Wiley, New York.
///
/// ## See Also
///
/// Distributions for other standard distributions, including dnorm for the normal distribution.
///
/// ## Examples
///
/// ```rust
/// # use r2rs_nmath::{
/// # distribution::{LogNormalBuilder, NormalBuilder},
/// # traits::Distribution,
/// # };
/// let norm = NormalBuilder::new().build();
/// println!("{}", norm.density(0));
/// let lnorm = LogNormalBuilder::new().build();
/// println!("{}", lnorm.density(1));
/// # use std::{fs::File, io::Write};
/// # let mut f = File::create("src/distribution/lnorm/doctest_out/dens.md").unwrap();
/// # writeln!(f, "```output").unwrap();
/// # writeln!(f, "{}", norm.density(0)).unwrap();
/// # writeln!(f, "{}", lnorm.density(1)).unwrap();
/// # writeln!(f, "```").unwrap();
/// ```
#[cfg_attr(feature = "doc_outputs", cfg_attr(all(), doc = include_str!("doctest_out/dens.md")))]
pub struct LogNormal {
mean_log: Real64,
standard_deviation_log: Positive64,
}
impl Distribution for LogNormal {
fn density<R: Into<Real64>>(&self, x: R) -> Real64 {
dlnorm(x, self.mean_log, self.standard_deviation_log, false)
}
fn log_density<R: Into<Real64>>(&self, x: R) -> Real64 {
dlnorm(x, self.mean_log, self.standard_deviation_log, true)
}
fn probability<R: Into<Real64>>(&self, q: R, lower_tail: bool) -> Probability64 {
plnorm(q, self.mean_log, self.standard_deviation_log, lower_tail)
}
fn log_probability<R: Into<Real64>>(&self, q: R, lower_tail: bool) -> LogProbability64 {
log_plnorm(q, self.mean_log, self.standard_deviation_log, lower_tail)
}
fn quantile<P: Into<Probability64>>(&self, p: P, lower_tail: bool) -> Real64 {
qlnorm(p, self.mean_log, self.standard_deviation_log, lower_tail)
}
fn log_quantile<LP: Into<LogProbability64>>(&self, p: LP, lower_tail: bool) -> Real64 {
log_qlnorm(p, self.mean_log, self.standard_deviation_log, lower_tail)
}
fn random_sample<R: RNG>(&self, rng: &mut R) -> Real64 {
rlnorm(self.mean_log, self.standard_deviation_log, rng)
}
}
pub struct LogNormalBuilder {
mean_log: Option<Real64>,
standard_deviation_log: Option<Positive64>,
}
impl LogNormalBuilder {
pub fn new() -> Self {
Self {
mean_log: None,
standard_deviation_log: None,
}
}
pub fn with_mean_log<R: Into<Real64>>(&mut self, mean_log: R) -> &mut Self {
self.mean_log = Some(mean_log.into());
self
}
pub fn with_standard_deviation_log<P: Into<Positive64>>(
&mut self,
standard_deviation_log: P,
) -> &mut Self {
self.standard_deviation_log = Some(standard_deviation_log.into());
self
}
pub fn build(&self) -> LogNormal {
let mean_log = self.mean_log.unwrap_or(0.0.into());
let standard_deviation_log = self.standard_deviation_log.unwrap_or(1.0.into());
LogNormal {
mean_log,
standard_deviation_log,
}
}
}
#[cfg(test)]
mod tests;
#[cfg(all(test, feature = "enable_proptest"))]
mod proptests;
#[cfg(all(test, feature = "enable_covtest"))]
mod covtests;