# T Distribution - Automatic Differentiation on quantile and cdf function

**URL:** <https://discourse.julialang.org/t/t-distribution-automatic-differentiation-on-quantile-and-cdf-function/89434>\
**Category:** General Usage\
**Tags:** differentiation, forwarddiff, distributions, autodiff\
**Created:** [October 28, 2022, 9:01am UTC](https://discourse.julialang.org/t/t-distribution-automatic-differentiation-on-quantile-and-cdf-function/89434 "2022-10-28T09:01:05Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![mrVeng](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrveng/32/8836_2.png) [@mrVeng](https://discourse.julialang.org/u/mrVeng)\
**Post date:** [October 28, 2022, 9:01am UTC](https://discourse.julialang.org/t/t-distribution-automatic-differentiation-on-quantile-and-cdf-function/89434/1 "2022-10-28T09:01:06Z")

</div>

Hi there,

I need to use the cdf (and quantile) function of the T distribution inside a function that I want to use Automatic Differentiation on. This works fine with almost any univariate distribution from the `Distributions.jl` package, but unfortunately not with the T distribution. Here is an MWE:

```julia
using ForwardDiff, ReverseDiff
using Distributions
function mytargetfunction(data::AbstractVector)
    function obtaingradient(ν::AbstractVector{R}) where {R<:Real}
        dist = Distributions.TDist(ν[1])
        data_uniform = cdf.(dist, data)
        return sum( logpdf(dist, data_uniform[i]) for i in eachindex(data_uniform) )
    end
end

#working
ν = [3.0]
data = randn(1000)
target = mytargetfunction(data)
target(ν)
#not working
ForwardDiff.gradient(target, ν) #MethodError: no method matching Float64(::ForwardDiff.Dual{ForwardDiff.Tag
ReverseDiff.gradient(target, ν) #ArgumentError: Converting an instance of ReverseDiff.TrackedReal{Float64, Float64, ReverseDiff.TrackedArray{Float64, Float64, 1, Vector{Float64}, Vector{Float64}}} to Float64 is not defined. Please use `ReverseDiff.value` instead.

```

If I swap the T distribution in the closure with, e.g., a Normal, everything works fine. Are there any alternative packages for Julia that allow me to use a AutoDiff friendly T distribution? Or does anyone know a better trick to solve that problem? I can write down the cdf/quantile function analytically but only for a few selected cases unfortunately.

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [October 28, 2022, 10:57am UTC](https://discourse.julialang.org/t/t-distribution-automatic-differentiation-on-quantile-and-cdf-function/89434/2 "2022-10-28T10:57:57Z")

</div>

[Open problem](https://github.com/JuliaStats/Distributions.jl/issues/1334)?

---

<div class="post-metadata">

**Author:** ![mrVeng](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrveng/32/8836_2.png) [@mrVeng](https://discourse.julialang.org/u/mrVeng)\
**Post date:** [October 31, 2022, 8:57am UTC](https://discourse.julialang.org/t/t-distribution-automatic-differentiation-on-quantile-and-cdf-function/89434/3 "2022-10-31T08:57:56Z")

</div>

Anyone having an idea of what I could do? I am afraid the Github link is out of my league.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [October 31, 2022, 11:36am UTC](https://discourse.julialang.org/t/t-distribution-automatic-differentiation-on-quantile-and-cdf-function/89434/4 "2022-10-31T11:36:11Z")

</div>

Finite differences are always available as workaround?

---

<div class="post-metadata">

**Author:** ![cgeoga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cgeoga/32/216186_2.png) [@cgeoga](https://discourse.julialang.org/u/cgeoga)\
**Post date:** [October 31, 2022, 1:20pm UTC](https://discourse.julialang.org/t/t-distribution-automatic-differentiation-on-quantile-and-cdf-function/89434/5 "2022-10-31T13:20:23Z")

</div>

Perhaps using `HypergeometricFunctions.jl` would be acceptable? I doubt this is as fast or robust as some other options, but in easy tests it seems to be fine:

```julia
using StatsFuns, SpecialFunctions, HypergeometricFunctions, ForwardDiff, FiniteDifferences

# not thoughtfully written at all
function tcdf(v, x)
  1/2 + x*gamma((v+1)/2)*_₂F₁(1/2, (v+1)/2, 3/2, -x*x/v)/(sqrt(pi*v)*gamma(v/2))
end

# CDF check:
@assert tcdf(1.1, 3.1) ≈ StatsFuns.tdistcdf(1.1, 3.1)

# Forward auto check:
@assert isapprox(ForwardDiff.derivative(_v->tcdf(_v, 3.1), 1.1),
                 central_fdm(10,1)(_v->tcdf(_v, 3.1), 1.1))

```

Obviously it’s preferable to have rules than to hope that `ForwardDiff` will pass through every branch of a function like that and give you the correct output—I had this fight with `besselk` a while ago, and it was an enormous pain to sort out…so I would guess the issue is even worse for a much more complicated function like 2F1.

For the quantile function, you could use a root finder on this CDF and [ImplicitDifferentiation.jl](https://github.com/gdalle/ImplicitDifferentiation.jl) to get the derivatives.

Again, though, it’s not obvious at all that a code implementation of 2F1 will give correct auto-derivatives of 2F1, so you should probably write a lot of tests that try to cover your uses cases and domain region and stuff.

Hope this helps!

---

<div class="post-metadata">

**Author:** ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)\
**Post date:** [October 31, 2022, 3:00pm UTC](https://discourse.julialang.org/t/t-distribution-automatic-differentiation-on-quantile-and-cdf-function/89434/6 "2022-10-31T15:00:57Z")

</div>

Don’t these packages address this problem?

> **[GitHub - tpapp/LogDensityProblems.jl: A common framework for implementing and...](https://github.com/tpapp/LogDensityProblems.jl)**
>
> A common framework for implementing and using log densities for inference. - GitHub - tpapp/LogDensityProblems.jl: A common framework for implementing and using log densities for inference.

> **[GitHub - TuringLang/DistributionsAD.jl: Automatic differentiation of ...](https://github.com/TuringLang/DistributionsAD.jl)**
>
> Automatic differentiation of Distributions using Tracker, Zygote, ForwardDiff and ReverseDiff - GitHub - TuringLang/DistributionsAD.jl: Automatic differentiation of Distributions using Tracker, Z...

---

<div class="post-metadata">

**Author:** ![mrVeng](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrveng/32/8836_2.png) [@mrVeng](https://discourse.julialang.org/u/mrVeng)\
**Post date:** [November 7, 2022, 3:24pm UTC](https://discourse.julialang.org/t/t-distribution-automatic-differentiation-on-quantile-and-cdf-function/89434/7 "2022-11-07T15:24:35Z")

</div>

Thanks a lot for the suggestions and your work!

I checked the manual implementation of the cdf with HypergeometricFunctions and it does work for my example! Unfortunately, it seems to segfault for quite a wide range of parameter values, making it difficult to work with.

I adjusted my expectations a bit and will try to define a custom Chainrules rule for my case to work.

---

<div class="post-metadata">

**Author:** ![mrVeng](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrveng/32/8836_2.png) [@mrVeng](https://discourse.julialang.org/u/mrVeng)\
**Post date:** [November 7, 2022, 3:26pm UTC](https://discourse.julialang.org/t/t-distribution-automatic-differentiation-on-quantile-and-cdf-function/89434/8 "2022-11-07T15:26:12Z")

</div>

Thanks for your reply!

`DistributionsAD` does indeed do that, but there does not seem to be a method defined for the cdf of the Tdistribution.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [November 7, 2022, 3:37pm UTC](https://discourse.julialang.org/t/t-distribution-automatic-differentiation-on-quantile-and-cdf-function/89434/9 "2022-11-07T15:37:41Z")

</div>

Or also there [add tdist cdfs and quantiles by oscardssmith · Pull Request #147 · JuliaStats/StatsFuns.jl · GitHub](https://github.com/JuliaStats/StatsFuns.jl/pull/147) there is a PR fixing this issue properly (implementing the right functions into StatsFuns.jl). It might just need some help to comply to the reviews and fix it properly, but this is a good start.

---

<div class="post-metadata">

**Author:** ![mrVeng](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrveng/32/8836_2.png) [@mrVeng](https://discourse.julialang.org/u/mrVeng)\
**Post date:** [November 7, 2022, 3:42pm UTC](https://discourse.julialang.org/t/t-distribution-automatic-differentiation-on-quantile-and-cdf-function/89434/10 "2022-11-07T15:42:02Z")

</div>

Thats great news, thanks for the link!
