# Custom univariate distribution in Turing.jl

**URL:** https://discourse.julialang.org/t/custom-univariate-distribution-in-turing-jl/38874
**Category:** Probabilistic Programming
**Tags:** question, turing
**Created:** [May 6, 2020, 9:40am UTC](https://discourse.julialang.org/t/custom-univariate-distribution-in-turing-jl/38874 "2020-05-06T09:40:40Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![SSU](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ssu/32/11306_2.png) [@SSU](https://discourse.julialang.org/u/SSU)
#### Post date: [May 6, 2020, 9:40am UTC](https://discourse.julialang.org/t/custom-univariate-distribution-in-turing-jl/38874/1 "2020-05-06T09:40:41Z")

</div>

I’m trying to use customized univariate distribution in `Turing.jl`.  
(The domain is 0 ~ +Inf)

I implemented `Distributions.pdf, logpdf, rand, minimum, maximum etc,` referring the document ([Advanced Usage](https://turing.ml/dev/docs/using-turing/advanced)).  
I’m pretty sure that every methods are working fine.

However, sampling from the following model returns the following error.  
At least I understand that this error is coming from `ForwardDiff.jl` but I have no clue where to fix…

Any suggestions are welcomed.  
Thank you in advance.

* * *

## Implementation of the custom distribution

```julia
import Distributions:@distr_support, minimum, maximum, pdf, cdf, quantile, logpdf, rand
mutable struct Diffusion{T<:Real} <: ContinuousUnivariateDistribution
    D::T
    δ::T
    ϵ::T
    Diffusion{T}(D::T, δ::T, ϵ::T) where {T <: Real} = new{T}(D, δ, ϵ)
end

function Diffusion(D::T, δ::T, ϵ::T; check_args = true) where {T <: Real}
    check_args && Distributions.@check_args(
        Diffusion, D > zero(D) && δ > zero(δ) && ϵ >= zero(ϵ)
    )
    return Diffusion{T}(D, δ, ϵ)
end

Distributions.@distr_support Diffusion 0 +Inf
Distributions.minimum(d::Diffusion) = 0.0
Distributions.maximum(d::Diffusion) = +Inf

Distributions.cdf(d::Diffusion, x::Real) where T <: Real =
    1 - exp(-x^2 / 4(d.D * d.δ + d.ϵ^2))
Distributions.quantile(d::Diffusion, p) = sqrt(-4(d.D * d.δ + d.ϵ^2) * log(1 - p))
Distributions.pdf(d::Diffusion, x::Float64) =
    0 ≤ x ? x / 2(d.D * d.δ + d.ϵ^2) * exp(-x^2 / 4(d.D * d.δ + d.ϵ^2)) : zero(x)
Distributions.logpdf(d::Diffusion, x::AbstractArray{<:Real}) =
    0 ≤ x ? log(x) - log(2(d.D * d.δ + d.ϵ^2)) - (x^2 / (4(d.D * d.δ + d.ϵ^2))) : zero(x)
Distributions.quantile(d::Diffusion, x::AbstractVector{<:Real}) = sqrt(-4(d.D * d.δ + d.ϵ^2) * log(1 - x))
Distributions.rand(d::Diffusion, rng::AbstractVector{<:Real}) =
    Distributions.quantile(d::Diffusion, rng)

```

* * *

## Code for `Turing.jl`

```julia
@model MyModel(x) = begin
    a ~ Gamma(1., 1.)
    N = length(x)
    for n in 1:N
        x[n] ~ Diffusion(a, 0.02, 0.03)
    end
end

# run sampler
x = rand(Diffusion(0.5, 0.02, 0.03), 1000)
sample(MyModel(x), NUTS(0.65), 1000)

```

* * *

## Error messages

```julia
MethodError: no method matching Diffusion(::ForwardDiff.Dual{ForwardDiff.Tag{Turing.Core.var"#f#7"{DynamicPPL.VarInfo{NamedTuple{(:a,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:a},Int64},Array{Gamma{Float64},1},Array{DynamicPPL.VarName{:a},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64},DynamicPPL.Model{var"##inner_function#593#21",NamedTuple{(:x,),Tuple{Array{Float64,1}}},DynamicPPL.ModelGen{(:x,),var"###MyModel#607",NamedTuple{(),Tuple{}}},Val{()}},DynamicPPL.Sampler{NUTS{Turing.Core.ForwardDiffAD{40},(),AdvancedHMC.Adaptation.DiagEuclideanMetric},Turing.Inference.SamplerState{DynamicPPL.VarInfo{NamedTuple{(:a,),Tuple{DynamicPPL.Metadata{Dict{DynamicPPL.VarName{:a},Int64},Array{Gamma{Float64},1},Array{DynamicPPL.VarName{:a},1},Array{Float64,1},Array{Set{DynamicPPL.Selector},1}}}},Float64}}}},Float64},Float64,1}, ::Float64, ::Float64)
Closest candidates are:
  Diffusion(::T, !Matched::T, !Matched::T; check_args) where T<:Real at In[23]:14
  ...

```

---

<div class="post-metadata">

### Author: ![trappmartin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/trappmartin/32/1165_2.png) [@trappmartin](https://discourse.julialang.org/u/trappmartin)
#### Post date: [May 6, 2020, 9:50am UTC](https://discourse.julialang.org/t/custom-univariate-distribution-in-turing-jl/38874/2 "2020-05-06T09:50:26Z")

</div>

You seem to be calling a different model then the one defined. Could you post a MWE please.

---

<div class="post-metadata">

### Author: ![SSU](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ssu/32/11306_2.png) [@SSU](https://discourse.julialang.org/u/SSU)
#### Post date: [May 6, 2020, 10:06am UTC](https://discourse.julialang.org/t/custom-univariate-distribution-in-turing-jl/38874/3 "2020-05-06T10:06:58Z")

</div>

Thank you for your reply.  
Sorry, I think I pasted something different.  
I edited the first post.

---

<div class="post-metadata">

### Author: ![trappmartin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/trappmartin/32/1165_2.png) [@trappmartin](https://discourse.julialang.org/u/trappmartin)
#### Post date: [May 6, 2020, 10:27am UTC](https://discourse.julialang.org/t/custom-univariate-distribution-in-turing-jl/38874/4 "2020-05-06T10:27:04Z")

</div>

You defined you distribution in a way that all parameters need to be of the same type.

> [@SSU](#):
>
> mutable struct Diffusion{T\<:Real} \<: ContinuousUnivariateDistribution

During AD, the type of `a` in `x[n] ~ Diffusion(a, 0.02, 0.03)` will inevitably change. So you could do the following instead:

```julia
struct Diffusion{T1<:Real,T2<:Real,T3<:Real} <: ContinuousUnivariateDistribution
    D::T1
    δ::T2
    ϵ::T3
    Diffusion{T1,T2,T3}(D::T1, δ::T2, ϵ::T3) where {T1<:Real,T2<:Real,T3<:Real} = new{T1,T2,T3}(D, δ, ϵ)
end

```

and change the remaining codes accordingly. Also, the distribution doesn’t need to be mutable. Just use `struct`, this way Julia will be more happy. 😉

---

<div class="post-metadata">

### Author: ![SSU](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ssu/32/11306_2.png) [@SSU](https://discourse.julialang.org/u/SSU)
#### Post date: [May 6, 2020, 10:58am UTC](https://discourse.julialang.org/t/custom-univariate-distribution-in-turing-jl/38874/5 "2020-05-06T10:58:41Z")

</div>

So these codes are different!  
I didn’t know that 😵

```julia
Diffusion{T1,T2,T3}(D::T1, δ::T2, ϵ::T3) where {T1<:Real,T2<:Real,T3<:Real}
Diffusion{T}(D::T, δ::T, ϵ::T) where {T:<Real}

```

The sampler started working!  
I’ve learned a lot!  
Thank you so much😊!!!
