In [1]:
using Plots
In [2]:
## The polynomial
yi = [2,3,6]
xi = [1,2,3]
xx = linspace(0,4,100)
Out[2]:
linspace(0.0,4.0,100)
In [3]:
"""fit the coefficients of a polynomial interpolant
c = polyfit(x,y,n) fits a degree n polynomial to the
data poly(x,c)"""
function polyfit(x,y,n)
    m = length(x) # datapoints
    Z = zeros(m,n+1)
    for i=1:m # Should fill this out columnwise.
        xi = 1.
        for j=1:n+1
            Z[i,j] = xi
            xi *= x[i]
        end
    end
    return Z\y
end
""" Evaluate a polynomial vs. Horner's rule """
function polyval(c,x)
    # based on Matlab's Horner's rule 
    m = length(x)
    y = zeros(m)
    
    if length(c) > 0
        y[:] = c[end]
    end
    for i=2:length(c)
        y = x .* y + c[end-i+1]
    end
    return y
end
@show polyfit([1,2,3.],[1,4.,9],2)
@show polyval([0.,0.,1.],[0.5,4.])

## Monomial form from class 
c = polyfit(xi,yi,2)
yyp = polyval(c,xx)
plot(xx,yyp); scatter!(xi,yi)
polyfit([1,2,3.0],[1,4.0,9],2) = [0.0,0.0,1.0]
polyval([0.0,0.0,1.0],[0.5,4.0]) = [0.25,16.0]
[Plots.jl] Initializing backend: pyplot
WARNING: No working GUI backend found for matplotlib.
Out[3]:
In [6]:
""" 
`lagrange_interp`: lagrange_interp(x, xi, yi)
y = lagrange_interp(x,xi,yi) uses the data from xi,yi to build the
Lagrange interpolant and then evaluates that interpolant at the points
x, returning the interpolated values y.
"""     
function lagrange_interp(x, xi, yi)
  y = zeros(size(x))
  for i=1:length(yi)
    elli = ones(size(x))
    for j=1:length(xi)
      if i==j continue; end
      elli = elli.*(x-xi[j])/(xi[i] - xi[j])
    end
    y = y + yi[i]*elli
  end
  return y
end
## Lagrange form
yyl = lagrange_interp(xx,xi,yi);
plot(xx,yyl); scatter!(xi,yi)
Out[6]:
In [5]:
function compute_barycentric_weights(xi)
  ws = zeros(size(xi))
  for i=1:length(xi)
    w = 1.0
    for j=1:length(xi)
      if j==i continue; end
      w = w*1.0/(xi[i] - xi[j])
    end
    ws[i] = w
  end
  return ws
end  
function barycentric_interp_with_weights(x,xi,fi,wi)
  ynumer = zeros(size(x))
  ydenom = zeros(size(x))
  for i=1:length(xi)
    ynumer += yi[i].*wi[i]./(x - xi[i])
    ydenom += wi[i]./(x - xi[i])
  end
  y = ynumer./ydenom
end
""" 
`barycentric_interp`: barycentric_interp(x, xi, yi)
y = barycentric_interp(x,xi,yi) uses the data from xi,yi to build the
Lagrange interpolant in the Barycentric form, and 
then evaluates that interpolant at the points x, 
returning the interpolated values y. 
"""     
function barycentric_interp(x,xi,fi)
  return barycentric_interp_with_weights(x,xi,fi,
    compute_barycentric_weights(xi))
end


## Barycentric form
yyb = barycentric_interp(xx,xi,yi);
plot(xx,yyb); scatter!(xi,yi)
Out[5]: