I am wondering whether someone has insights on the following:
I have a complicated function inside which I perform smoothed (1-D) Cubic Spline interpolation using an irregular grid. Right now I am using the Dierckx.jl package for this.
In particular, the function calls something equivalent to
where x is an irregularly spaced grid and s the smoothing parameter.
Now, I wish to obtain a derivative of said function w.r.t a small number of input parameter. My usual go-to package for this would be ForwardDiff, but it is unfortunately not compatible with Dierckx.
So, I am wondering whether there are other packages with equivalent functionalities that would be. I know that e.g. Interpolations.jl or BasicInterpolators.jl are compatible with ForwardDiff, but they don’t seem to have the smoothing functionality.
I have some freedom in choosing the grid x so if there is a package that would require an regular grid, that may be helpful as well. Of course, as fallback I could resort to finite differences for getting the derivatives, but I would prefer ForwardDiff if possible.
For one of my projects I had to do something similar.
I needed the first and second derivative of a (3D) cubic spline and was using forwarddiff.
I wrote my own implementation of the spline, and the tricky bit was letting derivatives work when selecting which bezier curve.
Essentially, if my spline is formed of 3 bezier curves, and I ask evaluate(spl, 1.2), it has to figure out “call evaluate(curves[2], 0.2)”. The problem was that doing modulo on a dual number didn’t work which made finding out the index hard.
My solution was as follows:
function get_curve_and_t(t::T1, s::CubicSpline{D, T2}) where {D, T1, T2}
i = Int(ceil(t))
t_curve = t-i+1
curve = get_curve(s, i)
return curve, i, t_curve
end
Here, t is what you have called x. Comparing with my example, t=1.2, i==2 and t_curve==0.2
ceil when used on a dual number throws away the partials, which in this case is what we want. When we do t_curve - i , we get a dual number with the correct partials.
BSplineApprox should do it. It should be ForwardDiff compatible out of the box, but it also has an analytical derivative setup since differentiating the spline can be less numerically stable:
Thank you all for your help! Given what I want to do, DataInterpolations.jl seems like a good place to start and substantially simpler than an approach requiring an own implementation of the spline.
One relatively easy way to get a derivative for an arbitrary 1-dimensional cubic spline:
using BasicInterpolators
using ForwardDiff
# irregularly spaced knots
x = [0, 0.2, 1.3, 4]
# values to interpolate
y = [0.5, -2.6, -2, 0.2]
# initialize the spline
spline = CubicSplineInterpolator(x, y)
# evaluate the derivative at x = 1
ForwardDiff.derivative(spline, 1))
# evaluate the derivative at x = 1 and x = 3
map(x -> ForwardDiff.derivative(spline, x), [1, 3])