-
Notifications
You must be signed in to change notification settings - Fork 42
add tdist cdfs and quantiles #147
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
Conversation
What should I have for type asserts? They were not added with any specific principles.
devmotion
left a comment
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.
You can have a look at other distributions, e.g., https://github.com/JuliaStats/StatsFuns.jl/blob/master/src/distrs/beta.jl. Here we want to support inputs of type ::Real, e.g., tdistcdf(nu::Real, x::Real) etc. However, similar to the beta.jl file in some cases it might be easiest to first promote both arguments, e.g., tdistcdf(nu::Real, x::Real) = tdistcdf(promote(nu, x)...) and then define tdistcdf(nu::T, x::T) where {T<:Real} since it can make it easier to ensure that constants etc are of the desired type (in this example we would like the result to be of type float(T)).
src/distrs/tdist.jl
Outdated
| if x < 0 && r < (0x1p-26 * x)^2 | ||
| return -log(abs(x))*r + log(r)*muladd(r, .5, -1.) - logbeta(r/2, 1/2) | ||
| end | ||
| q = 0.5*beta_inc(r/2, 1/2, r/muladd(x, x, r))[1] |
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 causes undesired promotions. We want e.g. that Float32 inputs yield Float32 results.
src/distrs/tdist.jl
Outdated
| if x < 0 && r < (0x1p-26 * x)^2 | ||
| return -log(abs(x))*r + log(r)*muladd(r, .5, -1.) - logbeta(r/2, 1/2) | ||
| end | ||
| q = 0.5*beta_inc(r/2, 1/2, r/muladd(x, x, r))[1] |
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.
Same here.
| if x < 0 && ν < (0x1p-26 * x)^2 | ||
| return -log(abs(x))*ν + log(ν)*muladd(ν, T(.5), -1.) - logbeta(ν/2, T(.5)) | ||
| end | ||
| q = T(0.5)*beta_inc(ν/2, T(.5), ν/muladd(x, x, ν))[1] | ||
| return ifelse(q > 0, 1 - q, q) |
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.
| if x < 0 && ν < (0x1p-26 * x)^2 | |
| return -log(abs(x))*ν + log(ν)*muladd(ν, T(.5), -1.) - logbeta(ν/2, T(.5)) | |
| end | |
| q = T(0.5)*beta_inc(ν/2, T(.5), ν/muladd(x, x, ν))[1] | |
| return ifelse(q > 0, 1 - q, q) | |
| half = one(T) / 2 | |
| if x < 0 && ν < (0x1p-26 * x)^2 | |
| return -log(abs(x)) * ν + log(ν) * muladd(ν, half, -1) - logbeta(ν / 2, half) | |
| end | |
| q = half * beta_inc(ν / 2, half, ν / muladd(x, x, ν))[1] | |
| return ifelse(q > 0, 1 - q, q) |
Summary of suggested changes:
- Functional:
- Change
-1.to-1to avoid promotion toFloat64. - Use
one(T) / 2in place ofT(0.5)sinceTmay not be closed under division, so this ensures that the use of 1/2 matches the type ofν / 2. Alternatively, you could useT(0.5) * νin place ofν / 2or1 // 2in place ofT(0.5). (If the latter, you'd just need to ensure there's a method ofbeta_incthat can deal withRationals.)
- Change
- Stylistic:
- The body of the
ifhad an errant 3-space indent. - The surrounding code in this file uses spaces around
*and/so this should be consistent.
- The body of the
These suggestions apply to the other functions here as well.
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.
Thanks a lot for the work! I think in the tdistcdf function, this line
return ifelse(q > 0, 1 - q, q)
should be changed to
return ifelse(x > 0, 1 - q, q)
Else one gets wrong cdfs for negative data, i.e.:
tdistcdf(1., 100.) #0.997
tdistcdf(1., -100.) #0.997
|
|
||
| function tdistinvcdf(ν, x::Real) | ||
| if x > .5 | ||
| return -tdistinvcdf(d, 1-x) |
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.
| return -tdistinvcdf(d, 1-x) | |
| return -tdistinvcdf(ν, 1 - x) |
|
Also, this is only an observation wrt usage of the new cdf, but I think the proposed cdf version does not yet work with Automatic differentiation, as the function using Distributions, DistributionsAD, StatsBase
using ForwardDiff, ReverseDiff
using StatsFuns
function _tdistcdf(ν::S, x::T) where {S<:Real, T<:Real}
if x < 0 && ν < (0x1p-26 * x)^2
return -log(abs(x))*ν + log(ν)*StatsFuns.muladd(ν, T(.5), -1.) - StatsFuns.logbeta(ν/2, T(.5))
end
q = T(0.5)*StatsFuns.beta_inc(ν/2, T(.5), ν/muladd(x, x, ν))[1]
return ifelse(x > 0, 1 - q, q)
end
function tdistinvcdf(ν, x::Real)
if x > .5
return -tdistinvcdf(d, 1-x)
end
end
function mytargetfunction(data::AbstractVector)
function obtaingradient(ν::AbstractVector{R}) where {R<:Real}
nu = ν[1]
data_uniform = [_tdistcdf(nu, data[iter]) for iter in eachindex(data)]
return sum(data_uniform)
end
end
#working
ν = [3.0]
data = randn(1000)
target = mytargetfunction(data)
target(ν)
#not working
ForwardDiff.gradient(target, ν) #MethodError: no method matching _beta_inc(::ForwardDiff.Dual
ReverseDiff.gradient(target, ν) #MethodError: no method matching _beta_inc(::ReverseDiff.TrackedReal
|
|
Superseded by #149. |
What should I have for type asserts? They were not added with any specific principles.