-
Notifications
You must be signed in to change notification settings - Fork 40
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
Use julia implementations for pdfs and some cdf-like functions #113
Changes from all commits
139d141
0bffee8
6bfc68d
60b64f3
542a6c4
6d66ba3
15b321c
49178c2
6366eab
b2ed6c9
15e20ff
9c22066
fd4db7e
3c942e0
7c67a0d
90a6404
0a54399
8cd5a76
73f20b7
71025f9
5a8d121
60ca443
2578dbe
9ec4aef
99cd041
b031752
f3ceda8
beb5dcd
14882a3
fbdb4eb
c3300d2
46bd90d
af14aba
cb1f325
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,17 @@ | ||
# functions related to beta distributions | ||
|
||
using HypergeometricFunctions: _₂F₁ | ||
|
||
# R implementations | ||
# For pdf and logpdf we use the Julia implementation | ||
using .RFunctions: | ||
betacdf, | ||
betaccdf, | ||
betalogcdf, | ||
betalogccdf, | ||
betainvcdf, | ||
betainvccdf, | ||
# betapdf, | ||
# betalogpdf, | ||
# betacdf, | ||
# betaccdf, | ||
# betalogcdf, | ||
# betalogccdf, | ||
# betainvcdf, | ||
# betainvccdf, | ||
andreasnoack marked this conversation as resolved.
Show resolved
Hide resolved
|
||
betainvlogcdf, | ||
betainvlogccdf | ||
|
||
|
@@ -22,3 +25,60 @@ function betalogpdf(α::T, β::T, x::T) where {T<:Real} | |
val = xlogy(α - 1, y) + xlog1py(β - 1, -y) - logbeta(α, β) | ||
return x < 0 || x > 1 ? oftype(val, -Inf) : val | ||
end | ||
|
||
function betacdf(α::Real, β::Real, x::Real) | ||
# Handle a degenerate case | ||
if iszero(α) && β > 0 | ||
return float(last(promote(α, β, x, x >= 0))) | ||
devmotion marked this conversation as resolved.
Show resolved
Hide resolved
|
||
end | ||
|
||
return first(beta_inc(α, β, clamp(x, 0, 1))) | ||
end | ||
|
||
function betaccdf(α::Real, β::Real, x::Real) | ||
# Handle a degenerate case | ||
if iszero(α) && β > 0 | ||
return float(last(promote(α, β, x, x < 0))) | ||
end | ||
|
||
last(beta_inc(α, β, clamp(x, 0, 1))) | ||
end | ||
|
||
# The log version is currently based on non-log version. When the cdf is very small we shift | ||
# to an implementation based on the hypergeometric function ₂F₁ to avoid underflow. | ||
function betalogcdf(α::T, β::T, x::T) where {T<:Real} | ||
# Handle a degenerate case | ||
if iszero(α) && β > 0 | ||
return log(last(promote(x, x >= 0))) | ||
end | ||
|
||
_x = clamp(x, 0, 1) | ||
p, q = beta_inc(α, β, _x) | ||
if p < floatmin(p) | ||
# see https://dlmf.nist.gov/8.17#E7 | ||
return -log(α) + xlogy(α, _x) + log(_₂F₁(promote(α, 1 - β, α + 1, _x)...)) - logbeta(α, β) | ||
elseif p <= 0.7 | ||
return log(p) | ||
else | ||
return log1p(-q) | ||
end | ||
end | ||
betalogcdf(α::Real, β::Real, x::Real) = betalogcdf(promote(α, β, x)...) | ||
|
||
function betalogccdf(α::Real, β::Real, x::Real) | ||
# Handle a degenerate case | ||
if iszero(α) && β > 0 | ||
return log(last(promote(α, β, x, x < 0))) | ||
end | ||
|
||
p, q = beta_inc(α, β, clamp(x, 0, 1)) | ||
if q < 0.7 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just noticed that this is a bit consistent with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I couldn't find a way to write the complementary version in terms of the hypergeometric in the same way as I could with the logcdf. |
||
return log(q) | ||
else | ||
return log1p(-p) | ||
end | ||
end | ||
|
||
betainvcdf(α::Real, β::Real, p::Real) = first(beta_inc_inv(α, β, p)) | ||
|
||
betainvccdf(α::Real, β::Real, p::Real) = last(beta_inc_inv(β, α, p)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,11 @@ | ||
# functions related to chi-square distribution | ||
|
||
# R implementations | ||
# For pdf and logpdf we use the Julia implementation | ||
using .RFunctions: | ||
chisqcdf, | ||
chisqccdf, | ||
chisqlogcdf, | ||
chisqlogccdf, | ||
chisqinvcdf, | ||
chisqinvccdf, | ||
chisqinvlogcdf, | ||
chisqinvlogccdf | ||
|
||
# Julia implementations | ||
# promotion ensures that we do forward e.g. `chisqpdf(::Int, ::Float32)` to | ||
# `gammapdf(::Float32, ::Int, ::Float32)` but not `gammapdf(::Float64, ::Int, ::Float32)` | ||
chisqpdf(k::Real, x::Real) = chisqpdf(promote(k, x)...) | ||
chisqpdf(k::T, x::T) where {T<:Real} = gammapdf(k / 2, 2, x) | ||
|
||
chisqlogpdf(k::Real, x::Real) = chisqlogpdf(promote(k, x)...) | ||
chisqlogpdf(k::T, x::T) where {T<:Real} = gammalogpdf(k / 2, 2, x) | ||
# Just use the Gamma definitions | ||
for f in ("pdf", "logpdf", "cdf", "ccdf", "logcdf", "logccdf", "invcdf", "invccdf", "invlogcdf", "invlogccdf") | ||
_chisqf = Symbol("chisq"*f) | ||
_gammaf = Symbol("gamma"*f) | ||
@eval begin | ||
$(_chisqf)(k::Real, x::Real) = $(_chisqf)(promote(k, x)...) | ||
$(_chisqf)(k::T, x::T) where {T<:Real} = $(_gammaf)(k/2, 2, x) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This requires a
[compat]
entry.This also pulls in some additional dependencies since HypergeometricFunctions depends on DualNumbers, it seems? I am just wondering if people are fine with this since my ChainRules PR (#106) was not received positively mainly due to the additional dependency on ChainRulesCore.
On a side note, HypergeometricFunctions would be needed in SpecialFunctions to resolve JuliaMath/SpecialFunctions.jl#317 and JuliaMath/SpecialFunctions.jl#160. There was some discussion about depending on HypergeometricFunctions in JuliaMath/SpecialFunctions.jl#175, but I assume for the very same reasons not everyone would welcome such a dependency in SpecialFunctions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add a compat entry (or CompatHelper will do it).
I can try to measure the effect on load time which I assume is the main concern here. I doubt that it will be much and more generally, I think that HypergeomericFunctions is a natural dependency here. Many CDFs have hypergeometric representations so I think this is a bit different from the AD discussion. I don't think it would make sense to have the CDFs defined in a separate package. (I think I'm in favor of #106 btw)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that probably it is more central to the package than AD (even though, of course, I'm in favor of the ChainRules PR 😉 ). I am fine with the dependency but I wanted to raise it due to the reactions in the other PR.