function hermite_birkhoff_interp

N = 3; % fixed for 3 derivatives
x = linspace(-1,1,250)';
xi = [-1 1]';

[V dV d2V d3V] = basis(2*N+1,xi);
Vp = basis(2*N+1,x); % plotting matrix

H = [V;dV;d2V;d3V];

% Runge's function
a = 5;
f = @(r) 1./(1+a*r.^2);
df = @(r) -(2*a*r)./(a*r.^2 + 1).^2;
d2f = @(r) (8*a^2*r.^2)./(a*r.^2 + 1).^3 - (2*a)./(a*r.^2 + 1).^2;
d3f = @(r) (24*a^2*r)./(a*r.^2 + 1).^3 - (48*a^3*r.^3)./(a*r.^2 + 1).^4;

a = 5;
f = @(x) tanh(a*x);
df = @(x) -a*(tanh(a*x).^2 - 1);
d2f = @(x) 2*a^2*tanh(a*x).*(tanh(a*x).^2 - 1);
d3f = @(x) - 2*a^3*(tanh(a*x).^2 - 1).^2 - 4*a^3*tanh(a*x).^2.*(tanh(a*x).^2 - 1);

plot(x,f(x))
hold on
plot(x,Vp*(H\[f(xi);df(xi);d2f(xi);d3f(xi)]),'--')

% compare with Lagrange interpolation of same degree
xi = linspace(-1,1,2*N+2)';
V = basis(2*N+1,xi);
plot(x,Vp*(V\f(xi)))

legend('True function','Hermite interpolant','Lagrange interpolant')

% use monomial basis to represent for now
function [V dV d2V d3V] = basis(N,r)

V = zeros(numel(r),N+1);
dV = zeros(numel(r),N+1);
d2V = zeros(numel(r),N+1);
d3V = zeros(numel(r),N+1);

for i = 0:N
    V(:,i+1) = r.^i;
    if i > 0
        dV(:,i+1) = i*r.^(i-1);
    end
    if i > 1
        d2V(:,i+1) = i*(i-1)*r.^(i-2);
    end
    if i > 2
        d3V(:,i+1) = i*(i-1)*(i-2)*r.^(i-3);
    end
end