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

    classdef ConGraphViewData < mbcgui.widget.ScrollTableData
    %cgoptimgui.ConGraphViewData class
    %   cageview.optimoutput.ConGraphViewData extends mbcgui.widget.ScrollTableData.
    %
    %    cageview.optimoutput.ConGraphViewData properties:
    %       MessageService - Property is of type 'handle'
    %       hTable - Property is of type 'handle'
    %       CacheIsFilled - Property is of type 'bool'
    %       CellIsCalculated - 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'
    %       LocationLHS - Property is of type 'MATLAB array'
    %       LocationRHS - Property is of type 'MATLAB array'
    %       SweepX - Property is of type 'MATLAB array'
    %       SweepLHS - Property is of type 'MATLAB array'
    %       SweepRHS - Property is of type 'MATLAB array'
    %       ConComparisonType - Property is of type 'MATLAB array'
    %       ConFeasibility - Property is of type 'MATLAB array'
    %       FeasibilityTol - Property is of type 'double'
    %       CellHasSweep - Property is of type 'MATLAB array'
    %
    %    cageview.optimoutput.ConGraphViewData 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.
    %       resetFeasibility - RESET Recalculate feasibility data.
    %       updateYLimits - Update y limits of graphs.
    
    %  Copyright 2000-2015 The MathWorks, Inc. and Ford Global Technologies, Inc.
    
    properties (AbortSet, SetObservable)
        %MESSAGESERVICE Property is of type 'handle'
        MessageService = [];
        %HTABLE Property is of type 'handle'
        hTable = [];
        %CACHEISFILLED Property is of type 'bool'
        CacheIsFilled
        %CELLISCALCULATED Property is of type 'MATLAB array'
        CellIsCalculated = [];
        %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 = [];
        %LOCATIONLHS Property is of type 'MATLAB array'
        LocationLHS = [];
        %LOCATIONRHS Property is of type 'MATLAB array'
        LocationRHS = [];
        %SWEEPX Property is of type 'MATLAB array'
        SweepX = [];
        %SWEEPLHS Property is of type 'MATLAB array'
        SweepLHS = [];
        %SWEEPRHS Property is of type 'MATLAB array'
        SweepRHS = [];
        %CONCOMPARISONTYPE Property is of type 'MATLAB array'
        ConComparisonType = [];
        %CONFEASIBILITY Property is of type 'MATLAB array'
        ConFeasibility = [];
        %FEASIBILITYTOL Property is of type 'double'
        FeasibilityTol
        %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>
            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}, ...
            'lhsdata', obj.SweepLHS{R, C}, ...
            'rhsdata', obj.SweepRHS{R, C}, ...
            'comparisontype', obj.ConComparisonType{R}, ...
            'confeas', obj.ConFeasibility(R), ...
            'value', obj.LocationX(C), ...
            'xlabel', Xlab, ...
            'ylabel', Ylab);
        
        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.
        
        if obj.ConFeasibility(Ridx)
            C = get(xregGui.SystemColorsDbl, 'CTRL_BACK');
        else
            C = mbcbdrycolor;
        end
        data = struct('Limits', obj.LimitsY{Ridx}, ...
            'Value', obj.LocationLHS(Ridx), ...
            'Label', obj.LabelsY{Ridx}, ...
            'Color', C);
        
        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
            
            i_SetToEmpty(obj);
            return
        end
        
        ms = obj.MessageService;
        RunIdx = ms.getFocusRun;
        SolIdx = ms.getFocusSolution;
        
        Out = ms.getOptimOutput;
        or = getOptimRunner(Out);
        
        [nConPerItem, nCon] = numConstraints(or);
        
        if nCon==0
            i_SetToEmpty(obj);
            return
        end
        
        % Get free variable values
        [XPoint, VarNames] = getSingleSolution(Out, RunIdx, SolIdx, 'OutputFormat', 'matrix', ...
            'OutputContents', {'FreeVars'});
        nFreeVar = length(VarNames);
        
        % Get constraint LHS/RHS at exact point
        [LHSPoint, ConNames] = getSingleSolution(Out, RunIdx, SolIdx, ...
            'OutputFormat', 'matrix', ...
            'OutputContents', {'ConstraintLHS'});
        RHSPoint = getSingleSolution(Out, RunIdx, SolIdx, ...
            'OutputFormat', 'matrix', ...
            'OutputContents', {'ConstraintRHS'});
        
        % Get Dependency matrix
        DepMatrix = getDependencyMatrix(or, 'Constraint', {});
        
        % Get free value ranges
        [LB, UB] = getFreeVariableRanges(or,RunIdx);
        
        % Get comparison operator for each constraint item
        ops = getConstraintOperators(or);
        idx = zeros(1, nCon);
        for n = 1:length(nConPerItem)
            idx(sum(nConPerItem(1:n-1))+1:sum(nConPerItem(1:n))) = n;
        end
        ops = ops(idx);
        
        set(obj, ...
            'CacheIsFilled', false, ...
            'CellIsCalculated', false(nCon, nFreeVar), ...
            'LimitsX', cellfun(@mbcmakelimits, num2cell([LB(:), UB(:)], 2)', 'UniformOutput', false), ...
            'LimitsY', repmat({[0 1]}, 1, nCon), ...
            'LabelsX', VarNames, ...
            'LabelsY', ConNames, ...
            'LocationX', XPoint, ...
            'LocationLHS', LHSPoint, ...
            'LocationRHS', RHSPoint, ...
            'SweepX', cell(1, nFreeVar), ...
            'SweepLHS', cell(nCon, nFreeVar), ...
            'SweepRHS', cell(nCon, nFreeVar), ...
            'ConComparisonType', ops, ...
            'CellHasSweep', DepMatrix);
        
        % Calculate the constraint feasibility
        obj.resetFeasibility;
        
        % Immediately calculate the initial data.  This means we will have some
        % idea of ylimits from the start
        obj.pUpdateEvalCache(obj.pGetEvalChunk(1,1));
        obj.pUpdateYLimits;
        end  % reset
        
        %----------------------------------------
        function resetFeasibility(obj)
        %RESET Recalculate feasibility data.
        %   RESETFEASIBILITY(OBJ) re-calculates just the feasibility data for the
        %   constraints.  This enables faster updating of this facet of the display
        %   when the tolerance is altered.
        
        if isempty(obj.MessageService) ...
                || ~ obj.MessageService.hasData ...
                || strcmp(obj.MessageService.CurrentSliceDirection, 'weightedsolution') ...
                || ~obj.MessageService.hasFocusIndex
            
            return
        end
        
        ms = obj.MessageService;
        RunIdx = ms.getFocusRun;
        SolIdx = ms.getFocusSolution;
        Out = ms.getOptimOutput;
        
        % Get constraint feasibility
        obj.ConFeasibility = getSingleSolution(Out, RunIdx, SolIdx, ...
            'OutputFormat', 'matrix', ...
            'OutputContents', {'ConstraintFeas'});
        
        % Get new tolerance
        obj.FeasibilityTol = getConstraintTol(Out);
        
        end  % resetFeasibility
        
        %----------------------------------------
        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 = pGetEvalChunk(obj, R, C) %#ok<INUSL>
        %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 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 LHS and RHS values values
        [LHSSweep, XSweep] = evaluateSweep(or, obj.LocationX, 'Constraint', {}, ...
            'EvaluationType', 'LHSEvaluate', ...
            'FixedValueRun', RunIdx, ...
            'SweepValues', SweepIdx, ...
            'NumSweepPoints', 100);
        RHSSweep = evaluateSweep(or, obj.LocationX, 'Constraint', {}, ...
            'EvaluationType', 'RHSEvaluate', ...
            'FixedValueRun', RunIdx, ...
            'SweepValues', SweepIdx, ...
            'NumSweepPoints', 100);
        
        % Transfer values to cached arrays
        sweepLHS = obj.SweepLHS;
        sweepRHS = obj.SweepRHS;
        sweepX = obj.SweepX;
        
        sweepX(SweepIdx) = XSweep;
        for n = 1:length(SweepIdx)
            ThisSweep = SweepIdx(n);
            sweepLHS(:, ThisSweep) = num2cell(LHSSweep{n}', 2);
            sweepRHS(:, ThisSweep) = num2cell(RHSSweep{n}', 2);
        end
        
        obj.SweepLHS = sweepLHS;
        obj.SweepRHS = sweepRHS;
        obj.SweepX = sweepX;
        
        obj.CellIsCalculated(:, SweepIdx) = true;
        obj.CacheIsFilled = all(obj.CellIsCalculated(:));
        
        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.LabelsY));
        AllData = cell2mat([obj.SweepLHS, obj.SweepRHS]);
        for n = 1:length(ylims)
            ylims{n} = mbcmakelimits(AllData(n, :), 'loose');
        end
        obj.LimitsY = ylims;
        
        end  % pUpdateYLimits
        
    end
    
end  % classdef

function i_SetToEmpty(obj)
% Set data cache to be empty
set(obj, ...
    'CacheIsFilled', true, ...
    'CellIsCalculated', false(0,0), ...
    'LimitsX', {}, ...
    'LimitsY', {}, ...
    'LabelsX', {}, ...
    'LabelsY', {}, ...
    'LocationX', [], ...
    'LocationLHS', [], ...
    'LocationRHS', [], ...
    'SweepX', {}, ...
    'SweepLHS', {}, ...
    'SweepRHS', {}, ...
    'ConComparisonType', {}, ...
    'CellHasSweep', false(0,0));
end  % i_SetToEmpty