SLEEF.jl icon indicating copy to clipboard operation
SLEEF.jl copied to clipboard

Automatic derivatives of SLEEF trig functions cause stack-overflow

Open MasonProtter opened this issue 7 years ago • 7 comments

Not sure if this is a SLEEF problem for a ForwardDiff problem but I would have expected a different error than a stack overflow when trying to take automatic derivatives of SLEEF trig functions.

julia> using ForwardDiff: derivative

julia> using SLEEF

julia> derivative(SLEEF.sin, 1.0)
ERROR: StackOverflowError:
Stacktrace:
 [1] sin(::ForwardDiff.Dual{ForwardDiff.Tag{typeof(SLEEF.sin),Float64},Float64,1}) at
/Users/mason/.julia/packages/SLEEF/pKpdp/src/SLEEF.jl:105 (repeats 80000 times)

Note: defining the action of trig functions on ForwardDiff.Duals does give the correct behaviour.

julia> using ForwardDiff: derivative, Dual, value, partials

julia> using SLEEF

julia> SLEEF.sin(d::Dual{T,V,N}) where {T,V,N} = Dual{T,V,N}(SLEEF.sin(value(d)), SLEEF.cos(value(d)) * partials(d))

julia> derivative(SLEEF.sin, 3.14)
-0.9999987317275395

MasonProtter avatar Sep 25 '18 19:09 MasonProtter

can you try sin_fast ? (the fast trig function doesn't use a DualNumber wrapper, which may be causing the stack overflow)

musm avatar Sep 25 '18 19:09 musm

julia> using ForwardDiff: derivative

julia> using SLEEF

julia> derivative(SLEEF.sin_fast, 1.0)
ERROR: StackOverflowError:
Stacktrace:
 [1] sin_fast(::Dual{ForwardDiff.Tag{typeof(SLEEF.sin_fast),Float64},Float64,1}) at 
/Users/mason/.julia/packages/SLEEF/pKpdp/src/SLEEF.jl:105 (repeats 80000 times)

MasonProtter avatar Sep 25 '18 19:09 MasonProtter

Ref https://github.com/JuliaLang/julia/issues/26552, particularly https://github.com/JuliaLang/julia/issues/26552#issuecomment-374980927.

tkoolen avatar Sep 25 '18 19:09 tkoolen

Ok thanks @tkoolen , it seems that this can be improved.

musm avatar Sep 27 '18 05:09 musm

So I guess the best way of going about this is something like the following?

using ForwardDiff: derivative

f(x::Union{Float32,Float64}) = exp(x)
for func in (:f,)
    priv = Symbol('_',func)
    @eval begin
    $priv(x::T) where {T<:Union{Float32,Float64}} = $func(x)
    $func(x::Real) = $priv(float(x))
    end
end

julia> derivative(f, 1.0)
ERROR: MethodError: no method matching _f(::ForwardDiff.Dual{ForwardDiff.Tag{typeof(f),Float64},Float64,1})

altough it's not clear to my why forwarddiff doesn't work without a custom wrapper.

musm avatar Oct 10 '18 15:10 musm

I was puzzeled as to why the base math function worked with ForwardDiff, but now I see that ForwardDiff relies on DiffRules to be able to differentiate the base math functions.

In principle it should be able to support SLEEF, ideally without having to add anything to DiffRules, but I am not sure how to do that.

musm avatar Oct 10 '18 15:10 musm

Is this the same reason SLEEF functions don't work with Zygote?

julia> Zygote.gradient(SLEEF.exp, 1.3)                                      
ERROR: Non-differentiable function Core.Intrinsics.bitcast

robsmith11 avatar May 07 '20 14:05 robsmith11