lacunary - Mathnotes

Interpolation and Polynomial Approximation

The set of algebraic polynomials, which are functions of the form

Pn(x)=anxn+an1xn1++a1x+a0,

where n is a nonnegative integer and a0,,an are real constants, are extremely useful for approximating functions.

Weierstrass Approximation Theorem: Suppose f is defined and continuous on [a,b]. For each ϵ>0, there exists a polynomial P(x), with the property that

|f(x)P(x)|<ϵ,x[a,b].

In other words, for any continuous function, there is a polynomial that approximates the function as closely as desired.

Morever, it's trivial to differentiate and integrate polynomials, making them very amenable to calculus based analysis.

Taylor polynomials are one type of approximating polynomial, but because they concentrate all of their information near a point, they generally only approximate the function well near the point. Here, we'll investigate other types of polynomials that are more useful for approximating functions along an entire continuous interval by incorporating information from multiple points in the interval.

Lagrange Interpolating Polynomials

If we have two points, (x0,y0) and (x1,y1), we can make a linear polynomial that passes through both points, and use it to approximate a function f(x) for which f(x0)=y0 and f(x1)=y1. We call this an interpolating polynomial because it agrees with the values of f at the given points. We can use this polynomial for approximating f within the interval [x0,x1] and we call this process polynomial interpolation.

If we define the functions

L0(x)=xx1x0x1,L1(x)=xx0x1x0,

then linear Lagrange interpolating polynomial through (x0,y0) and (x1,y1) is

P(x)=L0(x)f(x0)+L1(x)f(x1)=xx1x0x1f(x0)+xx0x1x0f(x1).

Note that

L0(x0)=1,L0(x1)=0,L1(x0)=0,L1(x1)=1,

which implies that

P(x0)=1f(x0)+0f(x1)=f(x0)=y0,

and

P(x0)=0f(x0)+1f(x1)=f(x1)=y1.

Thus, P is the unique polynomial of degree at most one that passes through both (x0,y0) and (x1,y1).

The functions L0(x) and L1(x) are called basis functions and serve to localize the influence of the values at the sample points. L0(x) is 1 when at x0 and 0 when at x1 (and the opposite is true for L1(x),) ensuring that only f(x0) contributes to the function's value at x0 and only f(x1) contributes to the function's value at x1, so that the polynomial agrees with f(x) at those points.

The numerator of L0(x) will be x0x1 when x=x0, and since we want its value to be 1 there, we must make its denominator x0x1.

We can generalize this concept to work for more than two points. To approximate a function given n+1 sample points, we can construct a polynomial that passes through

(x0,f(x0)),(x1,f(x1)),,(xn,f(xn)).

To do so, for each k=0..n we construct a function Ln,k(x) such that Ln,k(xi)=0 when ik and Ln,kxk=1. To make Ln,k(xi)=0 for ik, we need the numerator to contain

(xx0)(xx1)(xxk1)(xxk+1)(xxn).

To normalize the function so that Ln,k(xk)=1, the denominator must contian the same term but evaluated at xk, so we have

Ln,k(x)=(xx0)(xx1)(xxk1)(xxk+1)(xxn)(xkx0)(xkx1)(xkxk1)(xkxk+1)(xkxn).

Now that we've described how to construct the basis functions, we can define the nth Lagrange interpolating polynomial with the following theorem.

Theorem: If x0,x1,,xn are n+1 distinct numbers and f is a function whose values are given at these numbers, then a unique polynomial P(x) of degree at most n exists with

f(xk)=P(xk),k=0,1,,n.

This polynomial is given by

P(x)=f(x0)Ln,0(x)++f(xn)Ln,n(x)=k=0nf(xk)Ln,k(x),

where, for each k=0,1,,n,

Ln,k(x)=(xx0)(xx1)(xxk1)(xxk+1)(xxn)(xkx0)(xkx1)(xkxk1)(xkxk+1)(xkxn)=i=0,iknxxixkxi.

Sometimes we will write just Lk(x) instead of Ln,k(x) when the value of n is clear.

Divided Differences

If Pn(x) is the nth interpolating polynomial that agrees with f at n+1 points, it is unique, but it be written in multiple forms. An alternative form that uses divided differences of f with respect to samples at x0,x1,,xn are used to express Pn(x) in the form

Pn(x)=a0+a1(xx0)+a2(xx0)(xx1)++an(xx0)(xxn1),

for appropriate constants a0,a1,,an.

To get a sense for how we find the constants, note that when x=x0, we want Pn(x)=f(x0), and that since all terms in Pn(x), other than a0, have xx0 in them and will thus be 0 at x0, a0 must be f(x0).

Similarly, at x=x1, all terms other than the first two will be 0, so we have

Pn(x1)=f(x1)=a0+a1(x1x0).

Substituting a0=f(x0) and then solving for a1 gives a1=f(x1)f(x0)x1x0.

This process can be repeated to find more constants, but there is a simpler way.

Now for some new notation. We say that the zeroth divided difference of f with respect to xi, denoted as f[xi], is just the value of f at xi:

f[xi]=f(xi).

Remaining divided differences are defined recursively; the first divided difference of f with respect to xi and xi+1 is denoted f[xi,xi+1] and defined as

f[xi,xi+1]=f[xi+1]f[xi]xi+1xi.

The second divided difference is then

f[xi,xi+1,xi+2]=f[xi+1,xi+2]f[xi,xi+1]xi+2xi.

In general, the kth divided difference is

f[xi,xi+1,xi+2,,xi+k]=f[xi+1,xi+2,,xi+k]f[xi,xi+1,xi+k1]xi+kxi,

and finally we get the nth divided difference

f[x0,x1,,xn]=f[x1,x2,,xn]f[x0,x1,,xn1]xnx0.

This means that a0=f[x0], a1=f[x0,x1], and in general

ak=f[x0,x1,,xk],

for each k=0,1,,n. Now, we can rewrite Pn(x) as Newton's Divided Difference:

Pn(x)=f[x0]+k=1nf[x0,x1,,xk](xx0)(xxk1).

One important fact is that the value of f[x0,x1,,xk] is independent of the order of the numbers x0,x1,,xk. That means we can add a sample point in the middle of others and calculate the additional term in order to improve the accuracy of the interpolation.

Here's psuedocode:

float[] newtonsDividedDifference(float xs, float ys) {
    assert(len(xs) = len(ys));

    int n = len(xs) - 1;

    float F[n+1][n+1];
    float as[n+1];

    for (int i = 0; i <= n; i++) {
        F[i][0] = ys[i];
    }

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            //F[i][j] = f[x_{i - j}, ..., x_i]
            F[i][j] = (F[i][j-1] - F[i - 1][j - 1])/(xs[i] - xs[i - j]);
            if (i == j) {
                as[i][i] = F[i][i];
            }
        }
    }

    return as;
}

Chebyshev Polynomials

We can use the orthogonal family of Chebyshev Polynomials to pick optimal nodes for minimizing error for approximation of a function with Lagrange Interpolating Polynomials.

Doing so requires either that the function we're approximating is on [1,1] or doing some more advanced transformations I won't cover here, so just assume that's the domain.

Then, to make Pn(x), we pick the nodes as the roots of the monic Chebyshev Polynomial T~n+1. Those nodes are then given by

xk=x¯k+1=cos(2k+12(n+1)π).

We then proceed as usual using one of the above methods.

Cubic Splines

Using a single high-degree polynomial to approximate a function on an interval has some issues. Particualarly, high-degree polynomials can oscillate erratically.

Another approach is to use a lower degree polynomial to approximate the subinterval between each pair of successive points in the general interval; this is called piecewise-polynomial approximation.

The simplest form of this is piecewise-linear approximation, where we join each pair of successive sample points with a series of straight line segments. This can produce reasonable approximations but has a major disadvantage in there is no differentiability at the endpoints of each subinterval (except in the special case that all points fall on the same line.) This means the approximating function is not continuously differentiable - it's not smooth - which typically doesn't match the behavior of the phsyical system being approximated.

A better - and more common - approach is cubic spline interpolation. A cubic polynomial has 4 constants, which provides sufficient flexibility so that the approximating function is twice differentiable on the entire interval.

Given a function f defined on [a,b] and a set of nodes a=x0<x1<<xn=b, a cubic spline interpolant S for f is a function that satisfies the following conditions:

  • S(x) is a cubic polynomial, denoted as Sj(x), on the subinterval [xj,xj+1] for each j=0,1,,n1. (S is a piecewise function with each piece being composed of a cubic polynomial that covers the subinterval between two successive points, overlapping at the endpoints)
  • Sj(xj)=f(xj) and Sj(xj+1)=f(xj+1) for each j=0,1,,n1. (the cubic polynomial for each subinterval agrees with the function being approximated at the endpoints of each subinterval.)
  • Sj+1(xj+1)=Sj(xj+1) for each j=0,1,,n2. (the cubic polynomials for two adjacent subintervals have the same value at the point they overlap.)
  • Next,

Sj+1(xj+1)=Sj(xj+1)

for each j=0,1,,n2. (the first derivatives of the cubic polynomials for two adjacent subintervals have the same value at the point they overlap.)

  • Next,

Sj+1(xj+1)=Sj(xj+1)

for each j=0,1,,n2. (the second derivatives of the cubic polynomials for two adjacent subintervals have the same value at the point they overlap.)

  • One of the following sets of boundary conditions is satisfied:
    • S(x0)=S(xn)=0 (natural or free boundary.)
    • S(x0)=f(x0) and S(xn)=f(xn) (clamped boundary.)

A natural spline approximates the shape a long flexible rod would take when forced to go through the sample points. Clamped boundary conditions generally lead to more accurate approximations, but require information about the derivatives of the function at its endpoints.

The procedure for finding a cubic spline interpolation over n subintervals is to setup a system of equations using the contraints given above and to solve for the unknown constants. There will be n cubic polynomials, each with 4 constants, so 4n equations will be needed to find the 4n constants.

Each cubic polynomial is of the form