1
1
using DiffRules
2
2
using Test
3
+ using FiniteDifferences
3
4
4
5
using IrrationalConstants: fourπ
5
6
6
7
import SpecialFunctions, NaNMath, LogExpFunctions
7
8
import Random
8
9
Random. seed! (1 )
9
10
10
- function finitediff (f, x)
11
- ϵ = cbrt (eps (typeof (x))) * max (one (typeof (x)), abs (x))
12
- return (f (x + ϵ) - f (x - ϵ)) / (ϵ + ϵ)
13
- end
11
+ # Set `max_range` to avoid domain errors.
12
+ const finitediff = central_fdm (5 , 1 , max_range= 1e-3 )
14
13
15
14
@testset " DiffRules" begin
16
15
@testset " check rules" begin
@@ -23,24 +22,27 @@ for (M, f, arity) in DiffRules.diffrules(; filter_modules=nothing)
23
22
if arity == 1
24
23
@test DiffRules. hasdiffrule (M, f, 1 )
25
24
deriv = DiffRules. diffrule (M, f, :goo )
26
- modifier = if f in (:asec , :acsc , :asecd , :acscd , :acosh , :acoth )
27
- one (T)
28
- elseif f === :log1mexp
29
- - one (T)
30
- elseif f === :log2mexp
31
- - (one (T) / 2 )
32
- else
33
- zero (T)
34
- end
35
25
@eval begin
36
26
let
37
- goo = rand ($ T) + $ modifier
27
+ goo = if $ (f in (:asec , :acsc , :asecd , :acscd , :acosh , :acoth ))
28
+ # avoid singularities with finite differencing
29
+ rand ($ T) + $ T (1.5 )
30
+ elseif $ (f in (:log , :airyaix , :airyaiprimex ))
31
+ # avoid singularities with finite differencing
32
+ rand ($ T) + $ T (0.5 )
33
+ elseif $ (f === :log1mexp )
34
+ rand ($ T) - one ($ T)
35
+ elseif $ (f in (:log2mexp , :erfinv ))
36
+ rand ($ T) - $ T (0.5 )
37
+ else
38
+ rand ($ T)
39
+ end
38
40
@test $ deriv isa $ T
39
- @test isapprox ( $ deriv, finitediff ($ M.$ f, goo), rtol= 0.05 )
41
+ @test $ deriv ≈ finitediff ($ M.$ f, goo) rtol= 1e-3 atol = 1e-3
40
42
# test for 2pi functions
41
- if " mod2pi " == string ( $ M. $ f )
42
- goo = $ (fourπ) + $ modifier
43
- @test $ T ( NaN ) === $ deriv
43
+ if $ (f === :mod2pi )
44
+ goo = 4 * pi
45
+ @test NaN === $ deriv
44
46
end
45
47
end
46
48
end
@@ -49,17 +51,28 @@ for (M, f, arity) in DiffRules.diffrules(; filter_modules=nothing)
49
51
derivs = DiffRules. diffrule (M, f, :foo , :bar )
50
52
@eval begin
51
53
let
52
- if " mod" == string ($ M.$ f)
53
- foo, bar = rand ($ T) + 13 , rand ($ T) + 5 # make sure x/y is not integer
54
+ foo, bar = if $ (f === :mod )
55
+ rand () + 13 , rand () + 5 # make sure x/y is not integer
56
+ elseif $ (f === :polygamma )
57
+ rand (1 : 10 ), rand () # only supports integers as first arguments
58
+ elseif $ (f in (:bessely , :besselyx ))
59
+ # avoid singularities with finite differencing
60
+ rand (), rand () + 0.5
61
+ elseif $ (f === :log )
62
+ # avoid singularities with finite differencing
63
+ rand () + 1.5 , rand ()
64
+ elseif $ (f === :^ )
65
+ # avoid singularities with finite differencing
66
+ rand () + 0.5 , rand ()
54
67
else
55
- foo, bar = rand (1 : 10 ), rand ($ T )
68
+ rand (), rand ()
56
69
end
57
70
dx, dy = $ (derivs[1 ]), $ (derivs[2 ])
58
71
if ! (isnan (dx))
59
- @test isapprox (dx, finitediff (z -> $ M.$ f (z, bar), float ( foo)), rtol= 0.05 )
72
+ @test dx ≈ finitediff (z -> $ M.$ f (z, bar), foo) rtol= 1e-3 atol = 1e-3
60
73
end
61
74
if ! (isnan (dy))
62
- @test isapprox (dy, finitediff (z -> $ M.$ f (foo, z), bar), rtol= 0.05 )
75
+ @test dy ≈ finitediff (z -> $ M.$ f (foo, z), bar) rtol= 1e-3 atol = 1e-3
63
76
end
64
77
end
65
78
end
0 commit comments