www.gusucode.com > mbcexpr 工具箱 matlab 源码程序 > mbcexpr/@cgexprgroup/copyToStatic.m

    function [obj, idxInp] = copyToStatic(obj, expr, varargin)
%COPYTOSTATIC Copy a static version of an expression chain
%
%  [OBJ, INPIDX] = COPYTOSTATIC(OBJ, EXPR) where EXPR may be an expression,
%  cell array of expressions or a vector of pointers to expressions
%  constructs a static expression chain with an output for each specified
%  expression and inputs taken as being the variable dictionary items.
%  INPIDX is a vector of indices within the static copy of the chain that
%  the input values will be inserted at.  This vector is the value that is
%  returned from the method GETINPUTINDICES.
%
%  [...] = COPYTOSTATIC(OBJ, EXPR, OPTION1, VALUE1, ...) allows the
%  specification of additional options that control the static conversion.
%  These are the available options and their values:
%
%    OPTION     |  VALUE
%  ============================================================
%  'Inputs'     |  Pointer vector that specifies input points in the
%               |  expression chains.  These input points need not be
%               |  source expressions and they also do not need to actually
%               |  be part of the expression chains; input points that do
%               |  not exist in the expression chains will have input
%               |  indices of 0 and their data will be ignored at
%               |  evaluation time.  When using this form of the method,
%               |  the static copy will have its inputs sorted to be in the
%               |  same order as VALUE specifies.
%               |
%  'ConstInputs'|  Boolean flag that specifies whether all variable
%               |  dictionary items should be taken as inputs (VALUE =
%               |  true) or whether only inports (variable and formulae)
%               |  should be taken as inputs (VALUE = false).  The default
%               |  setting is true.  This option is ignored if the 'Inputs'
%               |  option has also been specified.
%               |
%  'OutputFcns' |  Cell array of function names or function handles, one
%               |  for each output expression.  This defines the quantity
%               |  that should be calculated for each output.  The function
%               |  must have a signature of the form func(obj, {inputs})
%               |  and the correct set of required inputs for it must be
%               |  returned by a call to getEvalDependencies on the same
%               |  object.  If this option is omitted, the function
%               |  'evalAtInputs' will be used for each output.

%  Copyright 2000-2008 The MathWorks, Inc. and Ford Global Technologies, Inc.


findfcn = @(expr, func) isinport(expr);
NumInputsDefined = 0;
outfcn = {};

% Parse options
for n = 1:2:length(varargin)
    switch lower(varargin{n})
        case 'inputs'
            findfcn = @(expr, func) isInInputList(varargin{n+1}, expr, func);
            NumInputsDefined = length(varargin{n+1});
        case 'constinputs'
            if (varargin{n+1}) && NumInputsDefined==0
                findfcn = @(expr, func) isddvariable(expr);
            end
        case 'outputfcns'
            outfcn = varargin{n+1};
            for i = 1:length(outfcn)
                if ischar(outfcn{i})
                    outfcn{i} = str2func(outfcn{i});
                end
            end
    end
end

if isa(expr, 'cgexpr')
    pTop = address(expr);
    expr = {expr};
elseif iscell(expr)
    pTop = mbccellarrayeval(expr, @address, [], mbcpointer);
else
    % Pointers to inputs
    pTop = expr;
    expr = infoarray(pTop);
end

% Initialise the defaults for the output functions if required
if isempty(outfcn)
    outfcn = repmat({@evalAtInputs}, size(expr));
end

% Get chain information
[exprList, fcnList, inputList, idxInp, idxOut] = i_getchaininfo(pTop, expr, outfcn, findfcn, NumInputsDefined);

% Initialise the adjacency matrix
numExpr = length(exprList);
Adj = false(numExpr,numExpr);
for n = 1:length(Adj)
    Adj(n,inputList{n}) = true;
end

% Sort the adjacency matrix so that dependencies are always evaluated
% before they are needed.
reOrder = 1:numExpr;
loop = false;
for i=1:numExpr
    if any(Adj(i,:))
        % find any inputs in expressions (i+1):numExpr
        p = find(Adj(i,i+1:numExpr));

        swap = ~isempty(p);
        loop = Adj(i,i);
        OrigIndex = reOrder(i);
        while swap && ~loop
            p = p+i;
            reOrder([i p]) = reOrder([p i]);

            % swap elements in adjaceny matrix
            Adj( [i p], :) = Adj([p i], :);
            Adj( :, [i p]) = Adj(:, [p i]);

            % find next swap
            p = find(Adj(i,i+1:numExpr));
            swap = ~isempty(p);

            % Halt loop if link to self or the original node is back at start
            loop= Adj(i,i) || reOrder(i)== OrigIndex;
        end

        if loop
            % Loop detected so stop now
            break
        end
    end
end
if loop
    error(message('mbc:cgexprgroup:InvalidState'));
end

% Apply reordering to other data
inputList = inputList(reOrder);
exprList = exprList(reOrder);
fcnList = fcnList(reOrder);

[~, targetIdx] = sort(reOrder);
idxInp(idxInp>0) = targetIdx(idxInp(idxInp>0));
idxOut = targetIdx(idxOut);

for i = find(idxInp)
    E = exprList{idxInp(i)};
    if isa(E,'cgvalue') && ~isa(E,'cgconstant')
        % set value fields for inputs to their nominal value
        E = setvalue( E , getnomvalue( E ) );
        exprList{idxInp(i)} = E;
    end
end

% Last 2 actions:
%  (1) Point input indices at reordered locations
%  (2) Look for last usage index to aid memory-saving efforts during evaluation
idxMax = (numExpr+1)*ones(1, numExpr);
for n = 1:numExpr
    inputList{n} = targetIdx(inputList{n});
    idxMax(inputList{n}) = n;
end

obj.ExprArray = exprList;
obj.InputIndices = inputList;
obj.Inports = idxInp;
obj.Outports = idxOut;
obj.OutportRequiredIndices = pGetEvaluationIndices(inputList, idxOut);
obj.MaxIndices = idxMax;
obj.EvaluationFunctions = fcnList;



% Function that looks at all of the input chains and returns a unique list
% of the items plus the inputs it requires.
function [Expr, Fcns, Inputs, InputIdx, OutputIdx] = i_getchaininfo( ...
                                    pTop, TopExpr, TopFcns, InputFindFcn, NumInputsDefined)

% Initialise list to contain the unique set of the output expressions, and
% save the indices that map the requested outputs to this unique set.
pList = pTop;
Fcns = TopFcns;
OutputIdx = 1:length(pTop);
IsUnique = true(size(OutputIdx));
hashList = zeros(size(pList));
for n = 1:length(hashList)
    hashList(n) = hash(pList(n), func2str(Fcns{n}));
    
    % Ignore non-unique matches that correspond to null-pointer expression
    % addresses
    if hashList(n)>1 
        DupIdx = find(hashList(n)==hashList(1:n-1),1);
        if ~isempty(DupIdx)
            OutputIdx(n) = OutputIdx(DupIdx);
            OutputIdx(n+1:end) = OutputIdx(n+1:end)-1;
            IsUnique(n) = false;
        end
    end
end
hashList = hashList(IsUnique);
pList = pList(IsUnique);
Fcns = Fcns(IsUnique);
Expr = TopExpr(IsUnique);
Inputs = cell(size(Expr));
nOut = length(pList);

InputIdx = zeros(1, NumInputsDefined);


% Grouped Backwards version
% Step through the expressions, getting the input information and adding
% them to the list of all expressions.  The loop stops when no new inputs
% are found in any of the expressions.
ExprMissingIndex = 0;
for k = 0:(nOut-1)
    eIndex = length(Expr)-k;
    NextStartJumpIndex = 0;
    while eIndex>0
        if eIndex<=ExprMissingIndex
            % Get as many new expressions as possible
            Expr(1:eIndex) = infoarray(pList(1:eIndex));
            ExprMissingIndex = 0;
        end

        IsInp = InputFindFcn(Expr{eIndex}, func2str(Fcns{eIndex}));
        if IsInp
            if NumInputsDefined>0
                % Place result at location specified
                InputIdx(IsInp) = eIndex;
            else
                InputIdx = [eIndex InputIdx]; %#ok<*AGROW>
            end
        else
            % Get input requirements for this expression
            [newInp, newFuncs] = getEvalDependencies(Expr{eIndex}, Fcns{eIndex});

            % Hash the new information
            newHash = zeros(size(newInp));
            for n = 1:length(newHash)
                newHash(n) = hash(newInp(n), func2str(newFuncs{n}));
            end
            
            % Remove duplicates in the new information
            [newHash, newHashIdx, newHashIdx2] = unique(newHash);
            newInp = newInp(newHashIdx);
            newFuncs = newFuncs(newHashIdx);

            % Add newly-found inputs to the main list
            [toAdd, existIdx] = ismember(newHash, hashList);
            toAdd = ~toAdd;
            numNew = sum(toAdd);
            pList = [newInp(toAdd), pList];
            Fcns = [newFuncs(toAdd), Fcns];
            Expr = [cell(1, numNew), Expr];
            hashList = [newHash(toAdd), hashList];

            % Adjust input indices already found
            if numNew>0
                if (eIndex>(length(Inputs)-nOut))
                    % Do all Inputs - there may be some we have discovered
                    % that are below us
                    for n = 1:length(Inputs)
                        Inputs{n} = Inputs{n}+numNew;
                    end
                else
                    % Do Inputs above us
                    for n = (eIndex+1):length(Inputs)
                        Inputs{n} = Inputs{n}+numNew;
                    end
                end
            end
            existIdx = existIdx+numNew;
            existIdx(toAdd) = 1:numNew;            
            Inputs{eIndex} = existIdx(newHashIdx2);
            Inputs = [cell(1, numNew), Inputs];
            InputIdx(InputIdx>0) = InputIdx(InputIdx>0)+numNew;

            % Adjust current index to the moved location
            eIndex = eIndex+numNew;
            NextStartJumpIndex = NextStartJumpIndex+numNew;
            ExprMissingIndex = ExprMissingIndex+numNew;
        end

        Expr{eIndex} = convertToStatic(Expr{eIndex},Fcns{eIndex});
        
        if (eIndex>(length(Expr)-nOut))
            eIndex = NextStartJumpIndex;
        else
            eIndex = eIndex-1;
        end
    end
end

% Offset the output indices by the number of chain expressions that have
% been added
OutputIdx = OutputIdx + (length(pList)-nOut);




% Check whether a pointer is one of the defined input points
function ret = isInInputList(pInp, Expr, Func)
if strcmpi(Func, 'evalatinputs')
    [~, ret] = ismember(address(Expr), pInp);
else
    % Inputs can only be fed standard evaluation data
    ret = false;
end


% Produce a unique hash number from a scalar xregpointer and a (short) string
function h = hash(ptr, str)
h = double(ptr) + 1./sum((str.*2.^(1:length(str))));