function H = taylortool(varargin)
%TAYLORTOOL A Taylor series calculator.
%
%   TAYLORTOOL is an interactive Taylor series calculator that 
%   graphs a function f against the Nth partial sum of its
%   Taylor series over [-2*pi,2*pi]. The default values for f
%   and N are x*cos(x) and 7, respectively.
%
%   TAYLORTOOL(f) Graphs the function f versus the Nth
%   partial sum of the Taylor series for f over [-2*pi,2*pi].
%   The default value for N is 7.
%   Note that f must be a quoted string.
%
%   Example:  taylortool('sin(tan(x)) - tan(sin(x))')
%
%   See also, FUNTOOL

%   Copyright 1993-2000 The MathWorks, Inc. 
%   $Revision: 1.5 $
%   P. J. Costa

% Define the set of actions.
S = {'initialize','plot','Reset','Help','Increment','Close'};

switch nargin
case 0
   ud.f = sym('x*cos(x)');
   action = 'initialize';
case 1
   ud = get(gcbf,'Userdata');
   % taylortool(f)
   if isempty(intersect(varargin{1},S))
      ud.f = sym(varargin{1});
      action = 'initialize';
   % taylortool('plot')
   elseif ~isempty(intersect(varargin{1},S)) & isempty(ud)
      ud.f = sym('x*cos(x)');
      action = varargin{1};
   % taylortool('plot') & a function is already in Feditbox.
   elseif ~isempty(intersect(varargin{1},S)) & ~isempty(ud)
      ud.f = sym(get(ud.Handle.Feditbox,'String'));
      action = varargin{1};
   else
      ud.f = sym('x*cos(x)');
      action = 'initialize';
   end
end

switch action
case 'initialize'
   ud.N = 7; % N = order of the partial sum.
   ud.a = 0; % a = center or basepoint of the series.
   ud.D = [-2*pi,2*pi]; % Initial domain.
   ud.t = taylor(ud.f,ud.N+1,ud.a);
   fig = LocalOpenFig(ud);
   taylorplot(ud.f,ud.N+1,ud.a,ud.D,fig);
   set(fig,'HandleVisibility','CallBack');
case 'plot'
   ud = get(gcbf,'Userdata');
   try
      ud.f = sym(get(ud.Handle.Feditbox,'String'));
   catch
      Errstr = [get(ud.Handle.Feditbox,'String') ...
              ' is not a valid symbolic object.'];
      errordlg(Errstr);
      set(ud.Handle.taylortext,'String',Errstr);
      return
   end
   % f = sym(get(ud.Handle.Feditbox,'String'));
   ud.N = str2double(get(ud.Handle.Neditbox,'String'));
   Errstr = '';
   if isnan(ud.N) | ~(floor(ud.N) == ud.N) | (ud.N < 0)
      Errstr = 'N must be a non-negative integer.';
   end
   if ~isempty(Errstr)
      errordlg(Errstr);
      set(ud.Handle.taylortext,'String',Errstr);
      return
   end
   % N = eval(get(ud.Handle.Neditbox,'String'));
   try
      ud.a = eval(get(ud.Handle.Aeditbox,'String'));
      Errstr = '';
   catch
      Errstr = 'a must use floating point (double) number.';
   end
   if ~isempty(Errstr)
      errordlg(Errstr);
      set(ud.Handle.taylortext,'String',Errstr);
      return
   end
   % a = eval(get(ud.Handle.Aeditbox,'String'));
   try
      ud.D(1) = eval(get(ud.Handle.Leditbox,'String'));
      ud.D(2) = eval(get(ud.Handle.Reditbox,'String'));
      Errstr = '';
   catch
      Errstr = ['The domain endpoints must be floating point' ...
                '(double) numbers.'];
   end
   if ud.D(1) >= ud.D(2)
      Errstr = 'The left endpoint must be less than the right endpoint.';
   end
   if ~isempty(Errstr)
      errordlg(Errstr);
      set(ud.Handle.taylortext,'String',Errstr);
      return
   end
   set(gcbf,'Userdata',ud);
   try
      t = taylorplot(ud.f,ud.N+1,ud.a,ud.D,gcbf);
      Errstr = '';
   catch
      Errstr = ['The function ' char(ud.f) ' does not have ' ...
            'a Taylor series expansion about ' mat2str(ud.a) '.'];
   end
   if ~isempty(Errstr)
      errordlg(Errstr);
      set(ud.Handle.taylortext,'String',Errstr);
      return
   end
   set(ud.Handle.taylortext,'String',texlabel(slen(char(t)),70));
case 'Increment'
   ud = get(gcbf,'Userdata');
   tag = get(gcbo,'Tag');
   N = str2num(get(ud.Handle.Neditbox,'String'));
   switch tag
   case 'Nup'
      N = N + 1;
   case 'Ndown'
      N = N - 1;
   otherwise
      N = N;
   end
   set(ud.Handle.Neditbox,'String',num2str(N) );
   taylortool('plot')
case 'Help'
   MyHelp;
case 'Reset'
   ud = get(gcbf,'Userdata');
   % Keep the current function . . .
   set(ud.Handle.Feditbox,'String',char(ud.f));
   % . . . but reset a, N, D, and t to their initial states.
   ud.N = 7; % N = order of the partial sum.
   ud.a = 0; % a = center or basepoint of the series.
   ud.D = [-2*pi,2*pi]; % Initial domain.
   ud.t = taylor(ud.f,ud.N+1,ud.a);  % Taylor series.
   set(ud.Handle.Aeditbox,'String',num2str(ud.a) );
   set(ud.Handle.Neditbox,'String',num2str(ud.N) );
   set(ud.Handle.Leditbox,'String',char(sym(ud.D(1))) );
   set(ud.Handle.Reditbox,'String',char(sym(ud.D(2))) );
   set(ud.Handle.taylortext,'String',texlabel(ud.t))
   taylorplot(ud.f,ud.N+1,ud.a,ud.D,gcbf);
   set(gcbf,'HandleVisibility','CallBack');
   set(gcbf,'Userdata',ud);
case 'Close'
   close;
end
if nargout > 0, H = fig; end

%---------------------------%
function H = LocalOpenFig(ud)
%LOCALOPENFIG Opens the GUI for the Taylor Series Tool.
%   LOCALOPENFIG(ud.f,ud.N,ud.a,ud.D,ud.t) sets the function f = f(x), the
%   number of terms in the Talyor partial sum N, the center
%   or base point a, and the Taylor series t.  The Domain over
%   which the approximation will be plotted D.
%
%   Example:  LocalOpenFig('x*cos(x)',12,0,[-2*pi,2*pi],'x-1/2*x^3')

StdUnit = 'point';
StdColor = get(0,'DefaultUIcontrolBackgroundColor');
PointsPerPixel = 72/get(0,'ScreenPixelsPerInch');

h0 = figure('Color',[13/15 13/15 13/15], ...
   'Units','points','name','Taylor Tool', ...
   'number','off','IntegerHandle','off', ...
   'Position',[150 100 520 420]*PointsPerPixel, ...
	'Tag','Taylor Tool');
h1 = axes('Parent',h0, ...
	'Units','points', ...
	'CameraUpVector',[0 1 0], ...
	'CameraUpVectorMode','manual', ...
	'Color',[1 1 1], ...
	'Position',[40 203 453 167]*PointsPerPixel, ...
	'Tag','FigAxis', ...
	'XColor',[0 0 0], ...
	'YColor',[0 0 0], ...
	'ZColor',[0 0 0]);
h1 = axes('Parent',h0, ...
	'Units','points', ...
	'Position',[28 125 464 54]*PointsPerPixel, ...
   'HandleVisibility','off', ...
	'box','on', ...
   'xlim',[0,1],'ylim',[0,1], ...
   'xtick',[],'ytick',[], ...
   'color',[0.8,0.8,0.8], ...
	'Tag','Tayframe');
h2 = text(0.01,0.5,'T_N(x) =','Parent',h1, ...
	 'Interpreter','tex', ...
    'Tag','FrameText');
ud.Handle.taylortext = ...
   text(0.1125,0.545,texlabel(slen(char(ud.t)),70),'Parent',h1, ...
	 'Interpreter','tex', ...
    'Tag','taylortext');
h1 = uicontrol('Parent',h0, ...
	'Units','points', ...
	'HorizontalAlignment','left', ...
   'Position',[28 94 32 20]*PointsPerPixel, ...
   'BackGroundColor',[13/15 13/15 13/15], ...
	'String','f(x)  = ', ...
   'Style','text', ...
   'fontsize',12,...
	'Tag','Function');
ud.Handle.Feditbox = ...
   uicontrol('Parent',h0, ...
	'Units','points', ...
	'BackgroundColor',[1 1 1], ...
	'Callback','taylortool(''plot'');', ...
	'HorizontalAlignment','left', ...
	'Position',[69 91 423 24]*PointsPerPixel, ...
	'String',char(ud.f), ...
   'Style','edit', ...
   'fontsize',12,...
	'Tag','Feditbox');
h1 = uicontrol('Parent',h0, ...
	'Units','points', ...
	'HorizontalAlignment','left', ...
   'Position',[161 59 25 20]*PointsPerPixel, ...
   'BackGroundColor',[13/15 13/15 13/15], ...
	'String','a = ', ...
   'Style','text', ...
   'fontsize',12,...
	'Tag','Basepoint');
ud.Handle.Aeditbox = ...
   uicontrol('Parent',h0, ...
	'Units','points', ...
	'BackgroundColor',[1 1 1], ...
   'Callback','taylortool(''plot'');', ...
	'HorizontalAlignment','left', ...
	'Position',[188 57 70 24]*PointsPerPixel, ...
   'String',ud.a, ...
   'fontsize',12, ...
	'Style','edit', ...
	'Tag','Aeditbox');
h1 = uicontrol('Parent',h0, ...
	'Units','points', ...
	'HorizontalAlignment','left', ...
   'Position',[28 40 25 20]*PointsPerPixel, ...
   'BackGroundColor',[13/15 13/15 13/15], ...
	'String','N = ', ...
   'Style','text', ...
   'fontsize',12, ...
	'Tag','Number');
ud.Handle.Neditbox = ...
   uicontrol('Parent',h0, ...
	'Units','points', ...
	'BackgroundColor',[1 1 1], ...
   'Callback','taylortool(''plot'');', ...
	'HorizontalAlignment','left', ...
	'Position',[54 38 44 23]*PointsPerPixel, ...
	'String',ud.N, ...
   'Style','edit', ...
   'fontsize',12, ...
	'Tag','Neditbox');
ud.Handle.Leditbox = ...
   uicontrol('Parent',h0, ...
	'Units','points', ...
	'BackgroundColor',[1 1 1], ...
   'Callback','taylortool(''plot'');', ...
	'HorizontalAlignment','left', ...
	'Position',[309 57 70 24]*PointsPerPixel, ...
	'String',char(sym(ud.D(1))), ...
   'Style','edit', ...
   'fontsize',12, ...
	'Tag','Leditbox');
ud.Handle.Reditbox = ...
   uicontrol('Parent',h0, ...
	'Units','points', ...
	'BackgroundColor',[1 1 1], ...
   'Callback','taylortool(''plot'');', ...
	'HorizontalAlignment','left', ...
	'Position',[422 55.5 70 24]*PointsPerPixel, ...
	'String',char(sym(ud.D(2))), ...
   'Style','edit', ...
   'fontsize',12, ...
	'Tag','Reditbox');
h1 = uicontrol('Parent',h0, ...
	'Units','points', ...
   'Position',[385 59 32 20]*PointsPerPixel, ...
   'BackGroundColor',[13/15 13/15 13/15], ...
	'String',' < x < ', ...
   'Style','text', ...
   'fontsize',12, ...
	'Tag','Domain');
h1 = uicontrol('Parent',h0, ...
	'Units','points', ...
	'Position',[315 19 60 25]*PointsPerPixel, ...
   'Callback','taylortool(''Reset'');', ...
	'String','Reset', ...
	'Tag','Reset');
h1 = uicontrol('Parent',h0, ...
	'Units','points', ...
	'Position',[432 19 60 25]*PointsPerPixel, ...
   'Callback','taylortool(''Close'');', ...
	'String','Close', ...
	'Tag','Close');
h1 = uicontrol('Parent',h0, ...
	'Units','points', ...
   'Position',[192 19 60 25]*PointsPerPixel, ...
   'Callback','taylortool(''Help'');', ...
	'String','Help', ...
	'Tag','Help');
h1 = uicontrol('Parent',h0, ...
	'Units','points', ...
	'Position',[106 51 16 15]*PointsPerPixel, ...
   'Callback','taylortool(''Increment'');', ...
   'String','»',...
	'Tag','Nup');
h1 = uicontrol('Parent',h0, ...
	'Units','points', ...
	'Position',[106 31 16 15]*PointsPerPixel, ...
   'Callback','taylortool(''Increment'');', ...
   'String','«', ...
   'Tag','Ndown');
Hui = findobj(gcf,'type','uicontrol');
Hax = findall(gcf,'type','axes');
set(Hui,'Units','normalized');
set(Hax,'Units','normalized');
set(h0,'UserData',ud);
if nargout > 0, H = h0; end

%----------------------------------%
function MyHelp
%MYHELP is the Window Help information for TAYLORTOOL.

Helpstr = {'TAYLORTOOL is a pedagogical utility designed to';
           'help you understand how Taylor series are used to';
           'approximate functions of a single variable.  The';
           'notation T (x) denotes the Nth partial sum of the';
           '          N                       ;'
           'Taylor series for the function f(x) centered about'
           'the point x = a.                  ';
           '                                  ';
           'TAYLORTOOL(f) illustrates the relationship between the';
           'function f(x), the number of terms N in the partial sum';
           'T (x), and the point (x = a) about which the series is'
           ' N                                ';
           'centered.  Both f(x) and T (x) are plotted over a';
           '                          N       ';
           'prescribed interval for x.        ';
           '                                  ';
           'The default values are f(x) = x*cos(x), a = 0; N = 7,';
           'and -2*pi < x < 2*pi              ';
           '                                  ';  
           'To change any value of f(x), N, a, or the limits';
           'over which f(x) is plotted, change the entry in';
           'the appropriate box and press the <enter>/<return>';
           'or <tab> keys.  You may increase or decrease the value';
           'of N by 1 by performing a mouse click on the » or « button,';
           'respectively.                      ';};
  helpwin(Helpstr,'taylortool');

%-------------------------

function c = plmin(s)
%PLMIN  PLMIN(s) is true for + or - not inside parentheses.
p = cumsum((s == '(') - (s == ')'));
c = (s == '+' | s == '-') & (p == 0);

%----------------------------------%
function S = slen(S)
% SLEN Reduces the length of a Taylor series by removing
%   terms until the string is less than 70 characters long.
%
%   Example:
%     S = ['1+x+1/2*x^2-1/8*x^4-1/15*x^5-1/240*x^6+1/90*x^7+' ...
%          '31/5760*x^8+1/5670*x^9-2951/3628800*x^10-1/3150*x^11'];
%     slen(S)  returns
%         1+x+1/2*x^2-1/8*x^4-1/15*x^5-1/240*x^6+1/90*x^7+...-1/3150*x^11

B = plmin(S); % Determine where S has + or -.
B1 = find(B == 1);
S1 = S;
for j = 1:length(B1)-1
   if length(S) < 70
      return;
   else
      S = [S(1:B1(end-j)) '...' S1(B1(end):end)];
   end
end

%----------------------------------%
function t = taylorplot(f,N,a,D,fig)
% TAYLORPLOT is the callback function that produces
%   the plot for the Taylor GUI.
% 
% TAYLORPLOT(f,N,a,D) plots a comparison of the
% function f(x) to the partial sum of order N of the Taylor series
% for f(x) about the basepoint a over the interval D = [xo,x1],
% in the figure window FIG.  Here the partial sum of order N is,
%                  n
%                 d f              n
% T_N(x) = sum(  ---- (a) * (x - a) , n = 0 .. N )
%                   n 
%                 dx
%

% Define a symbolic variable.
x = findsym(sym(f),1);
% Let N be the number of terms and a be the basepoint
% of the Taylor Approximant to f(x).
% Compute the first N terms of the Taylor series for f(x)
% about the basepoint a.
t = taylor(f,x,N,a);
% The functions f and t will be ploted over the interval
% [xo,x1];
ezplot(f,D,fig);
a = axis;
a(3:4) = 2*a(3:4);
hold on;
ezplot(t,D,fig);
axis(a);
xlabel(''); title('Taylor Series Approximation');
% Find the curves being plotted . . .
hT = findobj(gcf,'type','line');
% . . . and color them. 
set(hT(1),'color','r','LineStyle',':','Linewidth',2.5); % red
set(hT(2),'color','b'); % blue
% Place a "map legend" in the upper right hand corner of the plot
% legend('Function','Taylor',1);
hold off;
