-
Notifications
You must be signed in to change notification settings - Fork 44
Expand file tree
/
Copy pathgamma.jl
More file actions
106 lines (91 loc) · 3.39 KB
/
gamma.jl
File metadata and controls
106 lines (91 loc) · 3.39 KB
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
# functions related to gamma distribution
using HypergeometricFunctions: _₁F₁
# Julia implementations
gammapdf(k::Real, θ::Real, x::Real) = exp(gammalogpdf(k, θ, x))
gammalogpdf(k::Real, θ::Real, x::Real) = gammalogpdf(promote(k, θ, x)...)
function gammalogpdf(k::T, θ::T, x::T) where {T <: Real}
# we ensure that `log(x)` does not error if `x < 0`
xθ = max(x, 0) / θ
val = -loggamma(k) - log(θ) - xθ
# xlogy(k - 1, xθ) - xθ -> -∞ for xθ -> ∞ so we only add the first term
# when it's safe
if isfinite(xθ)
val += xlogy(k - 1, xθ)
end
return x < 0 ? oftype(val, -Inf) : val
end
function gammacdf(k::T, θ::T, x::T) where {T <: Real}
# Handle the degenerate case
if iszero(k)
return float(last(promote(x, x >= 0)))
end
return first(gamma_inc(k, max(0, x) / θ))
end
gammacdf(k::Real, θ::Real, x::Real) = gammacdf(map(float, promote(k, θ, x))...)
function gammaccdf(k::T, θ::T, x::T) where {T <: Real}
# Handle the degenerate case
if iszero(k)
return float(last(promote(x, x < 0)))
end
return last(gamma_inc(k, max(0, x) / θ))
end
gammaccdf(k::Real, θ::Real, x::Real) = gammaccdf(map(float, promote(k, θ, x))...)
gammalogcdf(k::Real, θ::Real, x::Real) = _gammalogcdf(map(float, promote(k, θ, x))...)
# Implemented via the non-log version. For tiny values, we recompute the result with
# loggamma. In that situation, there is little risk of significant cancellation.
function _gammalogcdf(k::Float64, θ::Float64, x::Float64)
# Handle the degenerate case
if iszero(k)
return log(x >= 0)
end
xdθ = max(0, x) / θ
l, u = gamma_inc(k, xdθ)
if l < floatmin(Float64) && isfinite(k) && isfinite(xdθ)
return -log(k) + k * log(xdθ) - xdθ + log(_₁F₁(1.0, 1 + k, xdθ)) - loggamma(k)
elseif l < 0.7
return log(l)
else
return log1p(-u)
end
end
function _gammalogcdf(k::T, θ::T, x::T) where {T <: Union{Float16, Float32}}
return T(_gammalogcdf(Float64(k), Float64(θ), Float64(x)))
end
gammalogccdf(k::Real, θ::Real, x::Real) = _gammalogccdf(map(float, promote(k, θ, x))...)
# Implemented via the non-log version. For tiny values, we recompute the result with
# loggamma. In that situation, there is little risk of significant cancellation.
function _gammalogccdf(k::Float64, θ::Float64, x::Float64)
# Handle the degenerate case
if iszero(k)
return log(x < 0)
end
xdθ = max(0, x) / θ
l, u = gamma_inc(k, xdθ)
if u < floatmin(Float64)
return loggamma(k, xdθ) - loggamma(k)
elseif u < 0.7
return log(u)
else
return log1p(-l)
end
end
function _gammalogccdf(k::T, θ::T, x::T) where {T <: Union{Float16, Float32}}
return T(_gammalogccdf(Float64(k), Float64(θ), Float64(x)))
end
function gammainvcdf(k::Real, θ::Real, p::Real)
_k, _θ, _p = promote(k, θ, p)
return _θ * gamma_inc_inv(_k, _p, 1 - _p)
end
function gammainvccdf(k::Real, θ::Real, p::Real)
_k, _θ, _p = promote(k, θ, p)
return _θ * gamma_inc_inv(_k, 1 - _p, _p)
end
# Rmath implementations
function gammainvlogcdf(k::Real, θ::Real, lq::Real)
T = float(Base.promote_typeof(k, θ, lq))
return convert(T, Rmath.qgamma(lq, k, θ, true, true))
end
function gammainvlogccdf(k::Real, θ::Real, lq::Real)
T = float(Base.promote_typeof(k, θ, lq))
return convert(T, Rmath.qgamma(lq, k, θ, false, true))
end