using StaticArrays
using ForwardDiff
using DiffResults
using BenchmarkTools
f(x) = SVector((@. x[1]*x[2]), x[1]+x[2])
df(x) = ForwardDiff.jacobian(f,x)
df_diffres(x) = ForwardDiff.jacobian!(DiffResults.JacobianResult(x),f,x)
If I benchmark each routine, the evaluation of f and df are both similar cost. However, evaluating df_diffres takes significantly longer than evaluating both the function and Jacobian.
What if you use floating point numbers? Derivatives of integers is somewhat weird…
But I see what your issue is. If you’re using DiffRules with static vectors, of course it needs to allocate it when it stores it. It really only makes sense to define temporary storage with things that would use such storage (i.e. arrays)
Thanks for the tip. If I use x = SVector(1.0,2.0), the timings change slightly but the ratios are about the same.
24.150 ns (1 allocation: 32 bytes) # timing for f
23.441 ns (1 allocation: 48 bytes) # timing for Jacobian
161.444 ns (6 allocations: 176 bytes) # timing with DiffResults
On the allocation - that makes sense. Guess I got lucky - this setup is pretty representative of my use case, where a function (with a small number of inputs/outputs) is evaluated at many states using AD.
Ah, thanks! So if I’m understanding correctly - I should expect computing Jacobian and function values simultaneously using ForwardDiff.jl/DiffResults.jl to be faster than computing them separately, but only for a large enough number of inputs/outputs?
It always computes it simultaneously: forward-mode AD cannot not do it simultaneously. However, it’s whether it’s stored in an intermediate for having the DiffRules interface: if it’s static vectors, putting it in a mutable type will currently require that it gets heap allocated, which is not great right now. However, that limitation should be lifted in v1.5 IIRC.