plot(XL,YL) hold off I.2.6. The linear equations for cubic splines: version 2 This version follows Numerical Recipes in C, by Press, et. al. Given points (x1 , y1 ), . . . , (xn , yn ) with x1 < x2 < · · · < xn we wish to find a collection of cubic polynomials p1 (x), p2 (x), . . . , pn−1 (x) such that 1. pi (xi ) = yi and pi (xi+1 ) = yi+1 for i = 1, . . . , n − 1 (Each pi has the correct values at the left and right endpoints.) 2. p�i (xi+1 ) = p�i+1 (xi+1 ) for i = 1, . . . , n − 2 (First derivatives are continuous.) 3. p��i (xi+1 ) = p��i+1 (xi+1 ) for i = 1, . . . , n − 2 (Second derivatives are continuous.) 4. p��1 (x1 ) = p��n−1 (xn ) = 0 (Endpoint condition holds.) There are a total of 2(n − 1) + 2(n − 2) + 2 = 4n − 4 equations. Each polynomial pi , being of the form ai x3 + bi x2 + ci x + di , contains 4 unknown coefficients. Since there are n − 1 polynomials, this gives a total of 4(n − 1) = 4n − 4 unknowns. The equations above form a system 4n − 4 linear equations in 4n − 4 unknown coefficients. These have a unique solution which can be found and plotted using MATLAB/Octave. However, it turns out that we only need to solve a much smaller system of n equations in n unknowns. Moreover, this system is tridiagonal (i.e., the coefficient matrix for the system only has non-zero entries on the diagonal and the first sub- and superdiagonals.) Such systems can be solved efficiently. The key to reducing the size of the system is replacing the parameters ai , bi , ci , di with more natural parameters. Instead of using these coefficients, we can specify a cubic polynomial on the interval [xi , xi+1 ] by fixing its values and the values of its second derivatives at the endpoints. Explicitly, let A(x) = xi+1 − x xi+1 − xi B(x) = 1 − A(x) = x − xi xi+1 − xi 1 C(x) = (A(x)3 − A(x))(xi+1 − xi )2 6 1 D(x) = (B(x)3 − B(x))(xi+1 − xi )2 6 41 and set pi (x) = A(x)yi + B(x)yi+1 + C(x)zi + D(x)zi+1 for some unknown numbers z1 , . . . , zn . Notice that [A(xi ), B(xi ), C(xi ), D(xi )] = [1, 0, 0, 0] [A(xi+1 ), B(xi+1 ), C(xi+1 ), D(xi+1 )] = [0, 1, 0, 0] [A�� (xi ), B �� (xi ), C �� (xi ), D�� (xi )] = [0, 0, 1, 0] [A�� (xi+1 ), B �� (xi+1 ), C �� (xi+1 ), D�� (xi+1 )] = [0, 0, 0, 1]. It follows that pi (xi ) = yi pi (xi+1 ) = yi+1 p��i (xi ) = zi p��i (xi+1 ) = zi+1 Thus we see that with this definition of pi , the equations 1. are automatically satisfied, and the numbers zi are the second derivatives of the pi ’s at the endpoints. Although these are not yet known, writing the pi ’s in the way we have done forces the continuity equations 3. to hold as well. We are therefore left with the equations 2. and 4., a total of n equations in the n unknowns z1 , . . . , zn . Equations 4. simply read z1 = zn = 0. When we substitute our expression for pi and pi+1 into Equations 2., these take the form � � � � � � xi+1 − xi yi+2 − yi+1 yi+1 − yi xi+2 − xi xi+2 − xi+1 zi + zi+1 + zi+2 = − 6 3 6 xi+2 − xi+1 xi+1 − xi for i = 1, . . . , n − 2. So the remaining equations have the form Sz = b with z = [z1 , . . . , zn ]T , 1 x2 −x1 6 0 S = .. . 42 0 0 x3 −x1 3 x3 −x1 6 x3 −x2 6 x4 −x2 3 .. . .. . 0 0 x4 −x3 6 .. . ··· ··· ··· .. . ··· ··· xn−1 −xn−2 6 0 xn −xn−2 3 0 xn −xn−1 6 1 and 0 − .. . y3 −y2 x3 −x2 b= yn −yn−1 − xn −xn−1 0 y2 −y1 x2 −x1 yn−1 −yn−2 xn−1 −xn−2 Solving these equation for z and using the resulting values in the expressions for pi (x), i = 1, . . . , n− 1 completes the computation of the splines. We now examine how we could implement this in MATLAB/Octave. We begin by computing the matrix S. To do this we can use the diag command. If a is a vector, then diag(a) defines a diagonal matrix with a on the diagonal. For example > a=[1,2,3] a = 1 2 3 > diag(a) ans = Diagonal Matrix 1 0 0 0 2 0 0 0 3 Similarly, diag(a,1) (resp. diag(a,-1)) puts a on the superdiagonal (resp. subdiagonal). Thus > diag(a,1) ans = 0 0 0 0 1 0 0 0 0 2 0 0 0 0 3 0 To define S, we start with the vector X = [x1 , . . . , xn ] and assemble the diagonal and sub- and superdiagonals by taking suitable subvectors and concatenating them. The diagonal of S is given by [1, (x3 − x1 )/3, (x4 − x2 )/3, . . . , (xn − xn−2 )/3, 1]. 43 In MATLAB/Octave we can define this vector as [1,(X(3:n)-X(1:n-2))/3,1]. Similarly the superdiagonal is given by [0,(X(3:n)-X(2:n-1))/6] and the subdiagonal by [(X(2:n-1)-X(1:n-2))/6,0]. Here are the commands, which should be stored in a file called splinemat2.m. The first and last lines make splinemat2 a function. If the file splinemat2.m is stored in the working directory for MATLAB/Octave and the vector X has been defined, then typing S=splinemat2(X) will define S using the values in X. function S=splinemat2(X) n=length(X); SD = [1,(X(3:n)-X(1:n-2))/3,1]; SU = [0,(X(3:n)-X(2:n-1))/6]; SL = [(X(2:n-1)-X(1:n-2))/6,0]; S=diag(SD)+diag(SU,1)+diag(SL,-1); end The following function takes as input the lower and upper endpoints of the interval (xl and xu), the values of the cubic polynomial at the endpoints (yl and yu) and the values of the second derivative at the endpoints (zl and zu) and plots the corresponding cubic polynomial. The code contains expressions that appear to add a number to a vector, which is an undefined operation. In this situation MATLAB/Octave replaces the number by a vector where every component is equal to the number. So, for example 1+[1,2,3] is evaluated as [1,1,1]+[1,2,3]. function plotcubic2(xl,xu,yl,yu,zl,zu) % % plots the cubic polynomial in the interval [xl,xu] % whose values (resp. 2nd derivatives) at the endpoints % are yl,yu (resp. zl,zu) % n=100; X=linspace(xl,xu,100); A=(xu-X)/(xu-xl); B=1-A; C=A.*(A.^2-1)*(xu-xl)^2/6; D=B.*(B.^2-1)*(xu-xl)^2/6; P=A*yl + B*yu + C*zl + D*zu; 44 plot(X,P) end; Finally, the following function takes as input the values X = [x1 , . . . , xn ] and Y = [y1 , . . . , yn ] to be interpolated, solves the equation Sz = b to find the values Z = [z1 , . . . , zn ] of the second derivatives at the endpoints, and then uses plotcubic2 to plot the resulting polynomials in each interval. function plotspline2(X,Y) % % For inputs X=[x1, ... ,xn] and Y=[y1, ... ,yn] this plots the cubic % spline through the points (x1,y1) ... (xn,yn) % S=splinemat2(X); n=length(X) b=[0,(Y(3:n)-Y(2:n-1))./(X(3:n)-X(2:n-1)) - (Y(2:n-1)-Y(1:n-2))./(X(2:n-1)-X(1:n-2)),0]; Z=S\b’; for k=[1:n-1] plotcubic2(X(k),X(k+1),Y(k),Y(k+1),Z(k),Z(k+1)); hold on end hold off end I.2.7. Summary of MATLAB/Octave commands used in this section How to access elements of a vector a(i) returns the i-th element of the vector a How to create a vector with linearly spaced elements linspace(x1,x2,n) generates n points between the values x1 and x2. 45