Skip to content

Commit 489e294

Browse files
authored
Add missing rules for SpecialFunctions 0.10 (#79)
* Add missing rules for SpecialFunctions 0.10 * Update tests * Bump version * Update runtests.jl * Add rule for `erf(x, y)` * Fix typos * Try to use `forward_fdm` * Use forward_fdm only for log, acoth, airyaix and airyaiprimex * Update runtests.jl * Fix binary tests * Update runtests.jl * Update tests * Fix tests * Update runtests.jl * Add rule for `logabsgamma` * Revert "Add rule for `logabsgamma`" This reverts commit 7cef376.
1 parent 88ad24c commit 489e294

3 files changed

Lines changed: 79 additions & 20 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "DiffRules"
22
uuid = "b552c78f-8df3-52c6-915a-8e097449b14b"
3-
version = "1.11.1"
3+
version = "1.12.0"
44

55
[deps]
66
IrrationalConstants = "92d709cd-6900-40b7-9082-c6be49f344b6"

src/rules.jl

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,17 @@ _abs_deriv(x) = signbit(x) ? -one(x) : one(x)
116116
@define_diffrule SpecialFunctions.erfinv(x) =
117117
:( ($sqrtπ * exp(SpecialFunctions.erfinv($x)^2)) / 2 )
118118
@define_diffrule SpecialFunctions.erfc(x) = :( -($invsqrtπ * exp(-$x^2) * 2) )
119+
@define_diffrule SpecialFunctions.logerfc(x) =
120+
:( - 2 * ($invsqrtπ * exp(- $x^2 - SpecialFunctions.logerfc($x))) )
121+
119122
@define_diffrule SpecialFunctions.erfcinv(x) =
120123
:( -($sqrtπ * exp(SpecialFunctions.erfcinv($x)^2)) / 2 )
121124
@define_diffrule SpecialFunctions.erfi(x) = :( $invsqrtπ * exp($x^2) * 2 )
122125
@define_diffrule SpecialFunctions.erfcx(x) =
123126
:( 2 * (($x * SpecialFunctions.erfcx($x)) - $invsqrtπ) )
124127
@define_diffrule SpecialFunctions.logerfcx(x) =
125128
:( 2 * ($x - inv(SpecialFunctions.erfcx($x) * $sqrtπ)) )
129+
126130
@define_diffrule SpecialFunctions.dawson(x) =
127131
:( 1 - (2 * $x * SpecialFunctions.dawson($x)) )
128132
@define_diffrule SpecialFunctions.digamma(x) =
@@ -131,14 +135,35 @@ _abs_deriv(x) = signbit(x) ? -one(x) : one(x)
131135
:( inv(SpecialFunctions.trigamma(SpecialFunctions.invdigamma($x))) )
132136
@define_diffrule SpecialFunctions.trigamma(x) =
133137
:( SpecialFunctions.polygamma(2, $x) )
138+
139+
# derivatives for `airybix` and `airybiprimex` are only correct for real inputs
140+
# `airyaix` and `airyaiprimex` are only defined for positive real inputs
141+
# `airybix` and `airybiprimex` are unscaled for negative real inputs
134142
@define_diffrule SpecialFunctions.airyai(x) =
135143
:( SpecialFunctions.airyaiprime($x) )
136144
@define_diffrule SpecialFunctions.airyaiprime(x) =
137145
:( $x * SpecialFunctions.airyai($x) )
146+
@define_diffrule SpecialFunctions.airyaix(x) =
147+
:( SpecialFunctions.airyaiprimex($x) + sqrt($x) * SpecialFunctions.airyaix($x) )
148+
@define_diffrule SpecialFunctions.airyaiprimex(x) =
149+
:( $x * SpecialFunctions.airyaix($x) + sqrt($x) * SpecialFunctions.airyaiprimex($x) )
138150
@define_diffrule SpecialFunctions.airybi(x) =
139151
:( SpecialFunctions.airybiprime($x) )
140152
@define_diffrule SpecialFunctions.airybiprime(x) =
141153
:( $x * SpecialFunctions.airybi($x) )
154+
@define_diffrule SpecialFunctions.airybix(x) =
155+
:( if $x > zero($x)
156+
SpecialFunctions.airybiprimex($x) - sqrt($x) * SpecialFunctions.airybix($x)
157+
else
158+
SpecialFunctions.airybiprimex($x)
159+
end )
160+
@define_diffrule SpecialFunctions.airybiprimex(x) =
161+
:( if $x > zero($x)
162+
$x * SpecialFunctions.airybix($x) - sqrt($x) * SpecialFunctions.airybiprimex($x)
163+
else
164+
$x * SpecialFunctions.airybix($x)
165+
end )
166+
142167
@define_diffrule SpecialFunctions.besselj0(x) =
143168
:( -SpecialFunctions.besselj1($x) )
144169
@define_diffrule SpecialFunctions.besselj1(x) =
@@ -148,49 +173,72 @@ _abs_deriv(x) = signbit(x) ? -one(x) : one(x)
148173
@define_diffrule SpecialFunctions.bessely1(x) =
149174
:( (SpecialFunctions.bessely0($x) - SpecialFunctions.bessely(2, $x)) / 2 )
150175

176+
@define_diffrule SpecialFunctions.sinint(x) = :( sinc($x / π) )
177+
@define_diffrule SpecialFunctions.cosint(x) = :( cos($x) / $x )
178+
179+
@define_diffrule SpecialFunctions.ellipk(m) =
180+
:( (SpecialFunctions.ellipe($m) / (1 - $m) - SpecialFunctions.ellipk($m)) / (2 * $m) )
181+
@define_diffrule SpecialFunctions.ellipe(m) =
182+
:( (SpecialFunctions.ellipe($m) - SpecialFunctions.ellipk($m)) / (2 * $m) )
183+
151184
# TODO:
152185
#
153186
# eta
154187
# zeta
155-
# airyaix
156-
# airyaiprimex
157-
# airybix
158-
# airybiprimex
159188

160189
# binary #
161190
#--------#
162191

192+
@define_diffrule SpecialFunctions.erf(x, y) =
193+
:( -2 * ($invsqrtπ * exp(-$x^2)) ), :( 2 * ($invsqrtπ * exp(-$y^2)) )
194+
195+
# derivatives with respect to the order `ν` exist but are not implemented
196+
# (analogously to the ChainRules definitions in SpecialFunctions)
197+
198+
# derivatives for `besselix`, `besseljx` and `besselyx` are only correct for real inputs
199+
# see https://github.com/JuliaMath/SpecialFunctions.jl/blob/master/src/chainrules.jl
200+
# for forward-mode and reverse-mode derivatives for complex inputs
201+
163202
@define_diffrule SpecialFunctions.besselj(ν, x) =
164203
:NaN, :( (SpecialFunctions.besselj($ν - 1, $x) - SpecialFunctions.besselj($ν + 1, $x)) / 2 )
204+
@define_diffrule SpecialFunctions.besseljx(ν, x) =
205+
:NaN, :( (SpecialFunctions.besseljx($ν - 1, $x) - SpecialFunctions.besseljx($ν + 1, $x)) / 2 )
165206
@define_diffrule SpecialFunctions.besseli(ν, x) =
166207
:NaN, :( (SpecialFunctions.besseli($ν - 1, $x) + SpecialFunctions.besseli($ν + 1, $x)) / 2 )
208+
@define_diffrule SpecialFunctions.besselix(ν, x) =
209+
:NaN, :( (SpecialFunctions.besselix($ν - 1, $x) + SpecialFunctions.besselix($ν + 1, $x)) / 2 - sign($x) * SpecialFunctions.besselix($ν, $x) )
167210
@define_diffrule SpecialFunctions.bessely(ν, x) =
168211
:NaN, :( (SpecialFunctions.bessely($ν - 1, $x) - SpecialFunctions.bessely($ν + 1, $x)) / 2 )
212+
@define_diffrule SpecialFunctions.besselyx(ν, x) =
213+
:NaN, :( (SpecialFunctions.besselyx($ν - 1, $x) - SpecialFunctions.besselyx($ν + 1, $x)) / 2 )
169214
@define_diffrule SpecialFunctions.besselk(ν, x) =
170215
:NaN, :( -(SpecialFunctions.besselk($ν - 1, $x) + SpecialFunctions.besselk($ν + 1, $x)) / 2 )
216+
@define_diffrule SpecialFunctions.besselkx(ν, x) =
217+
:NaN, :( -(SpecialFunctions.besselkx($ν - 1, $x) + SpecialFunctions.besselkx($ν + 1, $x)) / 2 + SpecialFunctions.besselkx($ν, $x) )
218+
@define_diffrule SpecialFunctions.besselh(ν, x) =
219+
:NaN, :( (SpecialFunctions.besselh($ν - 1, $x) - SpecialFunctions.besselh($ν + 1, $x)) / 2 )
220+
@define_diffrule SpecialFunctions.besselhx(ν, x) =
221+
:NaN, :( (SpecialFunctions.besselhx($ν - 1, $x) - SpecialFunctions.besselhx($ν + 1, $x)) / 2 - im * SpecialFunctions.besselhx($ν, $x) )
171222
@define_diffrule SpecialFunctions.hankelh1(ν, x) =
172223
:NaN, :( (SpecialFunctions.hankelh1($ν - 1, $x) - SpecialFunctions.hankelh1($ν + 1, $x)) / 2 )
224+
@define_diffrule SpecialFunctions.hankelh1x(ν, x) =
225+
:NaN, :( (SpecialFunctions.hankelh1x($ν - 1, $x) - SpecialFunctions.hankelh1x($ν + 1, $x)) / 2 - im * SpecialFunctions.hankelh1x($ν, $x) )
173226
@define_diffrule SpecialFunctions.hankelh2(ν, x) =
174227
:NaN, :( (SpecialFunctions.hankelh2($ν - 1, $x) - SpecialFunctions.hankelh2($ν + 1, $x)) / 2 )
228+
@define_diffrule SpecialFunctions.hankelh2x(ν, x) =
229+
:NaN, :( (SpecialFunctions.hankelh2x($ν - 1, $x) - SpecialFunctions.hankelh2x($ν + 1, $x)) / 2 + im * SpecialFunctions.hankelh2x($ν, $x) )
230+
175231
@define_diffrule SpecialFunctions.polygamma(m, x) =
176232
:NaN, :( SpecialFunctions.polygamma($m + 1, $x) )
233+
177234
@define_diffrule SpecialFunctions.beta(a, b) =
178235
:( SpecialFunctions.beta($a, $b)*(SpecialFunctions.digamma($a) - SpecialFunctions.digamma($a + $b)) ), :( SpecialFunctions.beta($a, $b)*(SpecialFunctions.digamma($b) - SpecialFunctions.digamma($a + $b)) )
179-
@define_diffrule SpecialFunctions.logbeta(a, b) =
236+
@define_diffrule SpecialFunctions.logbeta(a, b) =
180237
:( SpecialFunctions.digamma($a) - SpecialFunctions.digamma($a + $b) ), :( SpecialFunctions.digamma($b) - SpecialFunctions.digamma($a + $b) )
181238

182-
# TODO:
183-
#
184-
# zeta
185-
# besseljx
186-
# besselyx
187-
# besselix
188-
# besselkx
189-
# besselh
190-
# besselhx
191-
# hankelh1x
192-
# hankelh2
193-
# hankelh2x
239+
# derivative wrt to `s` is not implemented
240+
@define_diffrule SpecialFunctions.zeta(s, z) =
241+
:NaN, :( - $s * SpecialFunctions.zeta($s + 1, $z) )
194242

195243
# ternary #
196244
#---------#

test/runtests.jl

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ for xtype in [:Float64, :BigFloat, :Int64]
118118
x = $xtype(rand(1 : 10))
119119
y = $mode
120120
dx, dy = $(derivs[1]), $(derivs[2])
121-
@test isapprox(dx, finitediff(z -> rem2pi(z, y), float(x)), rtol=0.05)
121+
@test dx finitediff(z -> rem2pi(z, y), float(x)) rtol=1e-9 atol=1e-9
122122
@test isnan(dy)
123123
end
124124
end
@@ -134,13 +134,24 @@ for xtype in [:Float64, :BigFloat]
134134
x = rand($xtype)
135135
y = $ytype(rand(1 : 10))
136136
dx, dy = $(derivs[1]), $(derivs[2])
137-
@test isapprox(dx, finitediff(z -> ldexp(z, y), x), rtol=0.05)
137+
@test dx finitediff(z -> ldexp(z, y), x) rtol=1e-9 atol=1e-9
138138
@test isnan(dy)
139139
end
140140
end
141141
end
142142
end
143143

144+
# Check negative branch for `airybix` and `airybiprimex`
145+
for f in (:airybix, :airybiprimex)
146+
deriv = DiffRules.diffrule(:SpecialFunctions, f, :goo)
147+
@eval begin
148+
let
149+
goo = -rand()
150+
@test $deriv finitediff(SpecialFunctions.$f, goo) rtol=1e-9 atol=1e-9
151+
end
152+
end
153+
end
154+
144155
# Test `iszero(x)` branch of `xlogy`
145156
derivs = DiffRules.diffrule(:LogExpFunctions, :xlogy, :x, :y)
146157
for xytype in [:Float32, :Float64, :BigFloat]

0 commit comments

Comments
 (0)