Skip to content

Commit 61a7c5b

Browse files
authored
Define SpecialFunctions.gamma_inc for ForwardDiff.Dual (#587)
* Define `SpecialFunctions.gamma_inc` for `ForwardDiff.Dual` * Try to fix tolerances * Check if primal method exists * Fix tolerances
1 parent f365d41 commit 61a7c5b

File tree

3 files changed

+34
-5
lines changed

3 files changed

+34
-5
lines changed

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ForwardDiff"
22
uuid = "f6369f11-7733-5829-9624-2563aa707210"
3-
version = "0.10.30"
3+
version = "0.10.31"
44

55
[deps]
66
CommonSubexpressions = "bbf7d656-a473-5ed7-a52c-81e309532950"
@@ -24,7 +24,7 @@ DiffTests = "0.0.1, 0.1"
2424
LogExpFunctions = "0.3"
2525
NaNMath = "0.2.2, 0.3, 1"
2626
Preferences = "1"
27-
SpecialFunctions = "0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.10, 1.0, 2"
27+
SpecialFunctions = "0.8, 0.9, 0.10, 1.0, 2"
2828
StaticArrays = "0.8.3, 0.9, 0.10, 0.11, 0.12, 1.0"
2929
julia = "1"
3030

src/dual.jl

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -755,16 +755,24 @@ function LinearAlgebra.eigen(A::SymTridiagonal{<:Dual{Tg,T,N}}) where {Tg,T<:Rea
755755
Eigen(λ,Dual{Tg}.(Q, tuple.(parts...)))
756756
end
757757

758-
# SpecialFunctions.logabsgamma #
759-
# Derivative is not defined in DiffRules #
760-
#----------------------------------------#
758+
# Functions in SpecialFunctions which return tuples #
759+
# Their derivatives are not defined in DiffRules #
760+
#---------------------------------------------------#
761761

762762
function SpecialFunctions.logabsgamma(d::Dual{T,<:Real}) where {T}
763763
x = value(d)
764764
y, s = SpecialFunctions.logabsgamma(x)
765765
return (Dual{T}(y, SpecialFunctions.digamma(x) * partials(d)), s)
766766
end
767767

768+
# Derivatives wrt to first parameter and precision setting are not supported
769+
function SpecialFunctions.gamma_inc(a::Real, d::Dual{T,<:Real}, ind::Integer) where {T}
770+
x = value(d)
771+
p, q = SpecialFunctions.gamma_inc(a, x, ind)
772+
∂p = exp(-x) * x^(a - 1) / SpecialFunctions.gamma(a) * partials(d)
773+
return (Dual{T}(p, ∂p), Dual{T}(q, -∂p))
774+
end
775+
768776
###################
769777
# Pretty Printing #
770778
###################

test/DualTest.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,29 @@ for N in (0,3), M in (0,4), V in (Int, Float32)
540540
@test dual_isapprox(f(PRIMAL, PRIMAL2, FDNUM3), Dual{TestTag()}(f(PRIMAL, PRIMAL2, PRIMAL3), PARTIALS3))
541541
end
542542

543+
# Functions in Specialfunctions that return tuples and
544+
# therefore are not supported by DiffRules
543545
@test dual_isapprox(logabsgamma(FDNUM)[1], loggamma(abs(FDNUM)))
544546
@test dual_isapprox(logabsgamma(FDNUM)[2], sign(gamma(FDNUM)))
547+
548+
a = rand(float(V))
549+
fdnum = Dual{TestTag()}(1 + PRIMAL, PARTIALS) # 1 + PRIMAL avoids issues with finite differencing close to 0
550+
for ind in ((), (0,), (1,), (2,))
551+
# Only test if primal method exists
552+
# (e.g., older versions of SpecialFunctions don't define `gamma_inc(a, x)` but only `gamma_inc(a, x, ind)`
553+
hasmethod(gamma_inc, typeof((a, 1 + PRIMAL, ind...))) || continue
554+
555+
pq = gamma_inc(a, fdnum, ind...)
556+
@test pq isa Tuple{Dual{TestTag()},Dual{TestTag()}}
557+
# We have to adjust tolerances if lower accuracy is requested
558+
# Therefore we don't use `dual_isapprox`
559+
tol = V === Float32 ? 5f-4 : 1e-6
560+
tol = tol^(one(tol) / 2^(isempty(ind) ? 0 : first(ind)))
561+
for i in 1:2
562+
@test value(pq[i]) gamma_inc(a, 1 + PRIMAL, ind...)[i] rtol=tol
563+
@test partials(pq[i]) PARTIALS * Calculus.derivative(x -> gamma_inc(a, x, ind...)[i], 1 + PRIMAL) rtol=tol
564+
end
565+
end
545566
end
546567

547568
@testset "Exponentiation of zero" begin

0 commit comments

Comments
 (0)