ForwardDiff.jl
ForwardDiff.jl copied to clipboard
Forced periodicity (modulo) breaks ForwardDiff
It seems that modulo periodicity that seems to break ForwardDiff:
If I give it a very simple function that should be differentiable, but use a modulo for time, then this happens:
#+begin_src julia
function f(t)
sin(pi * 2 * (t % 1))^2
end
#+end_src
#+RESULTS:
: f (generic function with 1 method)
#+begin_src julia
ForwardDiff.derivative(f, 1)
#+end_src
#+RESULTS:
: NaN
#+begin_src julia
derivative(f, 1)
#+end_src
#+RESULTS:
: -5.736299254432828e-15
So the result from the CD is close to zero, as expected. But the ForwardDiff gives NaN. If I take the modulo out, then AutoDiff works.
So while I took care that my functions are continuous, smooth and differentiable at the period boundaries, AutoDiff will not work for them. It does work for cosine series, which are naturally periodic, but not with piecewise continuous functions with modulo periodicity.
Your complaint is this:
julia> using ForwardDiff: Dual
julia> rem(Dual(0.001, 2), 3)
Dual{Nothing}(0.001,2.0)
julia> rem(Dual(0.0, 2), 3)
Dual{Nothing}(0.0,NaN)
julia> rem(Dual(3.0, 2), 3)
Dual{Nothing}(0.0,NaN)
which is defined here:
https://github.com/JuliaDiff/DiffRules.jl/blob/42b11d0d07dbb9b1f552398bdf5a79e4f403edcf/src/rules.jl#L99
rem
is actually continuous at zero, unlike mod
, so perhaps the first NaN above is a bug? The others seem like a choice, and you could argue they should be slope 1 everywhere. Not sure how this was decided.
That did help me in finding a solution to the problem using floor division to get the remainder - not sure why this works if rem
and mod
don't, but hey:
#+begin_src julia
function f(t)
times = t ÷ 1
t = t - times
sin(pi * 2 * t)^2 * (t < 0.5)
end
#+end_src
#+RESULTS:
: f (generic function with 1 method)
#+begin_src julia
ForwardDiff.derivative(f, 1)
#+end_src
#+RESULTS:
: 0.0
#+begin_src julia
derivative(f, 1)
#+end_src
#+RESULTS:
: 0.00011952987976706194