Lagrange interpolation method

JAN picture JAN · Jun 14, 2012 · Viewed 23.9k times · Source

I use convolution and for loops (too much for loops) for calculating the interpolation using Lagrange's method , here's the main code :

function[p] = lagrange_interpolation(X,Y)
L = zeros(n);
p = zeros(1,n);


% computing L matrice, so that each row i holds the polynom L_i
% Now we compute li(x) for i=0....n  ,and we build the polynomial 

for k=1:n
    multiplier = 1;
    outputConv = ones(1,1);
    for index = 1:n
        if(index ~= k && X(index) ~= X(k))
            outputConv = conv(outputConv,[1,-X(index)]);
            multiplier = multiplier * ((X(k) - X(index))^-1);
        end
    end
    polynimialSize = length(outputConv);
    for index = 1:polynimialSize
        L(k,n - index + 1) = outputConv(polynimialSize - index + 1);
    end
    L(k,:) = multiplier .* L(k,:);
end

% continues 


end

Those are too much for loops for computing the l_i(x) (this is done before the last calculation of P_n(x) = Sigma of y_i * l_i(x)) .

Any suggestions into making it more matlab formal ?

Thanks

Answer

alexey picture alexey · Jul 19, 2012

Yeah, several suggestions (implemented in version 1 below): if loop can be combined with for above it (just make index skip k via something like jr(jr~=j) below); polynomialSize is always equal length(outputConv) which is always equal n (because you have n datapoints, (n-1)th polynomial with n coefficients), so the last for loop and next line can be also replaced with simple L(k,:) = multiplier * outputConv;

So I replicated the example on http://en.wikipedia.org/wiki/Lagrange_polynomial (and adopted their j-m notation, but for me j goes 1:n and m is 1:n and m~=j), hence my initialization looks like

clear; clc;
X=[-9 -4 -1 7]; %example taken from http://en.wikipedia.org/wiki/Lagrange_polynomial
Y=[ 5  2 -2 9];
n=length(X); %Lagrange basis polinomials are (n-1)th order, have n coefficients
lj = zeros(1,n); %storage for numerator of Lagrange basis polyns - each w/ n coeff
Lj = zeros(n); %matrix of Lagrange basis polyns coeffs (lj(x))
L  = zeros(1,n); %the Lagrange polynomial coefficients (L(x))

then v 1.0 looks like

jr=1:n; %j-range: 1<=j<=n
for j=jr %my j is your k
    multiplier = 1;
    outputConv = 1; %numerator of lj(x)
    mr=jr(jr~=j); %m-range: 1<=m<=n, m~=j
    for m = mr %my m is your index
        outputConv = conv(outputConv,[1 -X(m)]);
        multiplier = multiplier * ((X(j) - X(m))^-1);
    end
    Lj(j,:) = multiplier * outputConv; %jth Lagrange basis polinomial lj(x)
end
L = Y*Lj; %coefficients of Lagrange polinomial L(x)

which can be further simplified if you realize that numerator of l_j(x) is just a polynomial with specific roots - for that there is a nice command in matlab - poly. Similarly the denominator is just that polyn evaluated at X(j) - for that there is polyval. Hence, v 1.9:

jr=1:n; %j-range: 1<=j<=n
for j=jr
    mr=jr(jr~=j); %m-range: 1<=m<=n, m~=j
    lj=poly(X(mr)); %numerator of lj(x)
    mult=1/polyval(lj,X(j)); %denominator of lj(x)
    Lj(j,:) = mult * lj; %jth Lagrange basis polinomial lj(x)
end
L = Y*Lj; %coefficients of Lagrange polinomial L(x)

Why version 1.9 and not 2.0? well, there is probably a way to get rid of this last for loop, and write it all in 1 line, but I can't think of it right now - it's a todo for v 2.0 :)

And, for dessert, if you want to get the same picture as wikipedia:

figure(1);clf
x=-10:.1:10;
hold on
plot(x,polyval(Y(1)*Lj(1,:),x),'r','linewidth',2)
plot(x,polyval(Y(2)*Lj(2,:),x),'b','linewidth',2)
plot(x,polyval(Y(3)*Lj(3,:),x),'g','linewidth',2)
plot(x,polyval(Y(4)*Lj(4,:),x),'y','linewidth',2)
plot(x,polyval(L,x),'k','linewidth',2)
plot(X,Y,'ro','linewidth',2,'markersize',10)
hold off
xlim([-10 10])
ylim([-10 10])
set(gca,'XTick',-10:10)
set(gca,'YTick',-10:10)
grid on

produces

scaled basis functions and their sum

enjoy and feel free to reuse/improve