Search code examples
rinterpolationsplineintegralpolynomials

R: How to get piecewise coefficients of an interpolation spline for analytical integration?


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.


Solution

  • 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.

    enter image description here

    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