Skip to content

Add getters for distribution parameters, closes #1233 #1234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8eb388e
Add getters for `Binomial`
AlessioZanga May 27, 2022
1dd0516
Add getters for `Cauchy`
AlessioZanga May 27, 2022
3e77c27
Add getters for `Dirichlet`
AlessioZanga May 27, 2022
679a36b
Add getters for `Exp`
AlessioZanga May 27, 2022
681f4d8
Add getters for `Frechet`
AlessioZanga May 27, 2022
34c735f
Add reverse getters for `Gamma`
AlessioZanga May 27, 2022
b5960a3
Add reverse getters for `ChiSquared`
AlessioZanga May 27, 2022
2f8cd34
Add reverse getters for `FisherZ`
AlessioZanga May 27, 2022
639bde4
Add getters for `Beta`
AlessioZanga May 27, 2022
00cb3b3
Add reverse getters for `StudentT`
AlessioZanga May 27, 2022
21eb5cc
Fix getter return type of `Binomial`
AlessioZanga May 27, 2022
389fd1d
Fix missing clone in getter for `Dirichlet`
AlessioZanga May 27, 2022
ae7fcda
Add getters for `Geometric`
AlessioZanga May 27, 2022
1d5a677
Add getters for `Gumbel`
AlessioZanga May 27, 2022
9f2c2b0
Add getters for `InverseGaussian`
AlessioZanga May 27, 2022
895ea33
Add reverse getters for `NormalInverseGaussian`
AlessioZanga May 28, 2022
04a34eb
Add getters for `LogNormal`
AlessioZanga May 28, 2022
361889c
Add reverse getters for `Pareto`
AlessioZanga May 28, 2022
e004eb4
Add getters for `Poisson`
AlessioZanga May 28, 2022
9ac5d95
Add getters for `Triangular`
AlessioZanga May 28, 2022
a31471e
Add reverse getters for `Weibull`
AlessioZanga May 28, 2022
e61d57b
Add reverse getters for `Zeta`
AlessioZanga May 28, 2022
38dc461
Add reverse getters for `Zipf`
AlessioZanga May 28, 2022
b623d3a
Update getters for `Dirichlet`
AlessioZanga May 30, 2022
26e6887
Update getters for `Beta`
AlessioZanga May 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions rand_distr/src/binomial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ impl Binomial {
}
Ok(Binomial { n, p })
}

/// Returns the number of trials (`n`) of the distribution.
pub fn n(&self) -> u64 {
self.n
}

/// Returns the probability of success (`p`) of the distribution.
pub fn p(&self) -> f64 {
self.p
}
}

/// Convert a `f64` to an `i64`, panicking on overflow.
Expand Down
10 changes: 10 additions & 0 deletions rand_distr/src/cauchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ where F: Float + FloatConst, Standard: Distribution<F>
}
Ok(Cauchy { median, scale })
}

/// Returns the median (`median`) of the distribution.
pub fn median(&self) -> F {
self.median
}

/// Returns the scale (`scale`) of the distribution.
pub fn scale(&self) -> F {
self.scale
}
}

impl<F> Distribution<F> for Cauchy<F>
Expand Down
5 changes: 5 additions & 0 deletions rand_distr/src/dirichlet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ where
alpha: vec![alpha; size].into_boxed_slice(),
})
}

/// Returns the shape parameter (`alpha`) of the distribution.
pub fn alpha(&self) -> &[F] {
&self.alpha
}
}

impl<F> Distribution<Vec<F>> for Dirichlet<F>
Expand Down
5 changes: 5 additions & 0 deletions rand_distr/src/exponential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ where F: Float, Exp1: Distribution<F>
lambda_inverse: F::one() / lambda,
})
}

/// Returns the (inverse of the) shape parameter (`lambda`) of the distribution.
pub fn lambda_inverse(&self) -> F {
self.lambda_inverse
}
Comment on lines +144 to +147
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Storing 1 / λ was previously an implementation detail.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Further to my comments below: we may want to keep this method (but maybe also add Exp::lambda)?

}

impl<F> Distribution<F> for Exp<F>
Expand Down
15 changes: 15 additions & 0 deletions rand_distr/src/frechet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,21 @@ where
shape,
})
}

/// Returns the location (`location`) of the distribution.
pub fn location(&self) -> F {
self.location
}

/// Returns the scale (`scale`) of the distribution.
pub fn scale(&self) -> F {
self.scale
}

/// Returns the shape (`shape`) of the distribution.
pub fn shape(&self) -> F {
self.shape
}
}

impl<F> Distribution<F> for Frechet<F>
Expand Down
67 changes: 67 additions & 0 deletions rand_distr/src/gamma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,30 @@ where
};
Ok(Gamma { repr })
}

/// Returns the shape parameter (`shape`) of the distribution.
pub fn shape(&self) -> F {
match self.repr {
// By definition of `one`.
One(_) => F::one(),
// By definition of `small shape`.
Small(gamma) => gamma.inv_shape.recip(),
// By definition of `large shape`.
Large(gamma) => gamma.d + F::from(1. / 3.).unwrap(),
}
}

/// Returns the scale parameter (`scale`) of the distribution.
pub fn scale(&self) -> F {
match self.repr {
// By definition of `one`.
One(exp) => exp.lambda_inverse().recip(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually wrong: Gamma::One uses Exp::new(1 / scale) so lambda_inverse is scale, not its inverse.

It seems like it would be worth adding Exp::new_inverse and keeping lambda_inverse here.

// By definition of `small shape`.
Small(gamma) => gamma.large_shape.scale,
// By definition of `large shape`.
Large(gamma) => gamma.scale,
}
}
}

impl<F> GammaSmallShape<F>
Expand Down Expand Up @@ -350,6 +374,16 @@ where
};
Ok(ChiSquared { repr })
}

/// Returns the degrees-of-freedom (`k`) of the distribution.
pub fn k(&self) -> F {
match self.repr {
DoFExactlyOne => F::one(),
// Since `DoFAnythingElse` is computed using Gamma(shape = 0.5 * k, ...),
// we revert the operation k = (1. / 0.5) * shape = 2. * shape.
Comment on lines +382 to +383
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments like these are probably not useful.. reviewers can't rely on them and probably no one else has a use for them. So probably they should be removed?

DoFAnythingElse(gamma) => F::from(2.).unwrap() * gamma.shape(),
}
}
}
impl<F> Distribution<F> for ChiSquared<F>
where
Expand Down Expand Up @@ -447,6 +481,16 @@ where
dof_ratio: n / m,
})
}

/// Returns the m parameter (`m`) of the distribution.
pub fn m(&self) -> F {
self.numer.k()
}

/// Returns the n parameter (`n`) of the distribution.
pub fn n(&self) -> F {
self.denom.k()
}
}
impl<F> Distribution<F> for FisherF<F>
where
Expand Down Expand Up @@ -500,6 +544,11 @@ where
dof: n,
})
}

/// Return the degrees-of-freedom (`n`) of the distribution.
pub fn n(&self) -> F {
self.chi.k()
}
}
impl<F> Distribution<F> for StudentT<F>
where
Expand Down Expand Up @@ -650,6 +699,24 @@ where
})
}
}

/// Returns the alpha shape (`alpha`) of the distribution.
pub fn alpha(&self) -> F {
if self.switched_params {
self.b
} else {
self.a
}
}

/// Returns the beta shape (`beta`) of the distribution.
pub fn beta(&self) -> F {
if self.switched_params {
self.a
} else {
self.b
}
}
}

impl<F> Distribution<F> for Beta<F>
Expand Down
5 changes: 5 additions & 0 deletions rand_distr/src/geometric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ impl Geometric {
Ok(Geometric { p, pi, k })
}
}

/// Returns the probability of success on each trial (`p`) of the distribution.
pub fn p(&self) -> f64 {
self.p
}
}

impl Distribution<u64> for Geometric
Expand Down
10 changes: 10 additions & 0 deletions rand_distr/src/gumbel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ where
}
Ok(Gumbel { location, scale })
}

/// Returns the location (`location`) of the distribution.
pub fn location(&self) -> F {
self.location
}

/// Returns the scale (`scale`) of the distribution.
pub fn scale(&self) -> F {
self.scale
}
}

impl<F> Distribution<F> for Gumbel<F>
Expand Down
10 changes: 10 additions & 0 deletions rand_distr/src/inverse_gaussian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ where

Ok(Self { mean, shape })
}

/// Returns the mean (`μ`) of the distribution.
pub fn mean(&self) -> F {
self.mean
}

/// Returns the shape (`shape`) of the distribution.
pub fn shape(&self) -> F {
self.shape
}
}

impl<F> Distribution<F> for InverseGaussian<F>
Expand Down
10 changes: 10 additions & 0 deletions rand_distr/src/normal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,16 @@ where F: Float, StandardNormal: Distribution<F>
pub fn from_zscore(&self, zscore: F) -> F {
self.norm.from_zscore(zscore).exp()
}

/// Returns the mean (`μ`) of the distribution.
pub fn mean(&self) -> F {
self.norm.mean()
}

/// Returns the standard deviation (`σ`) of the distribution.
pub fn std_dev(&self) -> F {
self.norm.std_dev()
}
Comment on lines +308 to +316
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method names and descriptions are incorrect: these are the log-space mean and standard deviation.

I suggest calling the methods mu, sigma (copying the names of parameters to new).

The actual mean of a log-normal is exp(μ + σ²/2), but we probably don't need a method for that.

}

impl<F> Distribution<F> for LogNormal<F>
Expand Down
19 changes: 19 additions & 0 deletions rand_distr/src/normal_inverse_gaussian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,25 @@ where
inverse_gaussian,
})
}

/// Returns the alpha parameter (`alpha`) of the distribution.
pub fn alpha(&self) -> F {
// By definition:
// gamma = sqrt(alpha^2 - beta^2) with alpha > 0
// mu = 1 / gamma
// Therefore:
// mu = 1 / sqrt(alpha^2 - beta^2)
// mu^2 = 1 / (alpha^2 - beta^2)
// 1 / mu^2 = alpha^2 - beta^2
// 1 / mu^2 + beta^2 = alpha^2
// sqrt(1 / mu^2 + beta^2) = alpha with alpha > 0
F::sqrt(self.inverse_gaussian.mean().powi(2).recip() + self.beta.powi(2))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this computation may produce slightly different alpha than one used for distribution initialization. Maybe it's worth to add a comment in the docs about it? Same for a number of other getters.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I've commented in #1233 about the issue, I've proposed a set of alternatives, that's why this PR is just a draft.

}

/// Returns the beta parameter (`beta`) of the distribution.
pub fn beta(&self) -> F {
self.beta
}
}

impl<F> Distribution<F> for NormalInverseGaussian<F>
Expand Down
10 changes: 10 additions & 0 deletions rand_distr/src/pareto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ where F: Float, OpenClosed01: Distribution<F>
inv_neg_shape: F::from(-1.0).unwrap() / shape,
})
}

/// Returns the scale (`scale`) of the distribution.
pub fn scale(&self) -> F {
self.scale
}

/// Returns the shape (`shape`) of the distribution.
pub fn shape(&self) -> F {
self.inv_neg_shape.recip().neg()
}
}

impl<F> Distribution<F> for Pareto<F>
Expand Down
5 changes: 5 additions & 0 deletions rand_distr/src/poisson.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ where F: Float + FloatConst, Standard: Distribution<F>
magic_val: lambda * log_lambda - crate::utils::log_gamma(F::one() + lambda),
})
}

/// Returns the lambda shape (`lambda`) of the distribution.
pub fn lambda(&self) -> F {
self.lambda
}
}

impl<F> Distribution<F> for Poisson<F>
Expand Down
15 changes: 15 additions & 0 deletions rand_distr/src/triangular.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,21 @@ where F: Float, Standard: Distribution<F>
}
Ok(Triangular { min, max, mode })
}

/// Return the min shape (`min`) of the distribution.
pub fn min(&self) -> F {
self.min
}

/// Return the min shape (`max`) of the distribution.
pub fn max(&self) -> F {
self.max
}

/// Return the min shape (`mode`) of the distribution.
pub fn mode(&self) -> F {
self.mode
}
}

impl<F> Distribution<F> for Triangular<F>
Expand Down
10 changes: 10 additions & 0 deletions rand_distr/src/weibull.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ where F: Float, OpenClosed01: Distribution<F>
scale,
})
}

/// Returns the scale parameter (`scale`) of the distribution.
pub fn scale(&self) -> F {
self.scale
}

/// Returns the shape parameter (`shape`) of the distribution.
pub fn shape(&self) -> F {
self.inv_shape.recip()
}
}

impl<F> Distribution<F> for Weibull<F>
Expand Down
34 changes: 34 additions & 0 deletions rand_distr/src/zipf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ where F: Float, Standard: Distribution<F>, OpenClosed01: Distribution<F>
b: two.powf(a_minus_1),
})
}

/// Returns the a parameter (`a`) of the distribution.
pub fn a(&self) -> F {
self.a_minus_1 + F::one()
}
}

impl<F> Distribution<F> for Zeta<F>
Expand Down Expand Up @@ -205,6 +210,35 @@ where F: Float, Standard: Distribution<F> {
})
}

/// Returns the cardinality of the set of elements (`n`) of the distribution.
pub fn n(&self) -> F {
match self.s != F::one() {
true => {
// By definition:
// t = (n^(1 - s) - s) * q
// Therefore:
// t / q = n^(1 - s) - s
// t / q + s = n^(1 - s)
// (t / q + s)^(1/(1 - s)) = n
F::powf(self.t / self.q + self.s, F::recip(F::one() - self.s))
},
false => {
// By definition:
// t = 1 - ln(n)
// Therefore:
// t - 1 = - ln(n)
// 1 - t = ln(n)
// e^(1 - t) = n
F::exp(F::one() - self.t)
},
}
}
Comment on lines +214 to +235
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another complex case to check (or exclude)


/// Returns the frequency rank exponent (`s`) of the distribution.
pub fn s(&self) -> F {
self.s
}

/// Inverse cumulative density function
#[inline]
fn inv_cdf(&self, p: F) -> F {
Expand Down