Analytical solution for linear interpolation (stable)
Suppose we have some (x, y)
data. After a linear interpolation find all x
such that the value of the interpolant equals y0
.
## with default value y0 = 0, it finds all roots of the interpolant
RootLinearInterpolant <- function (x, y, y0 = 0) {
if (is.unsorted(x)) {
ind <- order(x)
x <- x[ind]; y <- y[ind]
}
z <- y - y0
## which piecewise linear segment crosses zero?
k <- which(z[-1] * z[-length(z)] < 0)
## analytically root finding
xk <- x[k] - z[k] * (x[k + 1] - x[k]) / (z[k + 1] - z[k])
xk
}
A more complicated example and test.
set.seed(0)
x <- sort(runif(10, 0, 10))
y <- rnorm(10, 3, 1)
y0 <- 2.5
xk <- RootLinearInterpolant(x, y, y0)
#[1] 3.375952 8.515571 9.057991
plot(x, y, "l"); abline(h = y0, lty = 2)
points(xk, rep.int(y0, length(xk)), pch = 19)

Numerical root finding for non-linear interpolation (not necessarily stable)
## suppose that f is an interpolation function of (x, y)
## this function finds all x, such that f(x) = y0
## with default value y0 = 0, it finds all roots of the interpolant
RootNonlinearInterpolant <- function (x, y, f, y0 = 0) {
if (is.unsorted(x)) {
ind <- order(x)
x <- x[ind]; y <- y[ind]
}
z <- y - y0
k <- which(z[-1] * z[-length(z)] < 0)
nk <- length(k)
xk <- numeric(nk)
F <- function (x) f(x) - y0
for (i in 1:nk) xk[i] <- uniroot(F, c(x[k[i]], x[k[i] + 1]))$root
xk
}
Try a natural cubic spline interpolation.
## cubic spline interpolation
f <- splinefun(x, y)
xk <- RootNonlinearInterpolant(x, y, f, y0)
#[1] 3.036643 8.953352 9.074306
curve(f, from = min(x), to = max(x))
abline(v = x, lty = 3) ## signal pieces
abline(h = y0)
points(xk, rep.int(y0, length(xk)), pch = 20)

We see that that RootNonlinearInterpolant
misses two crossover points on the 3rd piece.
RootNonlinearInterpolant
relies on uniroot
so the search is more restricted. Only if the sign of y - y0
changes on adjacent knots a uniroot
is called. Clearly this does not hold on the 3rd piece. (Learn more about uniroot
at Uniroot solution in R.)
Also note that uniroot
only returns a single root. So the most stable situation is when the interpolant is monotone on the piece so a unique root exists. If there are actually multiple roots, uniroot
would only find one of them.