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

Add getters for distribution parameters, closes #1233 #1234

wants to merge 25 commits into from

Conversation

AlessioZanga
Copy link

@AlessioZanga AlessioZanga commented May 29, 2022

Add getters for distributions that satisfy (1) and (2) criteria described in #1233, also provide a reference implementation for reverse-computing getters distribution that satisfy only (1), except for Hypergeometric, Pert and WeightedAlias.

This is still a draft since we need to decide what to do for these distribution that satisfy only (1), eventually we can simply revert the commits with the reverse-computing getters and keep the exact getters.

Closes #1233.

Copy link
Member

@newpavlov newpavlov left a comment

Choose a reason for hiding this comment

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

Some comments after a quick review.

Closes #1233

It's better to place it in the PR description, not in the title. Otherwise GitHub does not link the issue and will not automatically close it on merge.

// 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.

@AlessioZanga
Copy link
Author

Some comments after a quick review.

Closes #1233

It's better to place it in the PR description, not in the title. Otherwise GitHub does not link the issue and will not automatically close it on merge.

GitHub shows me that it is already linked to the original issue, but I'll edit the original comment and add it.

Comment on lines +144 to +147
/// Returns the (inverse of the) shape parameter (`lambda`) of the distribution.
pub fn lambda_inverse(&self) -> F {
self.lambda_inverse
}
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)?

Comment on lines 705 to 709
if self.switched_params {
return self.b;
}

self.a
Copy link
Member

Choose a reason for hiding this comment

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

Nit: early return is poor code style where it's not used to skip further computations.

Copy link
Author

Choose a reason for hiding this comment

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

Do you prefer to:

  1. Use an intermediate assignment upon checking the condition,
  2. Use a rust-like approach with a match,
  3. Other?

Is there any documentation about the coding standards that are used in this repository? I don't see any CONTRIBUTING.md guide.

Copy link
Member

Choose a reason for hiding this comment

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

I would just use if .. { self.b } else { self.a }. Simple.

No, we don't have a style guide beyond make it neat. https://rust-random.github.io/book/contributing.html

Copy link
Author

Choose a reason for hiding this comment

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

Sounds good! I'll update the getter!

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.

Comment on lines +382 to +383
// Since `DoFAnythingElse` is computed using Gamma(shape = 0.5 * k, ...),
// we revert the operation k = (1. / 0.5) * shape = 2. * shape.
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?

Comment on lines +144 to +147
/// Returns the (inverse of the) shape parameter (`lambda`) of the distribution.
pub fn lambda_inverse(&self) -> F {
self.lambda_inverse
}
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)?

Comment on lines +308 to +316
/// 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()
}
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.

Comment on lines +214 to +235
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)
},
}
}
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)

@AlessioZanga AlessioZanga closed this by deleting the head repository Oct 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add getters for distribution parameters
3 participants