function [t,u]=cranknic(odefun,tspan,y0,Nh,varargin)
%CRANKNIC  Solve differential equations using the
%  Crank-Nicolson method.
%  [T,Y]=CRANKNIC(ODEFUN,TSPAN,Y0,NH) with TSPAN=[T0,TF]
%  integrates the system of differential equations
%  y'=f(t,y) from time T0 to TF with initial condition
%  Y0 using the Crank-Nicolson method on an equispaced
%  grid of NH intervals.Function ODEFUN(T,Y) must return
%  a column vector corresponding to f(t,y). Each row in
%  the solution array Y corresponds to a time returned
%  in the column vector T.
%  [T,Y] = CRANKNIC(ODEFUN,TSPAN,Y0,NH,P1,P2,...) passes
%  the additional parameters P1,P2,... to the function
%  ODEFUN as ODEFUN(T,Y,P1,P2...).
tt=linspace(tspan(1),tspan(2),Nh+1);
y=y0(:); % convert y in a vector column
u=y.';
global glob_h glob_t glob_y glob_odefun;
glob_h=(tspan(2)-tspan(1))/Nh;
glob_y=y;
glob_odefun=odefun;
if ( exist('OCTAVE_VERSION') )
o_version=OCTAVE_VERSION;
version=str2num([o_version(1),o_version(3),o_version(5)]);
end

if( ~exist('OCTAVE_VERSION')  | version >= 320 )
 options=optimset;
 options.Display='off';
 options.TolFun=1.e-12;
 options.MaxFunEvals=10000;
end
for glob_t=tt(2:end)
if ( exist('OCTAVE_VERSION') & version < 320 )
  w = fsolve('cranknicfun',glob_y);
else
  w = fsolve(@(w) cranknicfun(w),glob_y,options);
end
  u = [u; w.'];
  glob_y = w;
end
t=tt';
clear glob_h glob_t glob_y glob_odefun;
end

function z=cranknicfun(w)
  global glob_h glob_t glob_y glob_odefun;
  z=w - glob_y - ...
    0.5*glob_h*(glob_odefun(glob_t,w) + ...
    glob_odefun(glob_t-glob_h,glob_y));
end
