gusucode.com > bigdata 工具箱 matlab源码程序 > bigdata/+matlab/+bigdata/+internal/+optimizer/ClosureGraph.m

    %ClosureGraph An execution graph leading up to a series of partitioned arrays.
%   The primary purpose of this class is to compute a digraph of
%   closure/promise/future nodes and the connectivity between them. This
%   information can then be used by optimizers to discover optimization
%   opportunities.

% Copyright 2016 The MathWorks, Inc.

classdef ClosureGraph < handle

    properties (SetAccess = private)
        % digraph linking Nodes with Edges. digraphs are value classes, so OK to make
        % this property 'GetAccess = public'.
        Graph
    end
    
    properties (GetAccess = private, SetAccess = immutable)
        % Starting points for this graph - an array of futures.
        Futures
    end

    methods
        function recalculate(obj)
        %Recalculate - recompute the graph from scratch.
            
            nodesMap = containers.Map('KeyType', 'char', ...
                                      'ValueType', 'any');
            % Calculate all the nodes and edges from the starting point
            edges = iCalcNodesAndEdges(nodesMap, obj.Futures);
            obj.Graph = iCalcGraphFromNodesAndEdges(nodesMap, edges);
        end
        
        function obj = ClosureGraph(varargin)
        %Build a ClosureGraph from a series of partitioned arrays.

            assert(all(cellfun(@(x) isa(x, 'matlab.bigdata.internal.lazyeval.LazyPartitionedArray'), ...
                               varargin)));
            % Get the value futures for all arrays
            futureCell = cell(1, nargin);
            for idx = 1:nargin
                futureCell{idx} = varargin{idx}.ValueFuture;
            end
            obj.Futures = vertcat(futureCell{:});
            recalculate(obj);
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Convert the two maps previously constructed into a digraph.
function G = iCalcGraphFromNodesAndEdges(nodesMap, edgesArray)

    % build up the table of nodes. We need the name of each node, plus we're going
    % to add a couple of extra variables - 'IsClosure' to indicate whether a
    % node is a closure, and 'OpType' - the trailing part of the Operation class
    % name (for closures only)
    nodeNames   = keys(nodesMap);
    nodeNames   = nodeNames(:);
    numNodes    = numel(nodeNames);
    nodeObjCell = values(nodesMap);
    nodeObjCell = nodeObjCell(:);
    isClosureV  = cellfun(@isClosure, nodeObjCell);

    closureType = repmat({''}, numNodes, 1);
    closureType(isClosureV) = cellfun(@(x) class(x.Operation), ...
                                      nodeObjCell(isClosureV), ...
                                      'UniformOutput', false);
    closureType = regexprep(closureType, '.*\.', '');

    nodeTable = table(nodeNames, nodeObjCell, isClosureV, categorical(closureType), ...
                      'VariableNames', {'Name', 'NodeObj', 'IsClosure', 'OpType'});

    edgeTable = table(edgesArray, 'VariableNames', {'EndNodes'});
    G = digraph(edgeTable, nodeTable);
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Given a starting list of 'nodes', walk the closure graph computing a map of
% node names to node object, and a map of edges (map source node name to list of
% destination node names). The edges are returned as an Mx2 cell array of node
% names.
function edges = iCalcNodesAndEdges(nodesMap, nodes)
    
    % We'll build up a cell array where the first column is the source node, second
    % column the destination node.
    edges       = cell(0, 2);
    nextEdgeIdx = 1;
    
    % Create the stack from all existing nodes
    stack    = num2cell(nodes);
    stackPos = numel(stack);
    
    while stackPos > 0
        % Get the next node, and bail if we've already seen it.
        
        % Pop node from stack
        node = stack{stackPos};
        stack{stackPos} = [];
        stackPos = -1 + stackPos;
        
        nodeId = node.IdStr;
        if isKey(nodesMap, nodeId)
            continue
        end
        
        % Haven't seen this node before, add it to the nodesMap, and then get the list
        % of 'supplier' (i.e. upstream) nodes.
        nodesMap(nodeId) = node;
        predecessors     = node.Predecessors;

        for idx = 1:numel(predecessors)
            % Push predecessor onto the stack for consideration.
            p = predecessors(idx);
            stack{stackPos + 1} = p;
            stackPos = 1 + stackPos;

            % Append edges
            supplierNodeId        = p.IdStr;
            edges(nextEdgeIdx, :) = {supplierNodeId, nodeId};
            nextEdgeIdx           = 1 + nextEdgeIdx;
        end
    end
    edges = edges(1:(nextEdgeIdx-1),:);
end