gusucode.com > symbolic工具箱matlab源码程序 > symbolic/taylortool.m

    function H = taylortool(f)
%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.
%
%   Example:  taylortool('sin(tan(x)) - tan(sin(x))')
%
%   See also FUNTOOL.

%   Copyright 1993-2013 The MathWorks, Inc.

if nargin<1
    f='x*cos(x)';
end

%Convert and store the input
[errMsg,ud.f,ud.N,ud.a,ud.D1,ud.D2] = checkAndConvert(f,'7','0','-2*pi','2*pi');
if ~isempty(errMsg)
    error(errMsg);
end

%Calculate the Taylor series expansion
ud.t = getTaylorResult(ud.f,ud.N,ud.a);
if isempty(ud.t)
    error(message('symbolic:taylortool:NoExpansion',char(ud.f),num2str(ud.a)));
end

%Set loading flag
ud.isReady = false;

%Create the GUI
fig = createTaylorToolGUI(ud);

%Plot the function and the Taylor series expansion
taylorplot(fig);

clearLoadingFlag(fig);

if nargout>0
    H = fig;
end

%---------------------------%
function [errMsg,fsym,Ndouble,adouble,D1double,D2double] = checkAndConvert(f,N,a,D1,D2)
%checkAndConvert: Checks the f, N, a, and [D1,D2] input values and converts
%them to the proper format. We assume that N, a, D1, and D2 are strings but
%we make no assumptions on f. If there is an issue with one of the inputs,
%then an error message will be stored in errMsg. Otherwise errMsg will be
%empty.

errMsg = '';
fsym = [];
Ndouble = [];
adouble = [];
D1double = [];
D2double = [];

%Convert the values
try 
    if ischar(f)
       fsym = evalin(symengine, f);
    else
       fsym = formula(sym(f));
    end    
catch
    errMsg = message('symbolic:taylortool:InvalidExpression',char(f));
    return;
end
try
    Ndouble = double(eval(N));
catch
    errMsg = message('symbolic:taylortool:InvalidDegree');
    return;
end
try
    adouble = double(eval(a));
catch
    errMsg = message('symbolic:taylortool:InvalidPoint');
    return;
end
try
    D1double = double(eval(D1));
    D2double = double(eval(D2));
catch
    errMsg = message('symbolic:taylortool:InvalidRange');
    return;
end

%Check the values
fvars = symvar(fsym);
if ~isscalar(fsym)
    errMsg = message('symbolic:taylortool:InvalidExpression',char(fsym));
elseif any(ismember(fvars,[sym('inf'),sym('Inf'),sym('NaN'),sym('nan')])) || ~isfinite(fsym)
    errMsg = message('symbolic:sym:InputMustNotContainNaNOrInf');
elseif ~(isscalar(fvars) || isempty(fvars))
    errMsg = message('symbolic:taylortool:InvalidExpression',char(fsym));
elseif strcmp(char(feval(symengine,'symobj::hasUnknownFunction',fsym)),'TRUE')
    errMsg = message('symbolic:taylortool:UnknownFunction', char(fsym));
elseif ~isscalar(Ndouble) || ~isfinite(Ndouble) || Ndouble<0 || floor(real(Ndouble))~=Ndouble
    errMsg = message('symbolic:taylortool:InvalidDegree');
elseif ~isscalar(adouble) || ~isfinite(adouble) || real(adouble)~=adouble
    errMsg = message('symbolic:taylortool:InvalidPoint');
elseif ~isscalar(D1double) || ~isscalar(D2double) || ~all(isfinite([D1double,D2double])) || ...
        D1double>=D2double || any(real([D1double,D2double])~=[D1double,D2double])
    errMsg = message('symbolic:taylortool:InvalidRange');
end

%---------------------------%
function taylorResult = getTaylorResult(f,N,a)
%getTaylorResult: Returns the Taylor series expansion of f with order N and
%expansion point a upon success. Otherwise an empty sym is returned.

%Get variable
var = symvar(f);
varAsChar = char(var);
if isempty(var)
    varAsChar = 'x';
end

%Assume var is real
varAssumptions = assumptions(var);
var = sym(varAsChar,'real');

try
    taylorResult = taylor(f,var,'ExpansionPoint',a,'Order',N+1);
catch
    taylorResult = sym([]);
end
%Make sure to not allow imaginary output
if ~isequal(imag(taylorResult),sym(0))
    taylorResult = sym([]);
end

%Reset assumption on var
if(isempty(varAssumptions))
    sym(varAsChar,'clear');
else
    assume(varAssumptions);
end

%---------------------------%
function fig = createTaylorToolGUI(ud)
%createTaylorToolGUI: Opens the GUI for the Taylor series tool and uses
%ud.f (sym), ud.t (sym), ud.N (double), ud.a (double), ud.D1 (double), and
%ud.D1 (double) to place initial values on the GUI.

PointsPerPixel = 72/get(0,'ScreenPixelsPerInch');

var = symvar(ud.f);
varAsChar = char(var);
if isempty(var)
    varAsChar = 'x';
end

%fig: figure window for the GUI
fig = figure(...
    'Tag','Taylor Tool',...
    'Units','points',...
    'Position',[150 100 520 420]*PointsPerPixel,...
    'name',getString(message('symbolic:taylortool:ToolName')),...
    'NumberTitle','off',...
    'IntegerHandle','off',...
    'HandleVisibility','callback',...
    'ToolBar','none');

%plotPanel: uipanel to hold plotAxes
ud.Handle.plotPanel = uipanel('Parent',fig,...
    'Tag','plotPanel',...
    'Units','normalized',...
    'Position',[0 0.45 1 0.55],...
    'BorderType','none');

%plotAxes: axes for the plot which is placed in plotPanel
ud.Handle.plotAxes = axes('Parent',ud.Handle.plotPanel,...
    'Tag','plotAxes',...
    'Units','normalized');
title(ud.Handle.plotAxes,getString(message('symbolic:taylortool:PlotTitle')));

%seriesPanel: uipanel to hold seriesAxes
ud.Handle.seriesPanel = uipanel('Parent',fig,...
    'Tag','seriesPanel',...
    'Units','normalized',...
    'Position',[0 0.3 1 0.15],...
    'BorderType','none');

%seriesAxes: axes containing the seriesText
ud.Handle.seriesAxes = axes('Parent',ud.Handle.seriesPanel,...
    'Tag','seriesAxes',...
    'Units','normalized',...
    'Position',[0.1 0.1 0.8 0.8],...
    'HandleVisibility','off',...
    'Box','on',...
    'XTick',[],'YTick',[],...
    'Color',[0.8,0.8,0.8]);

%seriesText: text object containing the series string
ud.Handle.seriesText = text(0.01,0.5,['T_N(' varAsChar ') = ' texlabel(slen(char(ud.t)),70)],...
    'Parent',ud.Handle.seriesAxes,...
    'Tag','seriesText',...
    'Units','normalized',...
    'Interpreter','tex',...
    'FontSize',10);

%fTextPanel: uipanel to hold fTextLabel
ud.Handle.fTextPanel = uipanel('Parent',fig,...
    'Tag','fTextPanel',...
    'Units','normalized',...
    'Position',[0 0.2 1 0.1],...
    'BorderType','none');

%fTextLabel: text uicontrol 'f(x) = '
ud.Handle.fTextLabel = uicontrol('Parent',ud.Handle.fTextPanel,...
    'Tag','fTextLabel',...
    'Units','normalized',...
    'Position',[0.1 0.2 0.1 0.6],...
    'Style','text',...
    'String',['f(' varAsChar ') = '],...
    'HorizontalAlignment','right',...
    'FontSize', 12);

%fEditBox: edit uicontrol for f user input
ud.Handle.fEditBox = uicontrol('Parent',ud.Handle.fTextPanel,...
    'Tag','fEditBox',...
    'Units','normalized',...
    'Position',[0.2 0.1 0.7 0.8],...
    'Style','edit',...
    'String',char(ud.f),...
    'HorizontalAlignment','left',...
    'FontSize', 12,...
    'BackgroundColor',[1 1 1],...
    'Interruptible','off',...
    'Callback',@(~,~) actionGetValuesAndPlot(fig));

%NaDPanel: uipanel to hold all the N, a, D1, and D2 buttons and inputs
ud.Handle.NaDPanel = uipanel('Parent',fig,...
    'Tag','NaDPanel',...
    'Units','normalized',...
    'Position',[0 0.1 1 0.1],...
    'BorderType','none');

%NLabel: text uicontrol 'N = '
ud.Handle.NLabel = uicontrol('Parent',ud.Handle.NaDPanel,...
    'Tag','NLabel',...
    'Units','normalized',...
    'Position',[0.1 0.2 0.1 0.6],...
    'Style','text',...
    'String','N = ',...
    'HorizontalAlignment','right',...
    'FontSize', 12);

%NEditBox: edit uicontrol for N user input
ud.Handle.NEditBox = uicontrol('Parent',ud.Handle.NaDPanel,...
    'Tag','NEditBox',...
    'Units','normalized',...
    'Position',[0.2 0.1 0.09 0.8],...
    'Style','edit',...
    'String',int2str(ud.N),...
    'HorizontalAlignment','left',...
    'FontSize', 12,...
    'BackgroundColor',[1 1 1],...
    'Interruptible','off',...
    'Callback',@(~,~) actionGetValuesAndPlot(fig));

%NupButton: pushbutton for N+
ud.Handle.NupButton = uicontrol('Parent',ud.Handle.NaDPanel,...
    'Tag','NupButton',...
    'Units','normalized',...
    'Position',[0.29 0.5 0.04 0.5],...
    'Style','pushbutton',...
    'String','+',...
    'HorizontalAlignment','center',...
    'FontSize', 10,...
    'FontName','Courier',...
    'FontWeight','bold',...
    'Interruptible','off',...
    'Callback',@(~,~) actionIncrement(fig,'up'));

%NdownButton: pushbutton for N-
ud.Handle.NdownButton = uicontrol('Parent',ud.Handle.NaDPanel,...
    'Tag','NdownButton',...
    'Units','normalized',...
    'Position',[0.29 0 0.04 0.5],...
    'Style','pushbutton',...
    'String','-',...
    'HorizontalAlignment','center',...
    'FontSize', 10,...
    'FontName','Courier',...
    'FontWeight','bold',...
    'Interruptible','off',...
    'Callback',@(~,~) actionIncrement(fig,'down'));

%aLabel: text uicontrol 'a = '
ud.Handle.aLabel = uicontrol('Parent',ud.Handle.NaDPanel,...
    'Tag','aLabel',...
    'Units','normalized',...
    'Position',[0.33 0.2 0.075 0.6],...
    'Style','text',...
    'String','a = ',...
    'HorizontalAlignment','right',...
    'FontSize', 12);

%aEditBox: edit uicontrol for a user input
ud.Handle.aEditBox = uicontrol('Parent',ud.Handle.NaDPanel,...
    'Tag','aEditBox',...
    'Units','normalized',...
    'Position',[0.405 0.1 0.125 0.8],...
    'Style','edit',...
    'String',char(sym(ud.a)),...
    'HorizontalAlignment','left',...
    'FontSize', 12,...
    'BackgroundColor',[1 1 1],...
    'Interruptible','off',...
    'Callback',@(~,~) actionGetValuesAndPlot(fig));

%D1EditBox: edit uicontrol for D1 user input
ud.Handle.D1EditBox = uicontrol('Parent',ud.Handle.NaDPanel,...
    'Tag','D1EditBox',...
    'Units','normalized',...
    'Position',[0.555 0.1 0.125 0.8],...
    'Style','edit',...
    'String',char(sym(ud.D1)),...
    'HorizontalAlignment','right',...
    'FontSize', 12,...
    'BackgroundColor',[1 1 1],...
    'Interruptible','off',...
    'Callback',@(~,~) actionGetValuesAndPlot(fig));

%DLabel: text uicontrol '< x <'
ud.Handle.DLabel = uicontrol('Parent',ud.Handle.NaDPanel,...
    'Tag','DLabel',...
    'Units','normalized',...
    'Position',[0.68 0.2 0.095 0.6],...
    'Style','text',...
    'String',['< ' varAsChar ' <'],...
    'HorizontalAlignment','center',...
    'FontSize', 12);

%D2EditBox: edit uicontrol for a D2 user input
ud.Handle.D2EditBox = uicontrol('Parent',ud.Handle.NaDPanel,...
    'Tag','D2EditBox',...
    'Units','normalized',...
    'Position',[0.775 0.1 0.125 0.8],...
    'Style','edit',...
    'String',char(sym(ud.D2)),...
    'HorizontalAlignment','left',...
    'FontSize', 12,...
    'BackgroundColor',[1 1 1],...
    'Interruptible','off',...
    'Callback',@(~,~) actionGetValuesAndPlot(fig));

%buttonPanel: uipanel to hold all the Help, Reset, and Close buttons
ud.Handle.buttonPanel = uipanel('Parent',fig,...
    'Tag','buttonPanel',...
    'Units','normalized',...
    'Position',[0 0 1 0.1],...
    'BorderType','none');

%resetButton: pushbutton uicontrol for Help
ud.Handle.helpButton = uicontrol('Parent',ud.Handle.buttonPanel,...
    'Tag','helpButton',...
    'Units','normalized',...
    'Position',[0.4 0.2 0.15 0.6],...
    'Style','pushbutton',...
    'String',getString(message('symbolic:taylortool:Help')),...
    'Callback',@(~,~) doc('taylortool'));

%resetButton: pushbutton uicontrol for Reset
ud.Handle.resetButton = uicontrol('Parent',ud.Handle.buttonPanel,...
    'Tag','resetButton',...
    'Units','normalized',...
    'Position',[0.575 0.2 0.15 0.6],...
    'Style','pushbutton',...
    'String',getString(message('symbolic:taylortool:Reset')),...
    'Callback',@(~,~) actionReset(fig));

%closeButton: pushbutton uicontrol for Close
ud.Handle.closeButton = uicontrol('Parent',ud.Handle.buttonPanel,...
    'Tag','closeButton',...
    'Units','normalized',...
    'Position',[0.75 0.2 0.15 0.6],...
    'Style','pushbutton',...
    'String',getString(message('symbolic:taylortool:Close')),...
    'Callback',@(~,~) close(fig));

% Set the figure user data
set(fig,'UserData',ud);

%----------------------------------%
function S = slen(S)
% slen: Reduces the length of a Taylor series by removing
%   terms until the string is less than 60 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

% Determine where S has + or -.
tmp = cumsum((S == '(') - (S == ')'));
B = (S == '+' | S == '-') & (tmp == 0);

B1 = find(B == 1);
S1 = S;
for j = 1:length(B1)-1
    if length(S) < 60
        return;
    else
        S = [S(1:B1(end-j)) '...' S1(B1(end):end)];
    end
end

%----------------------------------%
function taylorplot(fig)
% taylorplot: 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 = [D1,D2], 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
%
% Note that f, N, a, D1, and D2 are stored as fields of get(fig,'UserData')

ud = get(fig,'UserData');
h1 = ezplot(ud.Handle.plotAxes,char(ud.f),[ud.D1,ud.D2]);
set(h1,'Color','b'); % blue
hold(ud.Handle.plotAxes,'on');
ylim = get(ud.Handle.plotAxes,'YLim');
ydiff = diff(ylim);
h2 = ezplot(ud.Handle.plotAxes,char(ud.t),[ud.D1,ud.D2]);
set(h2,'Color','r','LineStyle','--','Linewidth',2); %red dotted
newylim = [ylim(1)-ydiff/2,ylim(2)+ydiff/2]; %show twice as much viewing area as the default
set(ud.Handle.plotAxes,'YLim',newylim);
title(ud.Handle.plotAxes,getString(message('symbolic:taylortool:PlotTitle')));
xlabel(ud.Handle.plotAxes,'');
hold(ud.Handle.plotAxes,'off');

%Put tag back (for some strange reason, the Tag gets cleared after plotting)
set(ud.Handle.plotAxes,'Tag','plotAxes');

drawnow;

%----------------------------------%
function ud = getUserDataAndSetLoadingFlag(fig)
%getUserDataAndSetLoadingFlag: Get figure UserData ud and sets ud.isReady=true
ud = get(fig,'UserData');
ud.isReady = false;
set(fig,'UserData',ud);

%----------------------------------%
function clearLoadingFlag(fig)
%clearLoadingFlag: Sets ud.isReady=false in the figure UserData
ud = get(fig,'UserData');
ud.isReady = true;
set(fig,'UserData',ud);

%----------------------------------%
function actionGetValuesAndPlot(fig)
%actionGetValuesAndPlot: Callback for all edit boxes

ud = getUserDataAndSetLoadingFlag(fig);

%Get and check user input
fstr = get(ud.Handle.fEditBox,'String');
Nstr = get(ud.Handle.NEditBox,'String');
astr = get(ud.Handle.aEditBox,'String');
D1str = get(ud.Handle.D1EditBox,'String');
D2str = get(ud.Handle.D2EditBox,'String');
[errMsg,ud.f,ud.N,ud.a,ud.D1,ud.D2] = checkAndConvert(fstr,Nstr,astr,D1str,D2str);

var = symvar(ud.f);
varAsChar = char(var);
if isempty(var)
    varAsChar = 'x';
end

%Get Taylor series result
if isempty(errMsg)
    ud.t = getTaylorResult(ud.f,ud.N,ud.a);
    if isempty(ud.t)
        errMsg = message('symbolic:taylortool:NoExpansion',char(ud.f),num2str(ud.a));
    end
end

%Update plot or error
if isempty(errMsg)
    set(ud.Handle.fTextLabel,'String',['f(' varAsChar ') = ']);
    set(ud.Handle.DLabel,'String',['< ' varAsChar ' <']);
    set(ud.Handle.seriesText,'String',['T_N(' varAsChar ') = ' texlabel(slen(char(ud.t)),70)]);
    set(fig,'UserData',ud);
    taylorplot(fig);
else
    errordlg(getString(errMsg));
    set(ud.Handle.seriesText,'String',getString(errMsg));
    drawnow;
end

clearLoadingFlag(fig);

%----------------------------------%
function actionReset(fig)
%actionReset: callback for resetButton

ud = getUserDataAndSetLoadingFlag(fig);

%Reset to defaults (except for f)
set(ud.Handle.NEditBox,'String','7');
set(ud.Handle.aEditBox,'String','0');
set(ud.Handle.D1EditBox,'String','-2*pi');
set(ud.Handle.D2EditBox,'String','2*pi');
drawnow;

%Plot again
actionGetValuesAndPlot(fig);

%----------------------------------%
function actionIncrement(fig,upOrDown)
%actionIncrement: Callback for NupButton and NdownButton

ud = getUserDataAndSetLoadingFlag(fig);

%Increase or decrease N
switch upOrDown
    case 'up'
        ud.N = ud.N + 1;
    case 'down'
        ud.N = ud.N - 1;
end
set(ud.Handle.NEditBox,'String',int2str(ud.N));
drawnow;

%Plot again
actionGetValuesAndPlot(fig);