Skip to content

Added icdf for Rice and skewnormal distributions #7095

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 3 commits into from
Closed
Changes from all commits
Commits
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
43 changes: 42 additions & 1 deletion pymc/distributions/continuous.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ def polyagamma_cdf(*args, **kwargs):
from scipy import stats
from scipy.interpolate import InterpolatedUnivariateSpline
from scipy.special import expit
from scipy.stats import norm
from scipy.optimize import newton
from scipy.special import ive, iv

from pymc.distributions import transforms
from pymc.distributions.dist_math import (
Expand Down Expand Up @@ -2993,6 +2996,29 @@ def logp(value, mu, sigma, alpha):
tau > 0,
msg="tau > 0",
)
def icdf(prob, mu, sigma, alpha, max_iter=100, tol=1e-8):
Copy link
Member

Choose a reason for hiding this comment

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

What justifies the icdf method having a different signature compared to the logp method mentioned above?

def cdf_difference(x):
return norm.cdf(x) - 2 * norm.cdf(alpha * x) - prob

x0 = norm.ppf(prob)
x = x0

for _ in range(max_iter):
diff = cdf_difference(x)

if pt.abs(diff) < tol:
return mu + sigma * x

derivative = norm.pdf(x) - 2 * alpha * norm.pdf(alpha * x)
Copy link
Member

Choose a reason for hiding this comment

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

does norm.pdf and norm.ppf work with PyTensor objects?

x -= derivative

res = mu + sigma * x
res = check_icdf_value(res, prob)
Copy link
Member

Choose a reason for hiding this comment

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

Can you explain in words (or math) what is going on here?

Copy link
Author

@ParamThakkar123 ParamThakkar123 Feb 2, 2024

Choose a reason for hiding this comment

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

The provided code defines a function icdf that aims to find the inverse cumulative distribution function (ICDF) for a specific probability distribution.
cdf Function:

Calculates the cumulative distribution function (CDF) for a given input
x using a specific probability distribution formula.
The distribution appears to be a modified version, involving terms like pt.exp (likely indicating exponentiation), iv (modified Bessel function of the first kind), and ive (modified Bessel function of the second kind).
cdf_derivative Function:

Calculates the derivative of the CDF with respect to
x. This derivative is used in the Newton-Raphson method, which is an iterative numerical technique for finding roots (or zeros) of a function.
Newton-Raphson Iteration (newton):

Uses the Newton-Raphson method to iteratively find a value of x such that
cdf(x)−prob=0.
The fprime argument is provided with the derivative function (cdf_derivative) to guide the iteration.
check_icdf_value Function:

Performs some checks on the calculated ICDF value (res) and potentially modifies it.

Checks whether certain parameters, in this case,
σ, satisfy a condition (in this case, >0 σ>0).
If the condition is not met, it likely raises an error or handles the situation accordingly.
Overall Workflow:

The main function icdf combines these components to find the ICDF for a given probability (prob) using the Newton-Raphson method.
It includes checks to ensure the validity of the ICDF value and the parameters involved.

Copy link
Member

@ricardoV94 ricardoV94 Feb 2, 2024

Choose a reason for hiding this comment

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

Sorry to ask but are you a bot?

The code will clearly not work with PyTensor variables.

Copy link
Author

Choose a reason for hiding this comment

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

No. I am not a bot

Copy link
Author

Choose a reason for hiding this comment

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

I'll fix everything and make a new pull request

Copy link
Member

Choose a reason for hiding this comment

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

Calculates the cumulative distribution function (CDF) for a given input x using a specific probability distribution formula. The distribution appears to be a modified version, involving terms like pt.exp (likely indicating exponentiation), iv (modified Bessel function of the first kind), and ive (modified Bessel function of the second kind). cdf_derivative Function:

Performs some checks on the calculated ICDF value (res) and potentially modifies it.

What do you mean by "likely indicating", "potentially modifies it"? This wording seems strange to me.

Again, none of this will work with PyTensor variables. If you are relying on AI to generate responses and code changes, we cannot accept them

return check_parameters(
res,
sigma > 0,
msg="sigma > 0"
)


class Triangular(BoundedContinuous):
Expand Down Expand Up @@ -3348,7 +3374,22 @@ def logp(value, b, sigma):
b >= 0,
msg="sigma >= 0, b >= 0",
)

def icdf(prob, nu, sigma, x0=1.0, max_iter=100, tol=1e-8):
def cdf(x):
return (1 + x / sigma**2) * pt.exp(-x**2 / (2 * sigma**2)) * iv(0, x * nu / sigma**2) - prob

def cdf_derivative(x):
return ((1 - x**2 / sigma**2) * pt.exp(-x**2 / (2 * sigma**2)) * iv(0, x * nu / sigma**2)
+ (x / sigma**2) * pt.exp(-x**2 / (2 * sigma**2)) * ive(0, x * nu / sigma**2)) * nu / sigma**2

approx_icdf = newton(cdf, x0, fprime=cdf_derivative, tol=tol, maxiter=max_iter)
Copy link
Member

Choose a reason for hiding this comment

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

Will newton from scipy work with PyTensor variables?

res = approx_icdf
res = check_icdf_value(res, prob)
return check_parameters(
res,
sigma > 0,
msg="sigma > 0"
)

class Logistic(Continuous):
r"""
Expand Down