We import the modules matplotlib.pyplot
y numpy
and the numpy
functions for polynomials.
import numpy as np
import matplotlib.pyplot as plt
import numpy.polynomial.polynomial as pol
Given some points $(x_0,y_0),(x_1,y_1),\ldots,(x_n,y_n)$ we want to find a polynomial function that passes through all of them.
Consider the points:
$$C=\{(-1,1),(0,3),(2,4),(3,3),(5,1)\}$$Let us plot them.
We store the points in two numpy arrays
x = np.array([-1., 0, 2, 3, 5])
y = np.array([ 1., 3, 4, 3, 1])
And we plot the points and the Lagrange polynomial
xp = np.linspace(min(x),max(x))
p = pol.polyfit(x,y,len(x)-1)
yp = pol.polyval(xp,p)
plt.figure()
plt.plot(xp,yp,'b-', label = 'interpolant polynomial')
plt.plot( x, y,'ro', label = 'points')
plt.legend()
plt.show()
For each $k=0,1,\ldots,n$, there exists a unique polynomial $\ell_{k}$ of degree $\leq n$ such as $\ell_{k}\left(x_{j}\right)=\delta_{kj}$ (one if $k=j$, zero otherwise):
$$ \ell_{k}\left(z\right)= \frac{(z-x_{0})}{(x_{k}-x_{0})}\cdots \frac{(z-x_{k-1})}{(x_{k}-x_{k-1})} \cdot \frac{(z-x_{k+1})}{(x_{k}-x_{k+1})} \cdots \frac{(z-x_{n})}{(x_{k}-x_{n})} $$For instance, with our 5 nodes, these polynomials are
$$ \ell_{0}\left(z\right)= \Bigg\rvert^{x_0} \frac{(z-x_1)}{(x_0-x_1)} \cdot \frac{(z-x_2)}{(x_0-x_2)} \cdot \frac{(z-x_3)}{(x_0-x_3)} \cdot \frac{(z-x_4)}{(x_0-x_4)} $$$$ \ell_{1}\left(z\right)= \frac{(z-x_0)}{(x_1-x_0)} \Bigg\rvert^{x_1} \frac{(z-x_2)}{(x_1-x_2)} \cdot \frac{(z-x_3)}{(x_1-x_3)} \cdot \frac{(z-x_4)}{(x_1-x_4)} $$$$ \ell_{2}\left(z\right)= \frac{(z-x_0)}{(x_2-x_0)} \cdot \frac{(z-x_1)}{(x_2-x_1)} \Bigg\rvert^{x_2} \frac{(z-x_3)}{(x_2-x_3)} \cdot \frac{(z-x_4)}{(x_2-x_4)} $$$$ \ell_{3}\left(z\right)= \frac{(z-x_0)}{(x_3-x_0)} \cdot \frac{(z-x_1)}{(x_3-x_1)} \cdot \frac{(z-x_2)}{(x_3-x_2)} \Bigg\rvert^{x_3} \frac{(z-x_4)}{(x_3-x_4)} $$$$ \ell_{4}\left(z\right)= \frac{(z-x_0)}{(x_4-x_0)} \cdot \frac{(z-x_1)}{(x_4-x_1)} \cdot \frac{(z-x_2)}{(x_4-x_2)} \cdot \frac{(z-x_3)}{(x_4-x_3)} \Bigg\rvert^{x_4} $$The polynomials $\ell_{0},\ell_{1},\ldots,\ell_{n}$ are the Lagrange fundamental polynomials.
The Lagrange polynomial for the points $x_{0,}x_{1},\ldots,x_{n}$ with values $y_{0},y_{1},\ldots,y_{n}$ is
$$ P_{n}\left(z\right)=y_{0}\ell_{0}\left(z\right)+ y_{1}\ell_{1}\left(z\right)+\cdots+y_{n}\ell_{n}\left(z\right) $$Write a script that computes Lagrange's fundamental polynomials. Create a function: lagrange_fundamental(k,x,z)
with
k
, index of the fundamental polynomial, x
, the $x$ coordinates of the nodes (or points the polynomial passes through) and z
, point (or array of points) where we will evaluate the polynomial. z
.Plot the Lagrange's fundamental polynomials.
Use the nodes:
x = np.array([-1., 0, 2, 3, 5])
Hints:
k = 2
z = 1.3
yz = lagrange_fundamental(k,x,z)
print(yz)
so we know that $\ell_{2}\left(1.3\right)= 1.04484$. The second version would do
k = 2
z = np.array([1.3, 2.1, 3.2])
yz = lagrange_fundamental(k,x,z)
print(yz)
so we know that $\ell_{2}\left([1.3,\, 2.1,\, 3.2]\right)= [ 1.04483889,\, 0.94395,\, -0.2688 ]$
x
vector of the nodes and the corresponding $y$s can be obtained as the rows of the identity matrix:print(np.eye(len(x)))
%run Exercise1.py
Let us remember that the Lagrange polynomial for the points $x_{0,}x_{1},\ldots,x_{n}$ with values $y_{0},y_{1},\ldots,y_{n}$ is
$$ P_{n}\left(z\right)=y_{0}\ell_{0}\left(z\right)+ y_{1}\ell_{1}\left(z\right)+\cdots+y_{n}\ell_{n}\left(z\right) $$Write a script that computes the Lagrange's interpolant polynomial using the Lagrange fundamental polynomials. Use the function lagrange_fundamental(k,x,z)
in the function lagrange_polynomial(x,y,z)
:
x
and y
, coordinates of the nodes (or points the polynomial passes through) and z
, point (or array of points) where we will evaluate the polynomial. z
.Plot the Lagrange's interpolant polynomial.
Use the nodes:
x = np.array([-1., 0, 2, 3, 5])
y = np.array([ 1., 3, 4, 3, 1])
Check that the script also works for the nodes:
x1 = np.array([-1., 0, 2, 3, 5, 6, 7])
y1 = np.array([ 1., 3, 4, 3, 2, 2, 1])
%run Exercise2.py
A drawback of this method is that if we want to add a new node we have to do all the computations again.
The interpolant polynomial can be computed with numpy function polyfit
if we choose as polynomial degree the number of the nodes minus one. The output is the coefficients of the polynomial, from $a_n$ to $a_0$.
x = np.array([-1., 0, 2, 3, 5])
y = np.array([ 1., 3, 4, 3, 1])
p = pol.polyfit(x,y,len(x)-1) # polynomial coefficients
xp = np.linspace(min(x),max(x))
yp = pol.polyval(xp,p) # polynomial value in the points contained in xp
We plot the polynomial and the nodes
plt.figure()
plt.plot(xp, yp, 'b-',x, y, 'ro')
plt.show()
Write a function chebyshev(f,a,b,n)
that interpolates the function f
in the interval [a,b]
using n
nodes:
the number of nodes is n = 11
, the interval is [a,b]=[-1,1]
and the function f
is
Check that it also works with 15 nodes and the function:
$$ f_2(x)=e^{-20x^2} $$Follow the steps:
Build the nodes: the n nodes will be stored in an n element vector x
in both cases. For the equispaced nodes the functionse np.linspace
or np.arange
may be used. The corresponding y
are calculated using f1
and f2
.
Build the interpolant polynomials: To interpolate the functions, use pol.polyfit
and pol.polyval
.
Plot the graphs: In both cases, plot the nodes, the function and the interpolant polynomial. Use plt.axis([-1.05, 1.05, -0.3, 2.3])
so all the graphs are plotted in the rectangle $[-1.05, 1.05]\times[ -0.3, 2.3]$. Use more than 50 points for np.linespace
as the interpolant polynomials will oscillate a lot.
%run Exercise3.py
Formula of Newton
The Lagrange interpolant polynomial of degree n for the nodes $(x_{0},y_{0}),(x_{1},,y_{1})\ldots,(x_{n},y_{n})$ is given by
$$ P_{n}\left(z\right)= \left[y_{0}\right]+\left[y_{0},y_{1}\right]\left(z-x_{0}\right)+ \left[y_{0},y_{1},y_{2}\right]\left(z-x_{0}\right)\left(z-x_{1}\right)+\cdots +\left[y_{0},y_{1},\ldots,y_{n}\right]\left(z-x_{0}\right)\left(z-x_{1}\right)\cdots\left(z-x_{n-1}\right) $$Table of divided differences
The coefficients of the latter polynomial are in the first row of the following table:
$$ \begin{array}{cccccc} x_{0} & y_{0} & \left[y_{0},y_{1}\right]=\frac{y_{0}-y_{1}}{x_{0}-x_{1}} & \left[y_{0},y_{1},y_{2}\right]=\frac{\left[y_{0},y_{1}\right]-\left[y_{1},y_{2}\right]}{x_{0}-x_{2}} & \ldots & \left[y_{0},y_{1},\ldots,y_{n}\right]=\frac{\left[y_{0},\ldots,y_{n-1}\right]-\left[y_{1},\ldots,y_{n}\right]}{x_{0}-x_{n}}\\ x_{1} & y_{1} & \left[y_{1},y_{2}\right]=\frac{y_{1}-y_{2}}{x_{1}-x_{2}} & \left[y_{1},y_{2},y_{3}\right]=\frac{\left[y_{1},y_{2}\right]-\left[y_{2},y_{3}\right]}{x_{1}-x_{3}} & \ldots\\ x_{2} & y_{2} & \left[y_{2},y_{3}\right]=\frac{y_{2}-y_{3}}{x_{2}-x_{3}} & \left[y_{2},y_{3},y_{4}\right]=\frac{\left[y_{2},y_{3}\right]-\left[y_{3},y_{4}\right]}{x_{2}-x_{4}} & \ldots\\ \ldots & \ldots & \ldots & \ldots & \ldots\\ x_{n-1} & y_{n-1} & \left[y_{n-1},y_{n}\right]=\frac{y_{n-1}-y_{n}}{x_{n-1}-x_{n}}\\ x_{n} & y_{n} \end{array} $$Write a script that computes the Lagrange's interpolant polynomial using the divided differences. Create two functions: div_dif(x,y)
with
x
and y
. and a function newton_polynomial(z,x,y)
with:
z
, point (or array of points) where we will evaluate the polynomial and the coordinates of the nodes x
and y
.z
.Print the divided difference matrix. Draw the interpolant polynomial.
Use the nodes:
x = np.array([-1., 0, 2, 3, 5])
y = np.array([ 1., 3, 4, 3, 1])
Check that the script also works for the nodes:
x1 = np.array([-1., 0, 2, 3, 5, 6, 7])
y1 = np.array([ 1., 3, 4, 3, 2, 2, 1])
%run Exercise4.py
We can compute piecewise interpolation with scipy
functions
x = np.array([-1., 0, 2, 3, 5])
y = np.array([ 1., 3, 4, 3, 1])
from scipy.interpolate import interp1d, CubicSpline
f1 = interp1d(x, y, kind='nearest')
f2 = interp1d(x, y, kind='linear')
f3 = CubicSpline(x, y, bc_type='natural')
xp = np.linspace(min(x),max(x))
Zero degree
plt.figure()
plt.plot(x, y, 'ro', xp, f1(xp), 'b-')
plt.show()
Degree one or linear
plt.figure()
plt.plot(x, y, 'ro', xp, f2(xp), 'b-')
plt.show()
Degree three, a natural cubic spline
plt.plot(x, y, 'ro', xp, f3(xp), 'b-')
plt.show()
Write a script that, for the function $f(x) = \cos x$ in interval $[0,10]$ with nodes $x=0,1,\ldots,10$ plots the polynomial interpolants
and calculates, for the points
xp = np.linspace(0,10,100)
the absolute error for each case. Use the funtion Ea = np.linalg.norm(yp-f(xp))
.
%run Exercise5.py
As we have $5$ points we can write $5$ equations and we need $5$ unknows that will be the coefficients of the polynomial. Thus:
$$P_4(x)=a_0+a_1x+a_2x^2+a_3x^3+a_4x^4$$that is $a_0,a_1,a_2,a_3,a_4$, that are $5$ unknowns and the polynomial degree is $4$. In general, the polynomial that passes throught the points $(x_0,y_0),(x_1,y_1),\ldots,(x_n,y_n)$ has a degree of $\leq n$.
The equations are:
$$ \begin{array}{lll} P_{4}(x_{0})=y_{0} & \quad & a_{0}+a_{1}x_{0}+a_{2}x_{0}^{2}+a_{3}x_{0}^{3}+a_{4}x_{0}^{4}=y_{0}\\ P_{4}(x_{1})=y_{1} & \quad & a_{0}+a_{1}x_{1}+a_{2}x_{1}^{2}+a_{3}x_{1}^{3}+a_{4}x_{1}^{4}=y_{1}\\ P_{4}(x_{2})=y_{2} & \quad & a_{0}+a_{1}x_{2}+a_{2}x_{2}^{2}+a_{3}x_{2}^{3}+a_{4}x_{2}^{4}=y_{2}\\ P_{4}(x_{3})=y_{3} & \quad & a_{0}+a_{1}x_{3}+a_{2}x_{3}^{2}+a_{3}x_{3}^{3}+a_{4}x_{3}^{4}=y_{3}\\ P_{4}(x_{4})=y_{4} & \quad & a_{0}+a_{1}x_{4}+a_{2}x_{4}^{2}+a_{3}x_{4}^{3}+a_{4}x_{4}^{4}=y_{4} \end{array} $$And the system to solve is:
$$ \left(\begin{array}{ccccc} 1 & x_{0} & x_{0}^{2} & x_{0}^{3} & x_{0}^{4}\\ 1 & x_{1} & x_{1}^{2} & x_{1}^{3} & x_{1}^{4}\\ 1 & x_{2} & x_{2}^{2} & x_{2}^{3} & x_{2}^{4}\\ 1 & x_{3} & x_{3}^{2} & x_{3}^{3} & x_{3}^{4}\\ 1 & x_{4} & x_{4}^{2} & x_{4}^{3} & x_{4}^{4} \end{array}\right)\left(\begin{array}{c} a_{0}\\ a_{1}\\ a_{2}\\ a_{3}\\ a_{4} \end{array}\right)=\left(\begin{array}{c} y_{0}\\ y_{1}\\ y_{2}\\ y_{3}\\ y_{4} \end{array}\right) $$that is, $Vp=y$, where $V$ is the system coefficient matrix, called Vandermonde's matrix, $y$, that contains the independent terms of the system and the system solution, the polynomial coefficients, contained in $p$.
Vandermonde(x)
, whose input argument is the x
vector that contains the $x$ coordinates of the points (nodes), and as output argument, the Vandermonde's matrix V
.polVandermonde(x,y)
, whose input argumets are the coordinates x
and y
of the nodes and whose output argument is p
, that contains the coefficients of the interpolation polynomial, that is, $p = (a_0,a_1,a_2,a_3,a_4)$..V
calling the Vandermonde
function.p = np.linalg.solve(V,y)
.xp = np.linspace(min(x),max(x))
creates a vector with 50 points in the interpolation interval.yp = pol.polyval(xp,p)
to compute the polynomial in the points xp
using the coefficients p
computed in the previous question.Use the nodes:
x = np.array([-1., 0, 2, 3, 5])
y = np.array([ 1., 3, 4, 3, 1])
Check that the script also works for the nodes:
x1 = np.array([-1., 0, 2, 3, 5, 6, 7])
y1 = np.array([ 1., 3, 4, 3, 2, 2, 1])
%run Exercise6.py
We can also show the Vandermonde's matrix and the polynomial coefficients
print('V matrix')
print(V)
print('Polynomial coefficients')
print(p)
There is a Python function that computes Vandermonde's matrix
va = pol.polyvander(x, len(x)-1)
print(va)
Nevertheless, it is not advisable to use Vandermonde's matrix to construct the polynomial interpolant because, the matrix, in general, is ill-conditioned and small errors in the data can lead to large errors in the solution of the system.