Hi,
recently I noticed some code I’ve been using broke after updating Forward Diff. The issue came from sampling with Turing using a binomial likelihood. Digging into it it boiled down to this:
using ForwardDiff
using Distributions
d = ForwardDiff.Dual(1.0,2.0);
Binomial(1,d)
which results in the error
ERROR: DomainError with Dual{Nothing}(1.0,2.0):
Binomial: the condition zero(p) <= p <= one(p) is not satisfied.
Stacktrace:
[1] #79
@ ~/.julia/packages/Distributions/psM3H/src/univariate/discrete/binomial.jl:33 [inlined]
[2] check_args
@ ~/.julia/packages/Distributions/psM3H/src/utils.jl:89 [inlined]
[3] #Binomial#77
@ ~/.julia/packages/Distributions/psM3H/src/univariate/discrete/binomial.jl:33 [inlined]
[4] Binomial(n::Int64, p::ForwardDiff.Dual{Nothing, Float64, 1})
@ Distributions ~/.julia/packages/Distributions/psM3H/src/univariate/discrete/binomial.jl:32
[5] top-level scope
@ REPL[7]:1
Diggin deeper I found it this is caused by changes on how ForwardDiff treats comparisons of Dual numbers in between versions 0.10.38 and 1.0.0 (specifically this PR with its changes to dual.jl: https://github.com/JuliaDiff/ForwardDiff.jl/pull/481). In practice it means that we have:
julia> d = ForwardDiff.Dual(1.0,2.0); d<=one(d)
false
julia> d = ForwardDiff.Dual(1.0,-2.0); d<=one(d)
true
And a similar things happens at zero. I understand the motivation of this change in ForwardDiff, but this does produce unusual behavior in instances like this. Wondering if this is an actual bug and some change should be done somewhere. In practice for now I can get almost equivalent results for my use case by slightly translating the probability away from zero and one, e.g.:
d = ForwardDiff.Dual(1.0,2.0); d<=one(d)
d = d*(1-1e-15)+5e-16
Binomial(1,d)
but that’s really just a dirty workaround and can imagine many users running into this not knowing how to sort it out.