function Error=ShapePreserving(T,Y)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% ShapePreserving.m constructs the best convex-concave and otherwise free
%% constrained cubic splines intrepolating given data.
%
% Modified: 17 January, 2007
%
% Author: 
%
% Houduo Qi
% School of Mathematics
% University of Southampton
% Highfield
% Southampton SO17 1BJ
% England
%%
% Input
% T=[t_1, t_2,...,t_{N+2}]'; (column vector)
% Y=[y_1, y_2,...,y_{N+2}]'; (column vector)
%
% Output
% Error=norm of gradient of the objective function f
% figure: dashed line is the resulting shape-preserving cubic spline
%         solid line is the natural spline interpolating the given data

% References
%
% A. Dontchev, H.-D. Qi, L. Qi, and H. Yin:
% A Newton method for shape-prserving spline interpolation
% SIOPT, 13 (2): 588--602
%
% MATLAB code sptsl.m by John Burkardt was used to solve the tridiagonal
% linear equations appeared in Newton's method for the best convex case
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 [N,NC]=size(T);
 N=N-2;
  
%    Parameter settings
%
  rho=0.5; %(Armijo steplenth)
   sigma=0.1;
   delta=0;
   tol=1e-10;
%  kondmax=1e16; 
  tmin= 2^(-3);%1.e-16;

% Number of iteration 

   k=0;

% Number of line search used
  lsit=0;
% The maximum iteration allowed

  kmax=1000;

% 2nd divided differences

  D=zeros(N,1);

  for i=1:N
   Delta1=(Y(i+1)-Y(i))/(T(i+1)-T(i));
   Delta2=(Y(i+2)-Y(i+1))/(T(i+2)-T(i+1));   
   D(i)=1/(T(i+2)-T(i))*(Delta2-Delta1);
  end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Data Removal Process Started (if you want to remove some data)
% % Data removal: Remove data Y(i+1) if D(i)==0
% % J1=zeros(N+2,1);
% 
% for i=1:(N+2)
%     J1(i)=i;
% end
% I=find(abs(D) <= 1.0e-5); % D(i) is thought to be zeros if |D(i)| <= small number
% 
% [s1, s2]=size(I);
% if s2==0 % I is empty
%    return;
% else
%    for i=1:s1
%        J1(I(i)+1)=0;
%    end
%    J=find(J1>0.5);
%    T=T(J);
%    Y=Y(J);
%    %%% Data removal process is completed
%    % Re-set other paratemetres associated with T
%    [N,NC]=size(T);
%    N=N-2;
%    % New 2nd divided differences
%   D=zeros(N,1);
% 
%   for i=1:N
%    Delta1=(Y(i+1)-Y(i))/(T(i+1)-T(i));
%    Delta2=(Y(i+2)-Y(i+1))/(T(i+2)-T(i+1));   
%    D(i)=1/(T(i+2)-T(i))*(Delta2-Delta1);
%   end
% 
% end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%End of data removal process%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 
% Defining II, the classification vector

  II=zeros(N,1);
  
% Allow 0 values in D(i)
  if D(1)>0
    II(1)=1;
  elseif D(1)<0
    II(1)=-1;
  else
    II(1)=0;
  end

  for i=2:N
   if (D(i-1) > 0) & (D(i) >0)
     II(i)=1;
      elseif (D(i-1)<0) & (D(i) <0)
     II(i)=-1;
        else
     II(i)=0;
   end
  end
% STARTING POINT


  Lam=sign(D);   

% We are going to solve the equations:
% F(\lambda)=2d (see, [Andersson and Elfving [SIAM Scientifc 87, 1014]

% Calculate the gradient $F(Lam)$ and the function $f(\Lam)$ itself

   [F, f]=Ff(T, Lam, D, II);

  Fold=F;
  fold=f;
% Number of function evaluation

   nf=1;
   
% Norm of the gradient of f

   ngf=norm(Fold);

% Calculate the Jacobian matrix $M(\lambda)$

   [dM, offdM]=Jacob(T, Lam, II);

% Loop
%
  while (k < kmax) & (ngf > tol)
      k=k+1;
%%%%%%use sptsl to solve the tridiagonal linear equations
        dM=dM+min(delta, ngf); % diagonal vector of Mk
%     regularization with a small positive diagonal matrix
%     numerical performance shows that no regularization performs best
%     hence, in this code, delta=0.
        d=sptsl(N,dM,offdM,-Fold);
%%%%%%%% end of sptsl
%%%%%%line search%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	t=1;
	Lamnew=Lam + t*d;
    [Fnew, fnew]=Ff(T, Lamnew, D, II);
	nf=nf+1;
    
    bound=sigma*Fold'*d;
    
       while (fnew > (fold + t*bound))  & (t>tmin) 
	      
	      lsit=lsit+1;
          t=rho*t;
	      Lamnew=Lam +t*d;
          [Fnew,fnew]=Ff(T, Lamnew, D, II);
	      
	      nf=nf+1;
	    end
%%%%%%%%% end of line search%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%Updates%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	Lam=Lamnew;
	fold=fnew;
    Fold=Fnew;
	ngf=norm(Fold);
	[dM, offdM]=Jacob(T,Lam, II);
  end % end of while (first)

  Error=ngf;
% Output some information as the number of iterations
 fprintf('Number of iteration =%d\n', k);
 fprintf('Size of the problem =%d\n', N);
 fprintf('Number of function evaluations =%d\n', nf);
 fprintf('Number of line search called =%d\n', lsit);
 fprintf('Final value of the error =%10.1e\n', ngf);

% end
% Now generating the convex cubic spline
% The procedure is taken from [Andersson and Elfving]
% Let \bar \lambda=4\lambda/(t_{i+2)-t_i)
%
  Barlam=zeros(N,1);
  for i=1:N
      Barlam(i)=4*Lam(i)/(T(i+2)-T(i));
  end

 cubic=Cubic(T, Y, II, Barlam);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Enf of Main Program: ShapePreserving.m%%%%%%%%%%%%%%%%%%%%

 function [F,f]=Ff(T, Lam, D, II)

%The function fvalue uses one application of SIMPSON's rule to calculate
%numerically the integral which reaults in the functional value of $f(Lam)$
% BEND is the basic matrix on data T, that is the matrix BEND in the main
% program, BMID is a matrix on the data (T(i)+T(i+1))/2
% II is an indentification vector whose values are 1, -1, 0 and
% II(i)=1 means [t_i, t_{i+1}] belongs to $\Omega_1$
% II(i)=-1 means [t_i, t_{i+1}] belongs to $\Omega_2$
% II(i)=0 means [t_i, t_{i+1}] belongs to $\Omega_3$

% f(\lambda)=\int_a^b(\sum_{l=1}^N \lambda_l B_l)_+^2X_{\Omega_1} dt
%            +\int_a^b(\sum_{l=1}^N \lambda_l B_l)_-^2X_{\Omega_2} dt
%            +\int_a^b(\sum_{l=1}^N \lambda_l B_l)^2X_{\Omega_3} dt

 [N,NC]=size(T);
 N=N-2;
 f=0;
 
 % Use Gamma and Psi to calculate F (DQQY03: Eq.(6))
 
 % for II(i)==1 ([t_i, t_{i+1}] \in \Omgea_1
 % Gamma(i)=int_{t_i}^{t_{i+1}} (lambda_{i-1}B_{i-1}(t) +
 % lambda_iB_i(t))_+ B_i(t)dt,  i=2, ... N
 % Psi(i-1)=int_{t_i}^{t_{i+1}} (lambda_{i-1}B_{i-1}(t) +
 % lambda_iB_i(t))_+ B_{i-1}(t)dt,  i=2, ... N
 
 % for II(i)==-1 ([t_i, t_{i+1}] \in \Omgea_2
 % Gamma(i)= - int_{t_i}^{t_{i+1}} (lambda_{i-1}B_{i-1}(t) +
 % lambda_iB_i(t))_- B_i(t)dt,  i=2, ... N
 % Psi(i-1)= - int_{t_i}^{t_{i+1}} (lambda_{i-1}B_{i-1}(t) +
 % lambda_iB_i(t))_- B_{i-1}(t)dt,  i=2, ... N
 
 % for II(i)==0 ([t_i, t_{i+1}] \in \Omgea_3
 % Gamma(i)=int_{t_i}^{t_{i+1}} (lambda_{i-1}B_{i-1}(t) +
 % lambda_iB_i(t)) B_i(t)dt,  i=2, ... N
 % Psi(i-1)=int_{t_i}^{t_{i+1}} (lambda_{i-1}B_{i-1}(t) +
 % lambda_iB_i(t)) B_{i-1}(t)dt,  i=2, ... N
 
 Gamma=zeros(N,1);
 Psi=zeros(N,1);
 
 % Calculate rho(i):=B_i(t_{i+1}) and lrho(i):=lambda_i*rho(i)
 rho=zeros(N,1);
 lrho=zeros(N,1);
 for i=1:N
     rho(i)=2/(T(i+2)-T(i));
     lrho(i)=Lam(i)*rho(i);
 end
 
% Calculate the first piece of intergral
% [t_i, t_{i+1}]
%
  Phi1=0;
  if (II(1)==1 & Lam(1)>=0) | (II(1)==-1 & Lam(1)<=0) | (II(1)==0)
     h=(T(2)-T(1))/2;
     f=f+2*lrho(1)^2*h/3;
     Phi1=2*Lam(1)*rho(1)^2*h/3; % To calculate Phi_1
  end
  
% Calculate the pieces on [T(2), T(3)] ... [T(N), T(N+1)]
%
  for i=2:N
      if II(i)==1
         if (Lam(i-1)>=0) & (Lam(i) >=0)
            h=(T(i+1)-T(i))/2;
            f=f+( lrho(i-1)^2 + lrho(i)^2 + (lrho(i-1)+lrho(i))^2 )*h/3;
            Gamma(i)=(2*Lam(i)*rho(i)^2 + Lam(i-1)*rho(i-1)*rho(i))*h/3;
            Psi(i-1)=(2*Lam(i-1)*rho(i-1)^2+Lam(i)*rho(i-1)*rho(i))*h/3;
         else
            T0=(lrho(i)*T(i)-lrho(i-1)*T(i+1))/(lrho(i)-lrho(i-1));
            H=T(i+1)-T(i);
               if (Lam(i-1)<0) & (Lam(i)>0)
                  h=(T(i+1)-T0)/2;
                  f=f+2*lrho(i)^2*h/3;
                  b1=rho(i-1)*h/H; 
                  % b1=B_{i-1}((T(i+1)+T0)/2) middle poin value of B_{i-1} at
                  % (T(i+1)+T0)/2
                  b2=0.5*rho(i)*(1+(T0-T(i))/H);
                  % b2=B_i((T(i+1)+T0)/2) middle poin value of B_i at
                  % (T(i+1)+T0)/2
                  Gamma(i)=( Lam(i)*rho(i)^2 + 4*( Lam(i-1)*b1*b2 + Lam(i)*b2^2 ) )*h/3;
                  Psi(i-1)=4*( Lam(i-1)*b1^2 + Lam(i)*b1*b2 ) *h/3;
               end
               if (Lam(i-1)>0) & (Lam(i)<0)
                   h=(T0-T(i))/2;
                   f=f+2*lrho(i-1)^2*h/3;
                   b1=0.5*rho(i-1)*(1+(T(i+1)-T0)/H);
                    % b1=B_{i-1}((T(i)+T0)/2) middle poin value of B_{i-1} at
                    % (T(i)+T0)/2
                   b2=rho(i)*h/H;
                    % b2=B_i((T(i+1)+T0)/2) middle poin value of B_i at
                    % (T(i)+T0)/2
                   Gamma(i)=4*( Lam(i-1)*b1*b2 + Lam(i)*b2^2 )*h/3;
                   Psi(i-1)=( Lam(i-1)*rho(i-1)^2 + 4*(Lam(i-1)*b1^2+Lam(i)*b1*b2) )*h/3;
               end
         end 
      end % end of (II(i)==1)
         if II(i)==-1
            if (Lam(i-1)<=0) & (Lam(i) <=0)
            h=(T(i+1)-T(i))/2;
            f=f+( lrho(i-1)^2 + lrho(i)^2 + (lrho(i-1)+lrho(i))^2 )*h/3;
            Gamma(i)=(2*Lam(i)*rho(i)^2 + Lam(i-1)*rho(i-1)*rho(i))*h/3;
            Psi(i-1)=(2*Lam(i-1)*rho(i-1)^2+Lam(i)*rho(i-1)*rho(i))*h/3;
         else
            T0=(lrho(i)*T(i)-lrho(i-1)*T(i+1))/(lrho(i)-lrho(i-1));
            H=T(i+1)-T(i);
               if (Lam(i-1)>0) & (Lam(i)<0)
                  h=(T(i+1)-T0)/2;
                  f=f+2*lrho(i)^2*h/3;
                  b1=rho(i-1)*h/H; 
                  % b1=B_{i-1}((T(i+1)+T0)/2) middle poin value of B_{i-1} at
                  % (T(i+1)+T0)/2
                  b2=0.5*rho(i)*(1+(T0-T(i))/H);
                  % b2=B_i((T(i+1)+T0)/2) middle poin value of B_i at
                  % (T(i+1)+T0)/2
                  Gamma(i)=( Lam(i)*rho(i)^2 + 4*( Lam(i-1)*b1*b2 + Lam(i)*b2^2 ) )*h/3;
                  Psi(i-1)=4*( Lam(i-1)*b1^2 + Lam(i)*b1*b2 ) *h/3;
               end
               if (Lam(i-1)<0) & (Lam(i)>0)
                   h=(T0-T(i))/2;
                   f=f+2*lrho(i-1)^2*h/3;
                   b1=0.5*rho(i-1)*(1+(T(i+1)-T0)/H);
                    % b1=B_{i-1}((T(i)+T0)/2) middle poin value of B_{i-1} at
                    % (T(i)+T0)/2
                   b2=rho(i)*h/H;
                    % b2=B_i((T(i+1)+T0)/2) middle poin value of B_i at
                    % (T(i)+T0)/2
                   Gamma(i)=4*( Lam(i-1)*b1*b2 + Lam(i)*b2^2 )*h/3;
                   Psi(i-1)=( Lam(i-1)*rho(i-1)^2 + 4*(Lam(i-1)*b1^2+Lam(i)*b1*b2) )*h/3;
               end  
            end
         end % end of (II(i)==1)
         if II(i)==0
            h=(T(i+1)-T(i))/2;
            f=f+( lrho(i-1)^2 + lrho(i)^2 + (lrho(i-1)+lrho(i))^2 )*h/3;
            Gamma(i)=(2*Lam(i)*rho(i)^2 + Lam(i-1)*rho(i-1)*rho(i))*h/3;
            Psi(i-1)=(2*Lam(i-1)*rho(i-1)^2+Lam(i)*rho(i-1)*rho(i))*h/3;
         end % end of (II(i)==0)
  end % end for i=2:N

% Calculate the last piece of the integral on [t_{N+1}, t_{N+2}]
%
  Phi2=0;
  if (II(N)==1 & Lam(N)>=0) | (II(N)==0 & Lam(N)<=0) | (II(N)==0)
     h=(T(N+2)-T(N+1))/2;
     f=f+2*lrho(N)^2*h/3;
     Phi2=2*Lam(N)*rho(N)^2*h/3; % to calculate Phi_2
  end
% Calculate f
f=0.5*f - Lam'*D;

% Calculate F
 F=zeros(N,1);
 F(1)=Phi1+Psi(1);
 for i=2:(N-1)
     F(i)=Gamma(i)+Psi(i);
 end
 F(N)=Gamma(N)+Phi2;
 F=F-D;
 
 return;
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %% Enf of Ff.m %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
  function [d, offd]=Jacob(T, Lam, II)

%The function fvalue uses one application of SIMPSON's rule to calculate
%numerically the integral which reaults in the Jacobian $M(Lam)$
%
% M(\lambda)(i,j) =\int_a^b (-\sum_{l=1}^N)_-^0 B_iB_j dt
% Refer to formulae (25) in my paper
% Output
% d=diagonal vector of the Jacobian matrix M
% offd=off diagonal vector (size (N-1)) of M

 [N,NC]=size(T);
 N=N-2;

% Calculate rho(i):=B_i(t_{i+1}) and lrho(i):=lambda_i*rho(i)
 rho=zeros(N,1);
 lrho=zeros(N,1);
 for i=1:N
     rho(i)=2/(T(i+2)-T(i));
     lrho(i)=Lam(i)*rho(i);
 end
 
 tau_1=0; tau_2=0;
 if (II(1)==1 & Lam(1)>=0) | (II(1)==-1 & Lam(1)<=0) | (II(1)==0)
     h=(T(2)-T(1))/2;
     tau_1=2*rho(1)^2*h/3;
 end
 
 if (II(N)==1 & Lam(N)>=0) | (II(N)==0 & Lam(N)<=0) | (II(N)==0)
     h=(T(N+2)-T(N+1))/2;
     tau_2=2*rho(N)^2*h/3;
 end
 % use a, b and c to denote the vectors contaning
 % a=(a_i) 
 % a_i=int_{t_i}^{t_{i+1}} P(lambda, t) B_i^2 dt
 % b=(b_i)
 % b_i=int_{t_i}^{t_{i+1}} P(lambda, t) B_{i-1}^2 dt
 % c=(c_i)
 % c_i=int_{t_i}^{t_{i+1}} P(lambda, t) B_iB_{i-1} dt
 % i=2, \ldots, N
 
 a=zeros(N-1,1);
 b=a;
 c=a;
 
 for i=2:N
     if II(i)==1
        if (Lam(i-1)>=0) & (Lam(i) >=0)
         h=(T(i+1)-T(i))/2;
         a(i-1)=2*rho(i)^2*h/3;
         b(i-1)=2*rho(i-1)^2*h/3;
         c(i-1)=rho(i-1)*rho(i)*h/3;
         else
         T0=(lrho(i)*T(i)-lrho(i-1)*T(i+1))/(lrho(i)-lrho(i-1));
         H=T(i+1)-T(i);
         biT0=rho(i)*(T0-T(i))/H;
         % biT0=B_i(T0)
         bi_1T0=rho(i-1)*(T(i+1)-T0)/H;
         % bi_1T0=B_{i-1}(T0)
         if (Lam(i-1)<0) & (Lam(i)>0)
             h=(T(i+1)-T0)/2;
             
             b1=rho(i-1)*h/H; 
             % b1=B_{i-1}((T(i+1)+T0)/2) middle poin value of B_{i-1} at
             % (T(i+1)+T0)/2
             b2=0.5*rho(i)*(1+(T0-T(i))/H);
             % b2=B_i((T(i+1)+T0)/2) middle poin value of B_i at
             % (T(i+1)+T0)/2
             a(i-1)=(rho(i)^2+biT0^2+4*b2^2)*h/3;
             b(i-1)=(bi_1T0^2+4*b1^2)*h/3;
             c(i-1)=(bi_1T0*biT0+4*b1*b2)*h/3;
         end
         if (Lam(i-1)>0) & (Lam(i)<0)
             h=(T0-T(i))/2;
             
             b1=0.5*rho(i-1)*(1+(T(i+1)-T0)/H);
             % b1=B_{i-1}((T(i)+T0)/2) middle poin value of B_{i-1} at
             % (T(i)+T0)/2
             b2=rho(i)*h/H;
             % b2=B_i((T(i)+T0)/2) middle poin value of B_i at
             % (T(i)+T0)/2
             a(i-1)=(biT0^2+4*b2^2)*h/3;
             b(i-1)=(rho(i-1)^2+4*b1^2+bi_1T0^2)*h/3;
             c(i-1)=(4*b1*b2+bi_1T0*biT0)*h/3;
         end
        end
     end % if II(i)==1
     if II(i)==-1
        if (Lam(i-1)<=0) & (Lam(i) <=0)
         h=(T(i+1)-T(i))/2;
         a(i-1)=2*rho(i)^2*h/3;
         b(i-1)=2*rho(i-1)^2*h/3;
         c(i-1)=rho(i-1)*rho(i)*h/3;
         else
         T0=(lrho(i)*T(i)-lrho(i-1)*T(i+1))/(lrho(i)-lrho(i-1));
         H=T(i+1)-T(i);
         biT0=rho(i)*(T0-T(i))/H;
         % biT0=B_i(T0)
         bi_1T0=rho(i-1)*(T(i+1)-T0)/H;
         % bi_1T0=B_{i-1}(T0)
         if (Lam(i-1)>0) & (Lam(i)<0)
             h=(T(i+1)-T0)/2;
             
             b1=rho(i-1)*h/H; 
             % b1=B_{i-1}((T(i+1)+T0)/2) middle poin value of B_{i-1} at
             % (T(i+1)+T0)/2
             b2=0.5*rho(i)*(1+(T0-T(i))/H);
             % b2=B_i((T(i+1)+T0)/2) middle poin value of B_i at
             % (T(i+1)+T0)/2
             a(i-1)=(rho(i)^2+biT0^2+4*b2^2)*h/3;
             b(i-1)=(bi_1T0^2+4*b1^2)*h/3;
             c(i-1)=(bi_1T0*biT0+4*b1*b2)*h/3;
         end
         if (Lam(i-1)<0) & (Lam(i)>0)
             h=(T0-T(i))/2;
             
             b1=0.5*rho(i-1)*(1+(T(i+1)-T0)/H);
             % b1=B_{i-1}((T(i)+T0)/2) middle poin value of B_{i-1} at
             % (T(i)+T0)/2
             b2=rho(i)*h/H;
             % b2=B_i((T(i)+T0)/2) middle poin value of B_i at
             % (T(i)+T0)/2
             a(i-1)=(biT0^2+4*b2^2)*h/3;
             b(i-1)=(rho(i-1)^2+4*b1^2+bi_1T0^2)*h/3;
             c(i-1)=(4*b1*b2+bi_1T0*biT0)*h/3;
         end
        end 
     end % if II(i)==-1
     if II(i)==0
        h=(T(i+1)-T(i))/2;
        a(i-1)=2*rho(i)^2*h/3;
        b(i-1)=2*rho(i-1)^2*h/3;
        c(i-1)=rho(i-1)*rho(i)*h/3; 
     end % if II(i)==0     
 end % for i=2:N

% Assigin values to d and offd
  d=zeros(N,1);
  offd=zeros(N-1,1);
  
  d(1)=tau_1+b(1);
  offd(1)=c(1);
  d(N)=tau_2+a(N-1);
  for i=2:(N-1)
      d(i)=a(i-1)+b(i);
      offd(i)=c(i);
  end
 
  return;
  
%%%%%%%%%%%%%% Enf of Jacob.m
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function b = sptsl ( n, d, e, b )

%% SPTSL solves a positive definite tridiagonal linear system.
%
%  Modified:
%
%    09 November 2006
%
%  Author:
%
%    MATLAB translation by John Burkardt.
%
%  Reference:
%
%    Dongarra, Moler, Bunch and Stewart,
%    LINPACK User's Guide,
%    SIAM, (Society for Industrial and Applied Mathematics),
%    3600 University City Science Center,
%    Philadelphia, PA, 19104-2688.
%    ISBN 0-89871-172-X
%
%  Parameters:
%
%    Input, integer N, the order of the matrix.
%
%    Input, real D(N), the diagonal of the tridiagonal matrix.
%
%    Input, E(N), the offdiagonal of the tridiagonal matrix in
%    entries E(1:N-1).
%
%    Input, real B(N), the right hand side.
%
%    Output, real B(N), the solution.
%

%
%  Check for 1 x 1 case.
%
  if ( n == 1 )
    b(1) = b(1) / d(1);
    return
  end

  nm1d2 = floor ( ( n - 1 ) / 2 );

  if ( 2 < n )

    kbm1 = n - 1;
%
%  Zero top half of subdiagonal and bottom half of superdiagonal.
%
    for k = 1 : nm1d2
      t1 = e(k) / d(k);
      d(k+1) = d(k+1) - t1 * e(k);
      b(k+1) = b(k+1) - t1 * b(k);
      t2 = e(kbm1) / d(kbm1+1);
      d(kbm1) = d(kbm1) - t2 * e(kbm1);
      b(kbm1) = b(kbm1) - t2 * b(kbm1+1);
      kbm1 = kbm1 - 1;
    end

  end

  kp1 = nm1d2 + 1;
%
%  Clean up for possible 2 x 2 block at center.
%
  if ( mod ( n, 2 ) == 0 )
    t1 = e(kp1) / d(kp1);
    d(kp1+1) = d(kp1+1) - t1 * e(kp1);
    b(kp1+1) = b(kp1+1) - t1 * b(kp1);
    kp1 = kp1 + 1;
  end
%
%  Back solve starting at the center, going towards the top and bottom.
%
  b(kp1) = b(kp1) / d(kp1);

  if ( 2 < n )

    k = kp1 - 1;
    ke = kp1 + nm1d2 - 1;

    for kf = kp1 : ke
      b(k) = ( b(k) - e(k) * b(k+1) ) / d(k);
      b(kf+1) = ( b(kf+1) - e(kf) * b(kf) ) / d(kf+1);
      k = k - 1;
    end

  end

  if ( mod ( n, 2 ) == 0 )
    b(1) = ( b(1) - e(1) * b(2) ) / d(1);
  end

return;

%%%%% End of sptsl.m %%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function cubic=Cubic(T,Y,II,alpha)
% II is the vector indicating where the intervals begong
% (T, Y) are original data
% alpha is the solution vector of the Dnewton
% alpha=Lam

  [N, Nc]=size(T);
  N=N-2;


%  for i=1:N
%    alpha(i)=alpha(i)/(T(i+2)-T(i));
%  end

% Between two endpoints, there exists at most one new Knot
% So for every interval [t_i, t_{i+1}], we assign six indexes, indicating
% where the knots are located
% K(i,j), j=1,2 3. and Z(i,j), j=1, 2,3.
% K(i,1)=t_i, K(i,3)=t_{i+1}, K(i,2) be the possible new Knot
% Z(i,1), Z(i,2) and Z(i,3) be the second derivatives at the Knots
% K(i,j), j=1,2,3.

% Sampling on each interval [T_i, T_{i+1}] and calculating the functional
% values on these sampling points. In every interval, we take 10 sample
% points, i.e., the jump step is h(i,1)/10 or h(i,2)/10 below.
%
% xs is x-sampling vector while ys is y-sampling vector

  xs=[]; ys=[];
  
% Working Interval [t_1, t_2]

  if II(1)==1
     K(1,1)=T(1); K(1,2)=0; K(1,3)=T(2);
     Z(1,1)=0;    Z(1,2)=0; Z(1,3)=max(0,alpha(1));
  elseif II(1)==-1
     K(1,1)=T(1); K(1,2)=0; K(1,3)=T(2);
     Z(1,1)=0;    Z(1,2)=0; Z(1,3)=min(0,alpha(1));
  end

% Cubic Spline in the interval [t_1, t_2]
% S(1,2)(t)=Z(1,3)/(6*h(1,2))*(t-t(1))^3+C(1,2)(t-K(1,1))+D(1,2)(K(1,3)-t)
% Conditions: S(1,2)(T(1))=Y(1);  S(1,2)(T_2)=Y(2)

  C(1,1)=0; D(1,1)=0;   % No use
  h(1,1)=0; %no use
  h(1,2)=K(1,3)-K(1,1);  %=T(2)-T(1);
  C(1,2)=Y(2)/h(1,2)-Z(1,3)*h(1,2)/6;
  D(1,2)=Y(1)/h(1,2);

% Save the first derivative of S(1,2) at t_2 for later use, denoted by ds

  ds=Z(1,3)/2*h(1,2)+C(1,2)-D(1,2);
 
% Sampling

  xsample=K(1,1):h(1,2)/10:K(1,3);
  ysample=Z(1,3)/(6*h(1,2))*(xsample-K(1,1)).^3+C(1,2)*(xsample-K(1,1))+...
          D(1,2)*(K(1,3)-xsample);
  xs=[xs xsample]; ys=[ys ysample];
  
% Now working on intervals [t_2, t_3] .... [t_N, t_{N+1}]

  for i=2:N

    if II(i)==1

% if min(alpha(i-1), alpha(i))<0 & max(alpha(i-1), alpha(i))>0    
% There is a new knot inserted
% Otherwise, no new knot incresed

  if alpha(i-1)>0 & alpha(i)<0
     K(i,1)=T(i); 
     K(i,2)=(alpha(i)*T(i)-alpha(i-1)*T(i+1))/(alpha(i)-alpha(i-1));
     K(i,3)=T(i+1);

     Z(i,1)=alpha(i-1);
     Z(i,2)=0;
     Z(i,3)=0;
 
% Cubic spline: There are two cubic splines on the interval 
% [T_i, K(i,2)] and [K(i,2), T_{i+1}], respectively
% Working interval [T_i, K(i,2)]
% S(i,1)(t)= Z(i,1)/(6*h(i,1))*(K(i,2)-t)^3+C(i,1)(t-K(i,1))+D(i,1)(K(i,2)-t)
% h(i,1)=K(i,2)-K(i,1)
% Conditions S(i,1)(T_i)=Y(i), S(i,1)'(T_i)=S(i-1,2)'(T_i)

  h(i,1)=K(i,2)-K(i,1);
  D(i,1)=Y(i)/h(i,1)-Z(i,1)*h(i,1)/6;
  C(i,1)=ds+Z(i,1)*h(i,1)/2+D(i,1);

% Save the function value at K(i,2)=yy;

  yy=C(i,1)*h(i,1);

% Sampling

  xsample=K(i,1):h(i,1)/10:K(i,2);
  ysample=Z(i,1)/(6*h(i,1))*(K(i,2)-xsample).^3+C(i,1)*(xsample-K(i,1))+...
  D(i,1)*(K(i,2)-xsample);
  xs=[xs xsample]; ys=[ys ysample];

% Working Interval [K(i,2), K(i,3)]
% S(i,2)(t)=C(i,2)(t-K(i,2))+D(i,2)(K(i,3)-t)
% Conditions: S(i,2)(T_{i+1})=Y(i+1); S(i,2)(K(i,2)=y

  h(i,2)=T(i+1)-K(i,2);
  C(i,2)=Y(i+1)/h(i,2);
  D(i,2)=yy/h(i,2);

% % Save the first derivative of S(i,2) at t_{i+1} for later use, denoted by ds

  ds=C(i,2)-D(i,2);

% Sampling

  xsample=K(i,2):h(i,2)/10:K(i,3);
  ysample=C(i,2)*(xsample-K(i,2))+D(i,2)*(K(i,3)-xsample);
  xs=[xs xsample]; ys=[ys ysample];

  elseif alpha(i-1)<0 & alpha(i)>0
  
    K(i,1)=T(i);    Z(i,1)=0;
    K(i,2)=(alpha(i)*T(i)-alpha(i-1)*T(i+1))/(alpha(i)-alpha(i-1));
    Z(i,2)=0;
    K(i,3)=T(i+1);  Z(i,3)=alpha(i);
    
% Cubic Splines: There are two cubic splines on the inetrvals:
% [K(i,1) K(i,2)] and [K(i,2), K(i,3)], respectively
% Working interval [K(i,1), K(i,2)]
% S(i,1)(t)=C(i,1)(t-K(i,1))+D(i,1)(K(i,2)-t)
% h(i,1)=K(i,2)-K(i,1);
% Conditions: S(i,1)(T(i))=Y(i), S(i,1)'(T(i))=S(i-1,2)'(T(i))

  h(i,1)=K(i,2)-K(i,1);
  D(i,1)=Y(i)/h(i,1);
  C(i,1)=ds+D(i,1);
  
% Save the function value at K(i,2), denoted by yy

  yy=C(i,1)*h(i,1);
 
% Sampling

  xsample=K(i,1):h(i,1)/10:K(i,2);
  ysample=C(i,1)*(xsample-K(i,1))+D(i,1)*(K(i,2)-xsample);
  xs=[xs xsample]; ys=[ys ysample];
  
% Working Interval [K(i,2) K(i,3)]
% S(i,2)(t)=Z(i,3)/(6*h(i,2))*(t-K(i,2))^3+C(i,2)*(t-K(i,2))+D(i,2)*(K(i,3)-t)
% h(i,2)=K(i,3)-K(i,2);
% Conditions: S(i,2)(K(i,2))=yy, S(i,2)(T(i+1))=Y(i+1)

  h(i,2)=K(i,3)-K(i,2);
  D(i,2)=yy/h(i,2);
  C(i,2)=Y(i+1)/h(i,2)-Z(i,3)*h(i,2)/6;
  
% Save the first derivative of S(i,2) at t_{i+1} for later use, denoted by ds 
 
  ds=Z(i,3)*h(i,2)/2+C(i,2)-D(i,2);
  
% Sampling
  
  xsample=K(i,2):h(i,2)/10:K(i,3);
  ysample=Z(i,3)/(6*h(i,2))*(xsample-K(i,2)).^3+...
          C(i,2)*(xsample-K(i,2))+D(i,2)*(K(i,3)-xsample);
  xs=[xs xsample]; ys=[ys ysample];
   
  else   % No new knots added 

    K(i,1)=T(i);   Z(i,1)=max(0, alpha(i-1));
    K(i,2)=0;      Z(i,2)=0;  %No use
    K(i,3)=T(i+1); Z(i,3)=max(0,alpha(i));

% Cubic Spline
% S(i,2)(t)=Z(i,3)/(6h(i,2))(t-K(i,1))^3+Z(i,1)/(6h(i,2))(K(i,3)-t)^3+...
%           C(i,2)(t-K(i,1))+D(i,2)(K(i,3)-t);
% Only one cubic spline, denoted S(i,2)(t)
% Conditions: S(i,2)(T_i)=Y_i; S(i,2)(T_{i+1})=Y_{i+1}

   h(i,2)=T(i+1)-T(i);
   D(i,2)=Y(i)/h(i,2)-Z(i,1)/6*h(i,2);
   C(i,2)=Y(i+1)/h(i,2)-Z(i,3)/6*h(i,2);
% Save the first derivative of S(i,2) at t_{i+1} for later use, denoted by ds

  ds=Z(i,3)/2*h(i,2)+C(i,2)-D(i,2);

% Sampling

  xsample=K(i,1):h(i,2)/10:K(i,3);
  ysample=Z(i,3)/(6*h(i,2))*(xsample-K(i,1)).^3+...
          Z(i,1)/(6*h(i,2))*(K(i,3)-xsample).^3+...
          C(i,2)*(xsample-K(i,1))+D(i,2)*(K(i,3)-xsample);
  xs=[xs xsample]; ys=[ys ysample];

  end
 end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  if II(i)==-1

% if min(alpha(i-1), alpha(i))<0 & max(alpha(i-1), alpha(i))>0
% There is a new knot inserted
% Otherwise, no new knot incresed
 
     if alpha(i-1)>0 & alpha(i)<0

        K(i,1)=T(i);   Z(i,1)=0;
        K(i,2)=(alpha(i)*T(i)-alpha(i-1)*T(i+1))/(alpha(i)-alpha(i-1));
        Z(i,2)=0;
        K(i,3)=T(i+1); Z(i,3)=alpha(i);

% Cubic spline: There are two cubic splines on [T(i), K(i,2)] and 
% [K(i,2), T(i+1)], respectively
% Working Interval [T(i), K(i,2)]
% S(i,1)(t)=C(i,1)(t-K(i,1))+D(i,1)(K(i,2)-t);
% Conditions: S(i,1)(T(i))=Y(i), S(i,1)'(T(i))=S(i-1,2)'(T(i));

        h(i,1)=K(i,2)-T(i);
        D(i,1)=Y(i)/h(i,1);
        C(i,1)=ds+D(i,1);

% Save the function value at K(i,2)=yy;
        
        yy=C(i,1)*h(i,1);

% Sampling

  xsample=K(i,1):h(i,1)/10:K(i,2);
  ysample=C(i,1)*(xsample-K(i,1))+D(i,1)*(K(i,2)-xsample);
  xs=[xs xsample]; ys=[ys ysample];

% Working Interval [K(i,2), T(i+1)]=[K(i,2), K(i,3)] 
% S(i,2)(t)=Z(i,3)/(6h(i,2))(t-K(i,2))^3+C(i,2)(t-K(i,2))+D(i,2)(K(i,3)-t);
%Conditions: S(i,2)(K(i,2))=y; S(i,2)(K(i,3))=Y(i+1);

        h(i,2)=K(i,3)-K(i,2);
        D(i,2)=yy/h(i,2);
        C(i,2)=Y(i+1)/h(i,2)-Z(i,3)/6*h(i,2);
% Save the first derivative of S(i,2) at t_{i+1} for later use, denoted by ds

        ds=Z(i,3)/2*h(i,2)+C(i,2)-D(i,2);
% Sampling

  xsample=K(i,2):h(i,2)/10:K(i,3);
  ysample=Z(i,3)/(6*h(i,2))*(xsample-K(i,2)).^3+...
          C(i,2)*(xsample-K(i,2))+D(i,2)*(K(i,3)-xsample);
  xs=[xs xsample]; ys=[ys ysample];

      elseif alpha(i-1)<0 & alpha(i)>0
      
      K(i,1)=T(i);     Z(i,1)=alpha(i-1);
      K(i,2)=(alpha(i)*T(i)-alpha(i-1)*T(i+1))/(alpha(i)-alpha(i-1));
      Z(i,2)=0;
      K(i,3)=T(i+1);   Z(i,3)=0;
      
% Cubic spline: There are two cubic splines on 
% [K(i,1), K(i,2)] and [K(i,2), K(i,3)], respectively
% Working Interval [K(i,1), K(i,2)]
% S(i,1)=Z(i,1)/(6h(i,1))*(K(i,2)-t)^3+C(i,1)(t-K(i,1))+D(i,1)(K(i,2)-t)
% h(i,1)=K(i,2)-K(i,1)
% Conditions: S(i,1)(T(i))=Y(i), S(i,1)'(T(i))=S(i-1,2)'(T(i))=ds

      h(i,1)=K(i,2)-K(i,1);
      D(i,1)=Y(i)/h(i,1)-Z(i,1)*h(i,1)/6;
      C(i,1)=ds+D(i,1)+Z(i,1)*h(i,1)/2;
      
% Save the function value at $K(i,2), denoted by yy

      yy=C(i,1)*h(i,1);
      
% Sampling 
    
      xsample=K(i,1):h(i,1)/10:K(i,2);
      ysample=Z(i,1)/(6*h(i,1))*(K(i,2)-xsample).^3+...
              C(i,1)*(xsample-K(i,1))+D(i,1)*(K(i,2)-xsample);
      xs=[xs xsample]; ys=[ys ysample];
      
% Working interval" [K(i,2), K(i,3)]
% S(i,2)(t)=C(i,2)(t-K(i,2))+D(i,2)(K(i,3)-t);
% Conditiond: S(i,2)(K(i,2))=yy; S(i,2)(T(i+1))=Y(i+1);

      h(i,2)=K(i,3)-K(i,2);
      D(i,2)=yy/h(i,2);
      C(i,2)=Y(i+1)/h(i,2);
      
% Save the first derivative of S(i,2) at t_{i+1} for later use, denoted by ds
  
      ds=C(i,2)-D(i,2);
      
% Sampling

     xsample=K(i,2):h(i,2)/10:K(i,3);    
     ysample=C(i,2)*(xsample-K(i,2))+D(i,2)*(K(i,3)-xsample);
     xs=[xs xsample]; ys=[ys ysample];    
            
      else  % No New knots added

        K(i,1)=T(i);   Z(i,1)=min(0, alpha(i-1));
        K(i,2)=0;      Z(i,2)=0; %No use
        K(i,3)=T(i+1); Z(i,3)=min(0,alpha(i));

% There is only one piece of cubic spline, namely
% S(i,2)(t)=Z(i,3)/(6h(i,2))(t-K(i,1))^3+Z(i,1)/(6h(i,2))(K(i,3)-t)^3+...
%           C(i,2)(t-K(i,1))+D(i,2)(K(i,3)-t);
% Conditions: S(i,2)(T(i))=Y(i);  S(i,2)(T(i+1))=Y(i+1);

        h(i,2)=K(i,3)-K(i,1);
        D(i,2)=Y(i)/h(i,2)-Z(i,1)/6*h(i,2);
        C(i,2)=Y(i+1)/h(i,2)-Z(i,3)/6*h(i,2);
% Save the first derivative of S(i,2) at t_{i+1} for later use, denoted by ds
     
        ds=Z(i,3)*h(i,2)/2+C(i,2)-D(i,2); 
% Sampling

  xsample=K(i,1):h(i,2)/10:K(i,3);
  ysample=Z(i,3)/(6*h(i,2))*(xsample-K(i,1)).^3+...
          Z(i,1)/(6*h(i,2))*(K(i,3)-xsample).^3+...
          C(i,2)*(xsample-K(i,1))+D(i,2)*(K(i,3)-xsample);
  xs=[xs xsample]; ys=[ys ysample];
     end
  end
    
    if II(i)==0
%This is natural spline on [T_i, T_{i+1}]

        K(i,1)=T(i);   Z(i,1)=alpha(i-1);
        K(i,2)=0;      Z(i,2)=0;   %No use
        K(i,3)=T(i+1); Z(i,3)=alpha(i);       
% Cubic spline: Only one, denoted by S(i,2)(t)
% S(i,2)(t)=Z(i,3)/(6h(i,2))(t-K(i,1))^3+Z(i,1)/(6h(i,2))(K(i,3)-t)^3+...
%           C(i,2)(t-K(i,1))+D(i,2)(K(i,3)-t);
%Conditions: S(i,2)(T(i))=Y(i);  S(i,2)(T(i+1))=Y(i+1)

        h(i,2)=T(i+1)-T(i);
        D(i,2)=Y(i)/h(i,2)-Z(i,1)/6*h(i,2);
        C(i,2)=Y(i+1)/h(i,2)-Z(i,3)/6*h(i,2);
% Save the first derivative of S(i,2) at t_{i+1} for later use, denoted by ds
     
        ds=Z(i,3)*h(i,2)/2+C(i,2)-D(i,2);
% Sampling

  xsample=K(i,1):h(i,2)/10:K(i,3);
  ysample=Z(i,3)/(6*h(i,2))*(xsample-K(i,1)).^3+...
          Z(i,1)/(6*h(i,2))*(K(i,3)-xsample).^3+...
          C(i,2)*(xsample-K(i,1))+D(i,2)*(K(i,3)-xsample);
  xs=[xs xsample]; ys=[ys ysample];
  end
end
%Working on the last interval [T(N+1), T(N+2)]
% This interval is determined by II(N), i.e., II(N)==1, it is convex ...

    if II(N)==1
       K(N+1,1)=T(N+1);   Z(N+1,1)=max(0,alpha(N));
       K(N+1,2)=0;        Z(N+1,2)=0;  %No use
       K(N+1,3)=T(N+2);   Z(N+1,3)=0;
     elseif II(N)==-1
       K(N+1,1)=T(N+1);   Z(N+1,1)=min(0,alpha(N));
       K(N+1,2)=0;        Z(N+1,2)=0;  %No use
       K(N+1,3)=T(N+2);   Z(N+1,3)=0;
     else
       K(N+1,1)=T(N+1);   Z(N+1,1)=alpha(N);
       K(N+1,2)=0;        Z(N+1,2)=0;  %No use
       K(N+1,3)=T(N+2);   Z(N+1,3)=0; 
    end
%Only one piece of cubic spline
%Denoted S(N+1,2)(t)=Z(N+1,1)/(6h(N+1,2))(T(N+2)-t)^3+C(N+1,2)(t-T(N+1))+...
%                    D(N+1,2)(T(N+2)-t);
%Conditions: S(N+1,2)(T(N+1))=Y(N+1);  S(N+1,2)(T(N+2))=Y(N+2)

    h(N+1,2)=T(N+2)-T(N+1);
    D(N+1,2)=Y(N+1)/h(N+1,2)-Z(N+1,1)*h(N+1,2)/6;
    C(N+1,2)=Y(N+2)/h(N+1,2);

% Sampling

  xsample=K(N+1,1):h(N+1,2)/10:K(N+1,3);
  ysample=Z(N+1,1)/(6*h(N+1,2))*(T(N+2)-xsample).^3+...
          C(N+1,2)*(xsample-T(N+1))+D(N+1,2)*(T(N+2)-xsample);
  xs=[xs xsample]; ys=[ys ysample]; 

% Generate the natural cubic spline
%
  xxx=T(1):0.02:T(N+2);
  yyy=spline(T,Y,xxx);
  
% Plot the natural cubic spline and the shape-preserving spline in 
% one figure

% plot(T,Y,'o',xxx,yyy,'-',xs,ys,'--')

% Plot the shape-preserving spline only 
plot(T,Y,'o',xs,ys,'--')
  
  cubic=1;

return;

%%%%%%%end of Cubic.m %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

