Motivation
I am numerically evaluating a deeply-nested multiple integral. At each nesting level I get a vector of integrals at the level below, which are multiplied by a vector of density functions to give the vector of integrands y
at this level. The x
values are unevenly spaced.
The integrand is curved and a trapezoidal integration is not sufficiently accurate, so I want to do an integration that allows for curvature. Simpson's Rule is not applicable because the abscissae are not evenly spaced. So I propose to do a cubic spline interpolation and then calculate the integral of the spline function by analytically calculating the integral of the cubic in each segment.
Question
I have been looking at functions like spline
and splinefun
as well as those in the splines2
package. But I cannot find anything that tells me the coefficients of the series of cubic polynomials - one per segment between knots.
I would be grateful if somebody could point me to a function that does the spline interpolation and makes available the array of cubic coefficients.
Thank you.
This is a great opportunity to extend my new answer here: How to save and load spline interpolation functions in R? With that piecewise parametrization, it is easy to compute piecewise integral.
Here is a (vectorized) function for its computation:
## a function for integration on a piece
piecewise_int <- function (hi, yi, bi, ci, di) {
yi * hi + bi * hi ^ 2 / 2 + ci * hi ^ 3 / 3 + di * hi ^ 4 / 4
}
In the following, I will take the small example in that thread, showing how to integrate the spline.
## the small example in the linked thread
set.seed(0)
xk <- c(0, 1, 2)
yk <- round(runif(3), 2)
f <- splinefun(xk, yk, "natural") ## natural cubic spline
construction_info <- environment(f)$z
## information for integration
int_info <- with(construction_info,
list(h = diff(x), y = y[-n], b = b[-n], c = c[-n], d = d[-n])
)
## cubic spline integration on all pieces
integral <- sum(do.call(piecewise_int, int_info))
#[1] 0.81375
We can also perform a numerical integration to verify this result.
integrate(f, 0, 2)
#0.81375 with absolute error < 9e-15