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))));