// Lagrange and Hermite interpolation in Asymptote // Author: Olivier Guibé import interpolate; import graph; // Test 1: The Runge effect in the Lagrange interpolation of 1/(x^2+1). unitsize(2cm); real f(real x) {return(1/(x^2+1));} real df(real x) {return(-2*x/(x^2+1)^2);} real a=-5, b=5; int n=15; real[] x,y,dy; x=a+(b-a)*sequence(n+1)/n; y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=diffdiv(x,y); fhorner p=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}L_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\frac{1}{x^2+1}$"); xlimits(-5,5); ylimits(-1,1,Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge1"); erase(); // Test 2: The Runge effect in the Hermite interpolation of 1/(x^2+1). real f(real x) {return(1/(x^2+1));} real df(real x) {return(-2*x/(x^2+1)^2);} real a=-5, b=5; int n=16; real[] x,y,dy; x=a+(b-a)*sequence(n+1)/n; y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=hdiffdiv(x,y,dy); fhorner ph=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}H_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\frac{1}{x^2+1}$"); unitsize(2cm); xlimits(-5,5); ylimits(-1,5,Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge2"); erase(); // Test 3: The Runge effect does not occur for all functions: // Lagrange interpolation of a function whose successive derivatives // are bounded by a constant M (here M=1) is shown here to converge. real f(real x) {return(sin(x));} real df(real x) {return(cos(x));} real a=-5, b=5; int n=16; real[] x,y,dy; x=a+(b-a)*sequence(n+1)/n; y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=diffdiv(x,y); fhorner p=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}L_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\cos(x)$"); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge3"); erase(); // Test 4: However, one notes here that numerical artifacts may arise // from limit precision (typically 1e-16). real f(real x) {return(sin(x));} real df(real x) {return(cos(x));} real a=-5, b=5; int n=72; real[] x,y,dy; x=a+(b-a)*sequence(n+1)/n; y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=diffdiv(x,y); fhorner p=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}L_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\cos(x)$"); ylimits(-1,5,Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge4"); erase(); // Test 5: The situation is much better using Tchebychev points. unitsize(2cm); real f(real x) {return(1/(x^2+1));} real df(real x) {return(-2*x/(x^2+1)^2);} real a=-5, b=5; int n=16; real[] x,y,dy; fhorner p,ph,ph1; for(int i=0; i <= n; ++i) x[i]=(a+b)/2+(b-a)/2*cos((2*i+1)/(2*n+2)*pi); y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=diffdiv(x,y); fhorner p=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}T_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\frac{1}{x^2+1}$"); xlimits(-5,5); ylimits(-1,2,Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge5"); erase(); // Test 6: Adding a few more Tchebychev points yields a very good result. unitsize(2cm); real f(real x) {return(1/(x^2+1));} real df(real x) {return(-2*x/(x^2+1)^2);} real a=-5, b=5; int n=26; real[] x,y,dy; for(int i=0; i <= n; ++i) x[i]=(a+b)/2+(b-a)/2*cos((2*i+1)/(2*n+2)*pi); y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=diffdiv(x,y); fhorner p=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}T_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\frac{1}{x^2+1}$"); xlimits(-5,5); ylimits(-1,2,Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge6"); erase(); // Test 7: Another Tchebychev example. unitsize(2cm); real f(real x) {return(sqrt(abs(x-1)));} real a=-2, b=2; int n=30; real[] x,y,dy; for(int i=0; i <= n; ++i) x[i]=(a+b)/2+(b-a)/2*cos((2*i+1)/(2*n+2)*pi); y=map(f,x); dy=map(df,x); for(int i=0; i <= n; ++i) dot((x[i],y[i]),5bp+blue); horner h=diffdiv(x,y); fhorner p=fhorner(h); draw(graph(p,a,b,n=500),"$x\longmapsto{}T_{"+string(n)+"}$"); draw(graph(f,a,b),red,"$x\longmapsto{}\sqrt{|x-1|}$"); xlimits(-2,2); ylimits(-0.5,2,Crop); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); attach(legend(),point(10S),30S); shipout("runge7");