gusucode.com > symbolic工具箱matlab源码程序 > symbolic/@sym/subs.m

    function G = subs(F,X,Y,swap) %#ok<INUSD>
%SUBS   Symbolic substitution.  Also used to evaluate expressions numerically.
%   SUBS(S,OLD,NEW) replaces OLD with NEW in the symbolic expression S.
%   OLD is a symbolic variable, a string representing a variable name, or
%   a symbolic expression. NEW is a symbolic or numeric variable
%   or expression.  That is, SUBS(S,OLD,NEW) evaluates S at OLD = NEW.
%
%   SUBS(S,VALUES), where VALUES is a STRUCT, replaces the symbolic
%   variables in S which are field names in VALUES by the corresponding
%   entries of the struct.
%
%   SUBS(S) replaces all the variables in the symbolic expression S with
%   values obtained from the calling function, or the MATLAB workspace.
%
%   SUBS(S,NEW) replaces the free symbolic variable in S with NEW.
%
%   If OLD and NEW are vectors or cell arrays of the same size, each element
%   of OLD is replaced by the corresponding element of NEW.  If S and OLD
%   are scalars and NEW is a vector or cell array, the scalars are expanded
%   to produce an array result.  If NEW is a cell array of numeric matrices,
%   the substitutions are performed elementwise.
%
%   Examples:
%     Single input:
%       Suppose
%          y = exp(-a*t)*C1
%       After that, set a = 980 and C1 = 3 in the workspace.
%       Then the statement
%          subs(y)
%       produces
%          ans = 3*exp(-980*t)
%
%     Single Substitution:
%       subs(a+b,a,4) returns 4+b.
%       subs(a*b^2, a*b, 5) returns 5*b.
%
%     Multiple Substitutions:
%       subs(cos(a)+sin(b),{a,b},[sym('alpha'),2]) or
%       subs(cos(a)+sin(b),{a,b},{sym('alpha'),2}) returns
%       cos(alpha)+sin(2)
%
%     Scalar Expansion Case:
%       subs(exp(a*t),'a',-magic(2)) returns
%
%       [   exp(-t), exp(-3*t)]
%       [ exp(-4*t), exp(-2*t)]
%
%     Multiple Scalar Expansion:
%       subs(x*y,{x,y},{[0 1;-1 0],[1 -1;-2 1]}) returns
%         0  -1
%         2   0
%
%   See also SYM/SUBEXPR, SYM/VPA, SYM/DOUBLE.

%   Copyright 1993-2015 The MathWorks, Inc.

if ~isa(F,'sym'), F = sym(F); end
if builtin('numel',F) ~= 1,  F = normalizesym(F);  end

if nargin == 4
    warning(message('symbolic:subs:swapDeprecated'));
end

if nargin == 1
    % initialize X and Y from workspace variables

    % Determine which variables are in the MATLAB workspace and
    % place them in the cell X.  Similarly, place the values of
    % variables in the MATLAB workspace into the cell Y.
    vars = arrayfun(@char, symvar(F), 'UniformOutput', false);
    nvars = length(vars);
    eflag = zeros(1,nvars);
    for k = 1:nvars
        str = sprintf('exist(''%s'',''var'')',vars{k});
        eflag(k) = evalin('caller',str);
        if ~eflag(k)
            eflag(k) = 2*evalin('base',str);
        end
    end
    einds = find(eflag);
    X = vars(einds);
    Y = cell(1,length(einds));
    for k = 1:length(einds)
        if eflag(einds(k)) == 1
            Y{k} = evalin('caller',vars{einds(k)});
        else
            Y{k} = evalin('base',vars{einds(k)});
        end
    end
elseif nargin == 2
    if isstruct(X)
        Y = struct2cell(X);
        X = fieldnames(X);
        % look for symfuns hiding behind those names.
        % Can't use a helper function, since we need to check the caller's workspace.
        for k=1:size(X,1)
            str = sprintf('exist(''%s'',''var'')',X{k});
            if evalin('caller',str)
                fn = evalin('caller', X{k});
                fname = isAbstractFun(fn);
                if ~isequal(fname, false) && isequal(char(fname), X{k})
                    X{k} = fn;
                end
            elseif evalin('base',str)
                fn = evalin('base', X{k});
                fname = isAbstractFun(fn);
                if ~isequal(fname, false) && isequal(char(fname), X{k})
                    X{k} = fn;
                end
            end
        end
    else
        % got Y and use free variable as X
        Y = X;
        X = symvar(F,1);
        if isempty(X), X = sym('x'); end
    end
end

if isempty(X)
    G = F;
elseif isempty(Y)
    G = formula(sym(Y));
else
    G = mupadsubs(F,X,Y);
end
if isa(F,'symfun')
    G = symfun(G,argnames(F));
end

%--------------------------------------------------------------------
function G = mupadsubs(F,X,Y)
% Check for appropriate forms of input.
error(inputchk(X,Y));

% convert X and Y to syms and wrap in cell array if needed
[X2,Y2,symX,symY] = normalize(X,Y); %#ok

% send all data to MuPAD for subs
G = mupadmex('symobj::fullsubs',F.s,X2,Y2);

%--------------------------------------------------------------------
% convert input X to cell array of sym objects
function [X2,Y2,X,Y] = normalize(X,Y)
if iscell(X)
    X = cellfun(@(x)sym(x),X,'UniformOutput',false);
elseif ischar(X) || isnumeric(X)
    X = {sym(X)};
elseif isa(X, 'symfun') % array-valued symfun? expand, for subs(f(1)+g(1), [f g], {@sin @cos})
    X = arrayfun(@(x) symfun(x,argnames(X)),formula(X),'UniformOutput',false);
elseif isa(X,'sym') % expand arrays here, too
    X = arrayfun(@(x) x,X,'UniformOutput',false);
else
    error(message('symbolic:subs:InvalidXClass'));
end

% if X contains symfuns, check for "abstract symfuns"
abstract_X = cellfun(@isAbstractFun, X, 'UniformOutput', false);
is_abstract = cellfun(@(x) isa(x, 'sym'), abstract_X);
is_abstract = reshape(is_abstract, 1, numel(is_abstract));
if any(is_abstract)
    % make sure Y is cell array of appropriate size, too
    if iscell(Y)
        % nothing
    elseif ischar(Y) || isnumeric(Y)
        Y = {sym(Y)};
    end
    if isa(Y, 'symfun') % array-valued symfun? expand, for subs(f(1)+g(2), [f g], [g f])
        Y = arrayfun(@(x) symfun(x,argnames(Y)),formula(Y),'UniformOutput',false);
    elseif isa(Y,'sym')
        if numel(is_abstract) == 1
            Y = arrayfun(@(x) x, fun2sym(Y,argnames(X{1})),'UniformOutput',false);
        else
            Y = arrayfun(@(x) x, Y,'UniformOutput',false);
        end
    elseif isa(Y,'function_handle')
        Y = {Y};
    end
    if ~iscell(Y)
        error(message('symbolic:subs:InvalidXClass'));
    end
    for i=find(is_abstract)
        Y{i} = fun2sym(Y{i},argnames(X{i}));
        X{i} = abstract_X{i};
    end
end

if iscell(Y)
    Y = cellfun(@(x)sym(x),Y,'UniformOutput',false);
elseif ischar(Y) || isnumeric(Y)
    Y = {sym(Y)};
elseif isa(Y, 'symfun') % array-valued symfun? expand, for subs(f(1)+g(1), [f g], [g f])
    Y = arrayfun(@(x) symfun(x,argnames(Y)),formula(Y),'UniformOutput',false);
elseif isa(Y,'sym')
    Y = {Y};
else
    error(message('symbolic:subs:InvalidXClass'));
end

% check number of variables and number of subs targets
if ~isequal(size(X), size(Y)) && numel(Y) == 1
  % expand sym array and check again
  Y = arrayfun(@(x) x,Y{1},'UniformOutput',false);
end
if ~isequal(size(X), size(Y)) && numel(X) ~= 1
  error(message('symbolic:subs:InconsistentLengths'));
end

% we can only vectorize over NEW
if ~all(cellfun(@isscalar, X))
  error(message('symbolic:subs:NonScalarOLD'));
end

% we need to keep X alive so that the reference is not collected
X2 = tolist(X);
Y2 = tolist(Y);

%--------------------------------------------------------------------
function msg = inputchk(x,y)
%INPUTCHK Generate error message for invalid cases

msg = '';
if isa(x,'sym') && length(x)==1
  if ischar(y) && size(y,1)~=1
    msg = message('symbolic:subs:errmsg1');
    return;
  end
elseif ischar(x) && ischar(y) && ...
      (length(sym(x))~=1 || length(sym(y))~=1) && isvarname(char(x))
    msg = message('symbolic:subs:errmsg1');
    return;
elseif (ischar(x) || isa(x,'sym')) && isvarname(char(x))
  if ischar(y) && size(y,1)~=1
    msg = message('symbolic:subs:errmsg1');
    return;
  end
end

%--------------------------------------------------------------------
% convert A to a MuPAD list
function s = tolist(A)
s = cellfun(@(x)[x.s ','],A,'UniformOutput',false);
s = [s{:}];
s = ['[' s(1:end-1) ']'];

%--------------------------------------------------------------------
function funcname = isAbstractFun(ex)
% check for abstract symfun
if ~isa(ex, 'symfun')
    funcname = false;
    return;
end
funcname = mupadmex('symobj::isAbstractFun', ex.s, char(argnames(ex)));
if strcmp(char(funcname), 'FAIL')
    funcname = false;
end

%--------------------------------------------------------------------
function f = fun2sym(ex, args)
% convert rhs for abstract symfun
if isa(ex, 'function_handle')
    % if this errors, just let the user know
    argscell = num2cell(args);
    ex = ex(argscell{:});
end
ex = sym(ex);
if isa(ex, 'symfun')
    f = mupadmex('fp::unapply',ex.s,char(argnames(ex)));
elseif logical(mupadmex('(t->testtype(eval(t), Type::Function))',ex.s))
    f = ex;
else
    argscell = num2cell(args);
    argsrefcell = cellfun(@(x) x.s, argscell, 'UniformOutput', false);
    f = mupadmex('fp::unapply', ex.s, argsrefcell{:});
end