www.gusucode.com > mbcview 工具箱matlab源码程序 > mbcview/+cageview/+optimoutput/ObjGraphViewData.m

    classdef ObjGraphViewData < mbcgui.widget.ScrollTableData
    %cageview.optimoutput.ObjGraphViewData class
    %   cageview.optimoutput.ObjGraphViewData extends mbcgui.widget.ScrollTableData.
    %
    %    cageview.optimoutput.ObjGraphViewData properties:
    %       MessageService - Property is of type 'handle'
    %       DisplayConstraints - Property is of type 'bool'
    %       hTable - Property is of type 'handle'
    %       CacheIsFilled - Property is of type 'bool'
    %       CellIsCalculated - Property is of type 'MATLAB array'
    %       ConIsCalculated - Property is of type 'MATLAB array'
    %       LimitsX - Property is of type 'MATLAB array'
    %       LimitsY - Property is of type 'MATLAB array'
    %       LabelsX - Property is of type 'MATLAB array'
    %       LabelsY - Property is of type 'MATLAB array'
    %       LocationX - Property is of type 'MATLAB array'
    %       LocationY - Property is of type 'MATLAB array'
    %       SweepX - Property is of type 'MATLAB array'
    %       SweepY - Property is of type 'MATLAB array'
    %       NumConstraints - Property is of type 'int'
    %       SweepConEdges - Property is of type 'MATLAB array'
    %       CellHasSweep - Property is of type 'MATLAB array'
    %
    %    cageview.optimoutput.ObjGraphViewData methods:
    %       fillDataCache - Evalaute data for all cells.
    %       getCellData - Get a structure of data for display in a table cell.
    %       getColumnCount - Return the number of columns in the data model.
    %       getRowCount - Return the number of rows in the data model.
    %       getStandardColumnHeaderData - Get the standard column header data structure.
    %       getStandardRowHeaderData - Get the standard row header data structure.
    %       reset - Clear cache and recalculate the one-time data.
    %       updateYLimits - Update y limits of graphs.
    
    %  Copyright 2005-2015 The MathWorks, Inc.
    
    properties (AbortSet, SetObservable)
        %MESSAGESERVICE Property is of type 'handle'
        MessageService = [];
        %DISPLAYCONSTRAINTS Property is of type 'bool'
        DisplayConstraints = true;
        %HTABLE Property is of type 'handle'
        hTable = [];
        %CACHEISFILLED Property is of type 'bool'
        CacheIsFilled
        %CELLISCALCULATED Property is of type 'MATLAB array'
        CellIsCalculated = [];
        %CONISCALCULATED Property is of type 'MATLAB array'
        ConIsCalculated = [];
        %LIMITSX Property is of type 'MATLAB array'
        LimitsX = [];
        %LIMITSY Property is of type 'MATLAB array'
        LimitsY = [];
        %LABELSX Property is of type 'MATLAB array'
        LabelsX = [];
        %LABELSY Property is of type 'MATLAB array'
        LabelsY = [];
        %LOCATIONX Property is of type 'MATLAB array'
        LocationX = [];
        %LOCATIONY Property is of type 'MATLAB array'
        LocationY = [];
        %SWEEPX Property is of type 'MATLAB array'
        SweepX = [];
        %SWEEPY Property is of type 'MATLAB array'
        SweepY = [];
        %NUMCONSTRAINTS Property is of type 'int'
        NumConstraints
        %SWEEPCONEDGES Property is of type 'MATLAB array'
        SweepConEdges = [];
        %CELLHASSWEEP Property is of type 'MATLAB array'
        CellHasSweep = [];
    end
    
    events
        YLimUpdated
    end  % events
    
    methods  % public methods
        %----------------------------------------
        function fillDataCache(obj)
        %FILLDATACACHE Evalaute data for all cells.
        %   FILLDATACACHE(OBJ) fills up the data cache for all cells that have not
        %   yet been evaluated.
        
        if ~obj.CacheIsFilled
            DataExists = all(obj.CellIsCalculated, 1);
            SweepIdx = find(~DataExists);
            obj.pUpdateEvalCache(SweepIdx); %#ok<FNDSB>
            
            SweepIdx = find(~obj.ConIsCalculated);
            obj.pUpdateConCache(SweepIdx); %#ok<FNDSB>
            
            obj.CacheIsFilled = true;
        end
        
        end  % fillDataCache
        
        %----------------------------------------
        function data = getCellData(obj, R, C)
        %GETCELLDATA Get a structure of data for display in a table cell.
        %   DATA = GETCELLDATA(OBJ, R, C) returns a data structure that contains
        %   all of the information needed to display in the specified table cell.
        
        if ~obj.CellIsCalculated(R, C)
            % Update the cache
            obj.pUpdateEvalCache(obj.pGetEvalChunk(R, C));
            obj.updateYLimits;
        end
        
        if R==obj.getRowCount
            Xlab = obj.LabelsX{C};
        else
            Xlab = '';
        end
        
        if C==1
            Ylab = obj.LabelsY{R};
        else
            Ylab = '';
        end
        
        % Form the main data structure
        data = struct('showdata', obj.CellHasSweep(R, C), ...
            'xlim', obj.LimitsX{C}, ...
            'ylim', obj.LimitsY{R}, ...
            'xdata', obj.SweepX{C}, ...
            'ydata', obj.SweepY{R, C}, ...
            'value', obj.LocationX(C), ...
            'xlabel', Xlab, ...
            'ylabel', Ylab);
        
        % Add constraints data
        if obj.DisplayConstraints
            if ~obj.ConIsCalculated(C)
                % Update the constraint cache
                obj.pUpdateConCache(obj.pGetConChunk(R, C));
            end
            data.constraintedges = obj.SweepConEdges{C};
        else
            data.constraintedges = NaN;
        end
        
        end  % getCellData
        
        %----------------------------------------
        function nC = getColumnCount(obj)
        %GETCOLUMNCOUNT Return the number of columns in the data model.
        %   NC = GETCOLUMNCOUNT(OBJ) returns the number of columns in the data model.
        
        nC = length(obj.LabelsX);
        
        end  % getColumnCount
        
        %----------------------------------------
        function nR = getRowCount(obj)
        %GETROWCOUNT Return the number of rows in the data model.
        %   NR = GETROWCOUNT(OBJ) returns the number of rows in the data model.
        
        nR = length(obj.LabelsY);
        
        end  % getRowCount
        
        %----------------------------------------
        function data = getStandardColumnHeaderData(obj, Cidx)
        %GETSTANDARDCOLUMNHEADERDATA Get the standard column header data structure.
        %   DATA = GETSTANDARDCOLUMNHEADERDATA(OBJ, CIDX) returns a standard data
        %   structure for the specified column header.  The structure must have
        %   fields Limits, Value and Label.
        %
        %   The standard header data is designed for use with header GUI
        %   objects such as the sharedAxisHeader.
        
        data = struct('Limits', obj.LimitsX{Cidx}, ...
            'Value', obj.LocationX(Cidx), ...
            'Label', obj.LabelsX{Cidx});
        
        end  % getStandardColumnHeaderData
        
        %----------------------------------------
        function data = getStandardRowHeaderData(obj, Ridx)
        %GETSTANDARDROWHEADERDATA Get the standard row header data structure.
        %   DATA = GETSTANDARDROWHEADERDATA(OBJ, RIDX) returns a standard data
        %   structure for the specified row header.  The structure must have fields
        %   Limits, Value and Label.
        %
        %   The standard header data is designed for use with header GUI
        %   objects such as the sharedAxisHeader.
        
        data = struct('Limits', obj.LimitsY{Ridx}, ...
            'Value', obj.LocationY(Ridx), ...
            'Label', obj.LabelsY{Ridx});
        
        end  % getStandardRowHeaderData
        
        %----------------------------------------
        function reset(obj)
        %RESET Clear cache and recalculate the one-time data.
        %   RESET(OBJ) clears all data that has been cached and recalculates the
        %   data that is created in a single pass.
        
        if isempty(obj.MessageService) ...
                || ~ obj.MessageService.hasData ...
                || strcmp(obj.MessageService.CurrentSliceDirection, 'weightedsolution') ...
                || ~obj.MessageService.hasFocusIndex
            
            % Set data cache to be empty
            set(obj, ...
                'CacheIsFilled', true, ...
                'CellIsCalculated', false(0,0), ...
                'ConIsCalculated', false(0,0), ...
                'LimitsX', {}, ...
                'LimitsY', {}, ...
                'LabelsX', {}, ...
                'LabelsY', {}, ...
                'LocationX', [], ...
                'LocationY', [], ...
                'SweepX', {}, ...
                'SweepY', {}, ...
                'NumConstraints', 0, ...
                'SweepConEdges', {}, ...
                'CellHasSweep', false(0,0));
            return
        end
        
        ms = obj.MessageService;
        RunIdx = ms.getFocusRun;
        SolIdx = ms.getFocusSolution;
        
        Out = ms.getOptimOutput;
        or = getOptimRunner(Out);
        
        % Get free variable values
        [XPoint, VarNames] = getSingleSolution(Out, RunIdx, SolIdx, 'OutputFormat', 'matrix', ...
            'OutputContents', {'FreeVars'});
        nFreeVar = length(VarNames);
        
        % Get objectives at exact point
        [YPoint, ObjNames] = getSingleSolution(Out, RunIdx, SolIdx, 'OutputFormat', 'matrix', ...
            'OutputContents', {'Objectives'});
        nObj= length(ObjNames);
        
        % Get Dependency matrix
        DepMatrix = getDependencyMatrix(or, 'Objective', {});
        
        % Get free value ranges
        [LB, UB] = getFreeVariableRanges(or,RunIdx);
        
        % Cache number of constraints
        [~, nCon] = numConstraints(or);
        
        set(obj, ...
            'CacheIsFilled', false, ...
            'CellIsCalculated', false(nObj, nFreeVar), ...
            'ConIsCalculated', false(1, nFreeVar), ...
            'LimitsX', cellfun(@mbcmakelimits, num2cell([LB(:), UB(:)], 2)', 'UniformOutput', false), ...
            'LimitsY', repmat({[0 1]}, 1, nObj), ...
            'LabelsX', VarNames, ...
            'LabelsY', ObjNames, ...
            'LocationX', XPoint, ...
            'LocationY', YPoint, ...
            'SweepX', cell(1, nFreeVar), ...
            'SweepY', cell(nObj, nFreeVar), ...
            'NumConstraints', nCon, ...
            'SweepConEdges', repmat({NaN}, 1, nFreeVar), ...
            'CellHasSweep', DepMatrix);
        
        % Immediately calculate the initial data.  This means we will have some
        % idea of ylimits from the start
        obj.pUpdateEvalCache(obj.pGetEvalChunk(1,1));
        obj.pUpdateConCache(obj.pGetConChunk(1,1));
        obj.pUpdateYLimits;
        
        end  % reset
        
        %----------------------------------------
        function updateYLimits(obj)
        %UPDATEYLIMITS Update y limits of graphs.
        %   UPDATEYLIMITS(OBJ) updates the y limits of the graphs and sends an
        %   event if any have changed.  The event data will indicate which rows
        %   have had their limits altered.
        
        ylOld = obj.LimitsY;
        obj.pUpdateYLimits;
        ylNew = obj.LimitsY;
        
        changed = false(size(ylOld));
        for n = 1:length(ylOld)
            changed(n) = ~all(ylOld{n}==ylNew{n});
        end
        
        if any(changed)
            Ridx = find(changed);
            data = struct('Rows', Ridx);
            evt = xregEventData(data);
            obj.notify('YLimUpdated', evt);
        end
        
        end  % updateYLimits
        
    end  % public methods
    
    methods (Access=protected)
        %----------------------------------------
        function SweepIdx = pGetConChunk(obj, R, C) %#ok<INUSL>
        %PGETCONCHUNK Get the limits of a block of constraints to evaluate.
        %   PGETCONCHUNK(OBJ, R, C) returns the sweep indices that need constraints
        %   evaluated next given that data is required at cell (R, C).
        
        if ~obj.CacheIsFilled && obj.DisplayConstraints
            % Check data size.  For smaller arrays we just calculate it all in one
            % go.
            nCon = obj.NumConstraints;
            nC = obj.getColumnCount;
            nCells = nCon*nC;
            if nCells>50
                if ~isempty(obj.hTable) && ishandle(obj.hTable)
                    % Provide enough data to fill up the visible size of the table
                    DispSize = obj.hTable.getVisibleSize;
                    C = max(obj.hTable.CurrentColumn, 1);
                    Cfinal = min(C+DispSize(2)-1, nC);
                else
                    % Calculate 5 columns at once
                    Cfinal = min(C+4, nC);
                end
                DataExists = obj.ConIsCalculated(C:Cfinal);
                SweepIdx = find(~DataExists) + C - 1;
            else
                SweepIdx = find(~obj.ConIsCalculated);
            end
            
        else
            SweepIdx = [];
        end
        
        end  % pGetConChunk
        
        %----------------------------------------
        function SweepIdx = pGetEvalChunk(obj, R, C)
        %PGETEVALCHUNK Get the limits of a block to evaluate.
        %   PGETEVALCHUNK(OBJ, R, C) returns the sweep indices that should be
        %   evaluated next given that data is required at cell (R, C).
        
        if ~obj.CacheIsFilled
            % Check data size.  For smaller arrays we just calculate it all in one
            % go.
            nR = obj.getRowCount;
            nC = obj.getColumnCount;
            nCells = nR*nC;
            if nCells>50
                if ~isempty(obj.hTable) && ishandle(obj.hTable)
                    % Provide enough data to fill up the visible size of the table
                    DispSize = obj.hTable.getVisibleSize;
                    C = max(obj.hTable.CurrentColumn, 1);
                    Cfinal = min(C+DispSize(2)-1, nC);
                else
                    % Calculate 5 columns at once
                    Cfinal = min(C+4, nC);
                end
                DataExists = all(obj.CellIsCalculated(:, C:Cfinal), 1);
                SweepIdx = find(~DataExists) + C - 1;
            else
                SweepIdx = find(~all(obj.CellIsCalculated, 1));
            end
            
        else
            SweepIdx = [];
        end
        
        end  % pGetEvalChunk
        
        %----------------------------------------
        function pUpdateConCache(obj, SweepIdx)
        %PUPDATECONCACHE Update cached constraint values for specified sweeps.
        %   PUPDATECONCACHE(OBJ, SWEEPIDX) calculates constraint data for the
        %   specified sweeps and updates the cache with the information.
        
        if isempty(obj.MessageService) ...
                || ~obj.MessageService.hasData ...
                || strcmp(obj.MessageService.CurrentSliceDirection, 'weightedsolution') ...
                || ~obj.MessageService.hasFocusIndex ...
                || isempty(SweepIdx)
            return
        end
        
        ms = obj.MessageService;
        Out = ms.getOptimOutput;
        or = getOptimRunner(Out);
        RunIdx = ms.getFocusRun;
        
        [~, nCon] = numConstraints(or);
        
        if obj.DisplayConstraints && nCon>0
            % Show figure pointer while new data is calculated
            PR = [];
            if ~isempty(obj.hTable) && ishandle(obj.hTable)
                PR = xregGui.PointerRepository;
                ptrID = PR.stackSetPointer(obj.hTable.Parent, 'watch');
            end
            
            ConEdges = obj.SweepConEdges;
            
            ItemNames = getConstraintNames(or,'inequality');
            % Evaluate sweeps of constraint values
            [ConSweep, XSweep] = evaluateSweep(or, obj.LocationX, 'Constraint', ItemNames, ...
                'FixedValueRun', RunIdx, ...
                'SweepValues', SweepIdx, ...
                'NumSweepPoints', 100);
            
            EqItemNames = getConstraintNames(or,'equality');
            if ~isempty(EqItemNames)
                % Evaluate sweeps of equality constraint values
                ConEqSweep = evaluateSweep(or, obj.LocationX, 'Constraint', EqItemNames, ...
                    'FixedValueRun', RunIdx, ...
                    'SweepValues', SweepIdx, ...
                    'NumSweepPoints', 100);
            end
            
            
            % Find regions where all constraints are satisfied
            Tol = getConstraintTol(Out);
            for n = 1:length(ConSweep)
                convector = all(ConSweep{n}<Tol, 2);
                if ~isempty(EqItemNames)
                    % feasible equality constraints
                    convector = convector & all(abs(ConEqSweep{n})<Tol, 2);
                end
                ConEdges{SweepIdx(n)} = mbcgui.widget.IntervalPatch1D.convertConstraintVector( ...
                    XSweep{n}, convector);
            end
            
            obj.SweepConEdges = ConEdges;
            
            obj.ConIsCalculated(SweepIdx) = true;
            obj.CacheIsFilled = all(obj.CellIsCalculated(:)) && all(obj.ConIsCalculated);
            
            if ~isempty(PR)
                PR.stackRemovePointer(obj.hTable.Parent, ptrID);
            end
        end
        
        end  % pUpdateConCache
        
        %----------------------------------------
        function pUpdateEvalCache(obj, SweepIdx)
        %PUPDATEEVALCACHE Update cached values for specified sweeps.
        %   PUPDATEEVALCACHE(OBJ, SWEEPIDX) calculates sweep data for the specified
        %   sweeps and updates the cache with the information.
        
        if isempty(obj.MessageService) ...
                || ~ obj.MessageService.hasData ...
                || strcmp(obj.MessageService.CurrentSliceDirection, 'weightedsolution') ...
                || ~obj.MessageService.hasFocusIndex ...
                || isempty(SweepIdx)
            return
        end
        
        % Show figure pointer while new data is calculated
        PR = [];
        if ~isempty(obj.hTable) && ishandle(obj.hTable)
            PR = xregGui.PointerRepository;
            ptrID = PR.stackSetPointer(obj.hTable.Parent, 'watch');
        end
        
        ms = obj.MessageService;
        Out = ms.getOptimOutput;
        or = getOptimRunner(Out);
        RunIdx = ms.getFocusRun;
        
        % Evaluate sweeps of objective values
        [YSweep, XSweep] = evaluateSweep(or, obj.LocationX, 'Objective', {}, ...
            'FixedValueRun', RunIdx, ...
            'SweepValues', SweepIdx, ...
            'NumSweepPoints', 100);
        
        % Transfer values to cached arrays
        sweepY = obj.SweepY;
        sweepX = obj.SweepX;
        
        sweepX(SweepIdx) = XSweep;
        for n = 1:length(SweepIdx)
            ThisSweep = SweepIdx(n);
            sweepY(:, ThisSweep) = num2cell(YSweep{n}', 2);
        end
        
        obj.SweepX = sweepX;
        obj.SweepY = sweepY;
        
        obj.CellIsCalculated(:, SweepIdx) = true;
        obj.CacheIsFilled = all(obj.CellIsCalculated(:)) && all(obj.ConIsCalculated);
        
        if ~isempty(PR)
            PR.stackRemovePointer(obj.hTable.Parent, ptrID);
        end
        
        end  % pUpdateEvalCache
        
        %----------------------------------------
        function pUpdateYLimits(obj)
        %PUPDATEYLIMITS Update the Y limits.
        %   PUPDATEYLIMITS(OBJ) updates the common set of limits that are used on
        %   the graphs.
        
        % Work out the common Y limits for each objective
        ylims = cell(1, length(obj.LocationY));
        AllData = cell2mat(obj.SweepY);
        for n = 1:length(ylims)
            ylims{n} = mbcmakelimits(AllData(n, :), 'loose');
        end
        obj.LimitsY = ylims;
        
        end  % pUpdateYLimits
        
    end
    
end  % classdef