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

Forced periodicity (modulo) breaks ForwardDiff

Open TS-CUBED opened this issue 3 years ago • 2 comments

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.

TS-CUBED avatar Jun 17 '21 11:06 TS-CUBED

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.

mcabbott avatar Jul 05 '21 20:07 mcabbott

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

TS-CUBED avatar Jul 06 '21 21:07 TS-CUBED