femhub-esco2010: Num Methods: Lagrange Polynomial

32 days ago by ondrej

Lagrange Interpolation Polynomial

The Lagrange interpolation polynomial L(x) is a single polynomial that passes through a given set of interpolation points. With n+1 interpolation points, the degree of the polynomial is n. All points are required to have different x-coordinates. The scripts below illustrate the construction of L(x) with interpolation points defined in four different ways. In cases 2 - 4, where a function f(x) is used to define them, also the interpolation error E(x) = f(x) - L(x) is shown.

  1. Given is an arbitrary array of x-coordinates and an arbitrary array of y-coordinates. 
  2. Given is an arbitrary array of x-coordinates and a function f(x) for y-coordinates.  
  3. Given is an array of equally-spaced x-coordinates and a function f(x) for y-coordinates.
  4. Given are Chebyshev points for x-coordinates and a function f(x) for y-coordinates.

The following active input text box contains the main code. You need to click on it to see an "Evaluate" link appear at its bottom. Click on this link to have the code sent to our computer and interpreted. Then you can evaluate/modify/evaluate the examples in the other text boxes in the same way. Have fun and let us know at femhub@googlegroups.com with any problems or questions.

The Code:

# Import symbolics and plotting functions. from pylab import plot, savefig, grid, legend, clf from numpy import arange from sympy import (var, pi, factorial, sin, cos, log, exp, tan, atan, asin, acos, sinh, cosh, tanh, asinh, acosh, lambdify) # Use the symbol 'x' for independent variable. var("x") # Basic function evaluating at point 'x' # the Lagrange polynomial given via a list of # [x, y] pairs. def lagrange(x, list): r = 0 for pi in list: val = 1 for pj in list: if pi != pj: val *= (float(x) - pj[0])/(pi[0]-pj[0]) r += val*pi[1] return r # Case 1: Interpolation points are defined via # arbitrary arrays of x- and y-coordinates. def lagrange_1(a, b, x_list, y_list, n=100): list = zip(x_list, y_list) h = (b-a)/float(n) x_array = arange(a, b+h, h) lagr_poly = [lagrange(xx, list) for xx in x_array] clf() label = "Lagrange polynomial L(x)" plot(x_array, lagr_poly, "b-", label=label) plot(x_list, y_list, "ko") legend() grid(True) savefig("a.png") # Case 2: x-coordinates of interpolation points are # defined via an arbitrary array x_list, y-coordinates # via function values f(x). def lagrange_2(a, b, x_list, f, x, n=100): f = lambdify(x, f, modules=["math"]) y_list = [f(xx) for xx in x_list] list = zip(x_list, y_list) h = (b-a)/float(n) x_array = arange(a, b+h, h) lagr_poly = [lagrange(xx, list) for xx in x_array] f_graph = [f(xx) for xx in x_array] clf() label = "Function f(x)" plot(x_array, f_graph, "g-", label=label) plot(x_list, y_list, "ko") label = "Lagrange polynomial L(x)" plot(x_array, lagr_poly, "b-", label=label) legend() grid(True) savefig("a.png") clf() error_graph = [float(f(xx) - lagrange(xx, list)) for xx in x_array] label = "Error E(x) = f(x) - L(x)" plot(x_array, error_graph, "b-", label=label) legend() grid(True) savefig("b.png") # calculate approximate error maximum (over plotting points) err_abs = [abs(float(f(xx) - lagrange(xx, list))) for xx in x_array] print "Max error:", max(err_abs) # Case 3: interpolation points are equidistributed # in the interval [a,b], y-coordinates are defined # via a function f(x). def lagrange_3(a, b, num_pts, f, x, n=100): f = lambdify(x, f, modules=["math"]) num_elem = num_pts-1 h0 = (b-a)/float(num_elem) x_list = [float(a + i*h0) for i in range(0, num_pts)] # demonstration of inoptimality of equidistant points: # move points out of center and see error decrease #x_list[1] -= 0.1 #x_list[-2] += 0.1 y_list = [f(xx) for xx in x_list] list = zip(x_list, y_list) h = (b-a)/float(n) x_array = arange(a, b+h, h) lagr_poly = [lagrange(xx, list) for xx in x_array] f_graph = [f(xx) for xx in x_array] clf() label = "Function f(x)" plot(x_array, f_graph, "g-", label=label) label = "Lagrange polynomial L(x)" plot(x_array, lagr_poly, "b-", label=label) plot(x_list, y_list, "ko") legend() grid(True) savefig("a.png") clf() error_graph = [f(xx) - lagrange(xx, list) for xx in x_array] label = "Error E(x) = f(x) - L(x)" plot(x_array, error_graph, "b-", label=label) legend() grid(True) savefig("b.png") # calculate approximate error maximum (over plotting points) err_abs = [abs(float(f(xx) - lagrange(xx, list))) for xx in x_array] print "Max error:", max(err_abs) # Case 4: x-coordinates of interpolation points are # the Chebyshev points, y-coordinates are defined # via function f(x). def lagrange_4(a, b, num_pts, f, x, n=100): f = lambdify(x, f, modules=["math"]) num_elem = num_pts - 1 x_list = [float(cos(i*pi/num_elem)*(b-a)/2) for i in range(0, num_pts)] # demonstration of optimality of Chebyshev points: # move any point and see error increase #x_list[2] += 0.2 #x_list[-3] -= 0.2 y_list = [f(xx) for xx in x_list] list = zip(x_list, y_list) h = (b-a)/float(n) x_array = arange(a, b+h, h) lagr_poly = [lagrange(xx, list) for xx in x_array] f_graph = [f(xx) for xx in x_array] clf() label = "Function f(x)" plot(x_array, f_graph, "g-", label=label) label = "Lagrange polynomial L(x)" plot(x_array, lagr_poly, "b-", label=label) plot(x_list, y_list, "ko") legend() grid(True) savefig("a.png") clf() error_graph = [f(xx) - lagrange(xx, list) for xx in x_array] label = "Error E(x) = f(x) - L(x)" plot(x_array, error_graph, "b-", label=label) legend() grid(True) savefig("b.png") # calculate approximate error maximum (over plotting points) err_abs = [abs(float(f(xx) - lagrange(xx, list))) for xx in x_array] print "Max error:", max(err_abs) 
       

Case 1

Input: Interval endpoints a, b, list of x-coordinates of interpolation points, list of corresponding y-coordinates,  plotting subdivision (optional).

lagrange_1(0, 2*pi, [0, pi/2., pi, 3*pi/2.], [0, 1, 0, -1]) 
       

Case 2

Input: Interval endpoints a, b, list of x-coordinates of interpolation points, function f(x) to provide y-coordinates, 'x' stating the independent variable for f(x), plotting subdivision (optional).

lagrange_2(0, 2.*pi, [0, pi/2., pi, 3*pi/2.], sin(x), x, 300) 
       
Max error: 0.18075324088

lagrange_2(-5., 5., [-5, -2, 0, 2, 5], 1/(1+x**2), x, 300) 
       
Max error: 0.793767858794

Case 3

Input: Interval endpoints a, b, number of equidistant points, function f(x) to provide y-coordinates, 'x' stating the independent variable for f(x), plotting subdivision (optional).

lagrange_3(-5, 5, 5, 1/(1+x**2), x, 500) 
       
Max error: 0.438344555245

lagrange_3(-5, 5, 10, 1/(1+x**2), x, 500) 
       
Max error: 0.300281129793

lagrange_3(-5, 5, 15, 1/(1+x**2), x, 500) 
       
Max error: 7.19200795571

lagrange_3(-5, 5, 41, 1/(1+x**2), x, 500) 
       
Max error: 103940.81177

Case 4

Input: Interval endpoints a, b, number of Chebyshev points, function f(x) to provide y-coordinates, 'x' stating the independent variable for f(x), plotting subdivision (optional).

lagrange_4(-5, 5, 5, 1/(1+x**2), x, 1000) 
       
Max error: 0.45997768664

lagrange_4(-5, 5, 10, 1/(1+x**2), x, 1000) 
       
Max error: 0.319095254735

lagrange_4(-5, 5, 15, 1/(1+x**2), x, 1000) 
       
Max error: 0.0535080394302

lagrange_4(-5, 5, 41, 1/(1+x**2), x, 1000) 
       
Max error: 0.000339616379427