Polynomial interpolation: Newton interpolation

73. Polynomial interpolation: Newton interpolation#

Anne Kværnø (modified by André Massing)

Date: Jan 18, 2021

If you want to have a nicer theme for your jupyter notebook, download the cascade stylesheet file tma4125.css and execute the next cell:

import matplotlib.pyplot as plt
import numpy as np
from IPython.core.display import HTML
from numpy import pi
from numpy.linalg import norm, solve  # Solve linear systems and compute norms


def css_styling():
    try:
        with open("tma4125.css") as f:
            styles = f.read()
            return HTML(styles)
    except FileNotFoundError:
        pass  # Do nothing


# Comment out next line and execute this cell to restore the default notebook style
css_styling()

And of course we want to import the required modules.

%matplotlib inline


newparams = {
    "figure.figsize": (6.0, 6.0),
    "axes.grid": True,
    "lines.markersize": 8,
    "lines.linewidth": 2,
    "font.size": 14,
}
plt.rcParams.update(newparams)

73.1. Newton interpolation#

This is an alternative approach to find the interpolation polynomial. Let x0,x1,,xn be n+1 distinct real numbers. Instead of using the Lagrange polynomials to write the interpolation polynomial in Lagrange form, we will now employ the Newton polynomials ωi, i=0,,n. The Newton polynomials are defined by as follows:

ω0(x)=1,ω1(x)=(xx0),ω2(x)=(xx0)(xx1),ωn(x)=(xx0)(xx1)(xxn1),

or in more compact notation

(1)ωi(x)=k=0i1(xxk).

The so-called Newton form of a polynomial of degree n is an expansion of the form

p(x)=i=0nciωi(x)

or more explicitly

p(x)=cn(xx0)(xx1)(xxn1)+cn1(xx0)(xx1)(xxn2)++c1(xx0)+c0.

In the light of this form of writing a polynomial, the polynomial interpolation problem leads to the following observations. Let us start with a single node x0, then f(x0)=p(x0)=c0.

Going one step further and consider two nodes x0,x1. Then we see that f(x0)=p(x0)=c0 and f(x1)=p(x1)=c0+c1(x1x0). The latter implies that the coefficient

c1=f(x1)f(x0)x1x0.

Given three nodes x0,x1,x2 yields the coefficients c0,c1 as defined above, and from

f(x2)=p(x2)=c0+c1(x2x0)+c2(x2x0)(x2x1)

we deduce the coefficient

c2=f(x2)f(x0)f(x1)f(x0)x1x0(x2x0)(x2x0)(x2x1).

Playing with this quotient gives the much more structured expression

c2=f(x2)f(x1)x2x1f(x1)f(x0)x1x0(x2x0).

This procedure can be continued and yields a so-called triangular systems that permits to define the remaining coefficients c3,,cn. One sees quickly that the coefficient ck only depends on the interpolation points (x0,y0),,(xk,yk), where yi:=f(xi), i=0,,n.

We introduce the folllwing so-called finite difference notation for a function f. The 0th order finite difference is defined to be f[x0]:=f(x0). The 1st order finite difference is

f[x0,x1]:=f(x1)f(x0)x1x0.

The second order finite difference is defined by

f[x0,x1,x2]:=f[x1,x2]f[x0,x1]x2x0.

In general, the nth order finite difference of the function f, also called the nth Newton divided difference, is defined recursively by

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

Newton’s method to solve the polynomial interpolation problem can be summarized as follows. Given n+1 interpolation points (x0,y0),,(xn,yn), yi:=f(xi). If the order n interpolation polynomial is expressed in Newton’s form

pn(x)=cn(xx0)(xx1)(xxn1)+cn1(xx0)(xx1)(xxn2)++c1(xx0)+c0,

then the coefficients

ck=f[x0,,xk]

for k=0,,n.

In fact, a recursion is in place

pn(x)=pn1(x)+f[x0,,xn](xx0)(xx1)(xxn1)

It is common to write the finite differences in a table, which for n=3 will look like:

x0f[x0]f[x0,x1]x1f[x1]f[x0,x1,x2]f[x1,x2]f[x0,x1,x2,x3]x2f[x2]f[x1,x2,x3]f[x2,x3]x3f[x3]

Example 1 again: Given the points in Example 1. The corresponding table of divided differences becomes:

013/42/31/23/43/210

and the interpolation polynomial becomes

p2(x)=134(x0)34(x0)(x23)=114x34x2.

73.2. Implementation#

The method above is implemented as two functions:

  • divdiff(xdata, ydata): Create the table of divided differences

  • newtonInterpolation(F, xdata, x): Evaluate the interpolation polynomial.

Here, xdata and ydata are arrays with the interpolation points, and x is an array of values in which the polynomial is evaluated.

def divdiff(xdata, ydata):
    # Create the table of divided differences based
    # on the data in the arrays x_data and y_data.
    n = len(xdata)
    F = np.zeros((n, n))
    F[:, 0] = ydata  # Array for the divided differences
    for j in range(n):
        for i in range(n - j - 1):
            F[i, j + 1] = (F[i + 1, j] - F[i, j]) / (xdata[i + j + 1] - xdata[i])
    return F  # Return all of F for inspection.
    # Only the first row is necessary for the
    # polynomial.


def newton_interpolation(F, xdata, x):
    # The Newton interpolation polynomial evaluated in x.
    n, m = np.shape(F)
    xpoly = np.ones(len(x))  # (x-x[0])(x-x[1])...
    newton_poly = F[0, 0] * np.ones(len(x))  # The Newton polynomial
    for j in range(n - 1):
        xpoly = xpoly * (x - xdata[j])
        newton_poly = newton_poly + F[0, j + 1] * xpoly
    return newton_poly

Run the code on the example above:

# Example: Use of divided differences and the Newton interpolation
# formula.
xdata = [0, 2 / 3, 1]
ydata = [1, 1 / 2, 0]
F = divdiff(xdata, ydata)  # The table of divided differences
print("The table of divided differences:\n", F)

x = np.linspace(0, 1, 101)  # The x-values in which the polynomial is evaluated
p = newton_interpolation(F, xdata, x)
plt.plot(x, p)  # Plot the polynomial
plt.plot(xdata, ydata, "o")  # Plot the interpolation points
plt.title("The interpolation polynomial p(x)")
plt.grid(True)
plt.xlabel("x");
The table of divided differences:
 [[ 1.   -0.75 -0.75]
 [ 0.5  -1.5   0.  ]
 [ 0.    0.    0.  ]]
../_images/1f3c7ee1fd9193a70395863a233a482bcd0afced6443749c2b076696cfb964a4.png