www.gusucode.com > mbc 工具箱 matlab 源码程序 > mbc/+mbcboundary/AbstractBoundary.m

    classdef AbstractBoundary < mbcutils.abstractdataobject 
    %MBCBOUNDARY.ABSTRACTBOUNDARY base command-line boundary model class
    %    The mbcboundary.AbstractBoundary model is the base class for all
    %    boundary model classes in the Model-Based Calibration toolbox
    %    software. There should not be any instances of this class.
    %
    %    mbcboundary.AbstractBoundary properties:
    %        Name           - name of boundary model (read only)
    %        NumberOfInputs - number of inputs (read only)
    %        Type           - boundary model type (read only)
    %        Inputs         - boundary model inputs
    %        FitAlgorithm   - fit algorithm for boundary model
    %        Fitted         - indicates whether boundary model has been fitted (read only)
    %
    %    mbcboundary.AbstractBoundary methods:
    %        CreateBoundary      - create a new boundary model
    %        getAlternativeTypes - list of alternative boundary model types
    %        Evaluate            - evaluate boundary model
    %        designconstraint    - convert boundary model to a design constraint 
    %
    %    Boundary models can be combined using the logical operators &, | and ~.

    %  Copyright 2009-2011 The MathWorks, Inc.
    
    properties (Dependent,SetAccess=protected)
        %NAME Name of boundary model (read only)
        Name
        %NUMBEROFINPUTS Number of inputs (read only)
        %    The number of boundary model inputs are set on creation of the
        %    boundary model.
        %
        % See also Inputs, mbcboundary.CreateBoundaryModel
        NumberOfInputs
        %TYPE Boundary model type (read only)
        %    The boundary model type is set on creation with CreateBoundaryModel.
        %    The list of valid types is specified by getAlternativeTypes.
        %
        %See also getAlternativeTypes, CreateBoundaryModel
        Type
    end
    
    properties (Dependent,AbortSet)
        %INPUTS boundary model inputs 
        %    Boundary model inputs are an array of mbcmodel.modelinput objects. 
        %    The number of boundary model inputs are set on creation of the
        %    boundary model. The name, symbol and range of the inputs can
        %    be changed.
        %
        %See also NumberOfInputs, mbcmodel.modelinput
        Inputs
        %FITALGORITHM fit algorithm for boundary model 
        %    FitAlgorithm is a mbcmodel.fitalgorithm object.
        FitAlgorithm
    end
    
    properties (Access=protected)
        %pFitAlgorithm actual storage for FitAlgorithm
        pFitAlgorithm
    end
    
    
    properties (SetAccess=protected)
        %FITTED indicates whether boundary model has been fitted (read only)
        %    Fitted must be true before the boundary model can be evaluated.
        %
        %See also Evaluate
        Fitted = false;
    end
   
    methods (Hidden)
        function B = AbstractBoundary(con,opts,Status,varargin)
           %AbstractBoundary - constructor not intended for public calls

            if nargin
                B = pInitialise(B,con);
                B = mbcSetPropValuePairs(B,varargin{:});
            end
            
           if nargin>1 
               % create and store a fit algorithm object
                if ~isempty(opts) && isnull(opts)
                    opts = [];
                end
               B.pFitAlgorithm = mbcmodel.fitalgorithm(opts,B);
           end
           
           if nargin>=3
               B.Fitted = Status~=0;
           end

        end
        
        function UpdateTree(B,bdev)
            %UPDATETREE update boundary tree object
            %
            % This is the main method to update the boundary tree in
            % mbcmodel projects.
            
            mbcboundary.AbstractBoundary.assertScalar(B)
            con = B.Object;
            if ~isempty(B.FitAlgorithm)
                opts = getObject(B.FitAlgorithm);
            else
                opts = [];
            end
            if isempty(opts)
                % use default fit options
                opts = getFitOptions(con);
            end

            if getstages(bdev)==2
                stage  = 2;
            else
                stage  = 0;
            end
            if ~isequal(getInputFactors(con),getInputFactors(bdev,stage))
                % check inputs
                error('mbc:mbcboundary:AbstractBoundary:InvalidValue',...
                    'The boundary model has incompatible inputs with the boundary tree.')
            end
            
            % check type
            ClassNames = BoundaryClasses(bdev);
            if ~any(strcmp(class(B.Object),ClassNames ))
                % check that the boundary model type is valid.
                OptionNames = cell(1,length(ClassNames));
                for i=1:length(ClassNames)
                    OptionNames{i} = typename(feval(ClassNames{i}));
                end
                error(message('mbc:mbcboundary:AbstractBoundary:InvalidValue1', mbcListString( OptionNames, ' ', 'or' )))
            end
            
            %set it and fit it - boundary models are always refitted when
            %updating the tree 
            bdev = setupConstraint(bdev,con, opts);
            fitConstraint(info(bdev),'all');
            
        end
        
    end
    
    methods 
        %get and set methods
        function v = get.Name(obj) 
            v = tostring(obj.Object);
        end
        function v = get.Inputs(obj) 
            cif = getInputFactors(obj.Object);
            Inputs = mbcinputfactor(cif);
            v = mbcmodel.modelinput(Inputs);
        end
        
        
        function B = set.Inputs(B,Inputs)
            if isa(Inputs,'mbcmodel.modelinput') && length(Inputs)==B.NumberOfInputs
                cif = coninputfactor( mbcinputfactor(Inputs) );
                B.Object = setInputFactors(B.Object,cif);
            else
                error(message('mbc:mbcboundary:AbstractBoundary:InvalidValue2'))
            end
        end
            
        function v = get.NumberOfInputs(obj)
            v = nFactors(obj.Object);
        end
        
        function v = get.Type(obj)
            v= typename(obj.Object);
        end
        
        function B = set.FitAlgorithm(B,OPTS)
            
            if ~isempty(B.Object)
                OldValue = B.FitAlgorithm;
                if ischar(OPTS) && isa(OldValue,'mbcmodel.fitalgorithm')
                    % create algorithm from string
                    OPTS = CreateAlgorithm(OldValue,OPTS);
                end
                if ~isscalar(OPTS) || ~isa(OPTS,'mbcmodel.fitalgorithm')
                    error(message('mbc:mbcboundary:AbstractBoundary:InvalidArgument'))
                elseif ~(isempty(OldValue) || IsAlternative(OPTS,OldValue))
                    % this doesn't work due to change of types
                    error(message('mbc:mbcboundary:AbstractBoundary:InvalidArgument1', B.Type))
                end
            end
            B.pFitAlgorithm = OPTS;
            B.Fitted = false;
        end
        
        
        function OPTS = get.FitAlgorithm(B)
        
        if isempty(B.pFitAlgorithm)
            % create a new default fit object when required
            opts = getFitOptions(B.Object,'all');
            if ~isempty(opts) && isnull(opts)
                opts = [];
            end
            OPTS = mbcmodel.fitalgorithm( opts ,B);
        else
            OPTS = B.pFitAlgorithm;
        end
        end
        
        function y = Evaluate(B,X)
            %EVALUATE evaluate boundary model
            %    y = Evaluate(B,X);
            %    X is a matrix with B.NumberOfInputs columns.
            %    All boundaries are of the form g(x)=0. A positive value
            %    indicates that the point is outside the boundary.
            %    A boundary model must be fitted before it can be
            %    evaluated.
            %
            %See also Fitted
            
            mbcboundary.AbstractBoundary.assertScalarFitted(B);

            if nargin<2 || ~isa(X,'double') || ~size(X,2)==B.NumberOfInputs
                error(message('mbc:mbcboundary:AbstractBoundary:InvalidValue3', obj.NumberOfInputs))
            end
            
            y = constraintDistance(B.Object,X);
        end
        
        function [OptionNames,ObjectIndex,OptionObjects] = getAlternativeTypes(obj)
            %GETALTERNATIVETYPES list of boundary model types
            %    Types = getAlternativeTypes(obj);
            %    Types is a list of boundary model types which could be
            %    used as alternative boundary model types for the current
            %    boundary model.
            %
            %See also Type, CreateBoundaryModel

            % undocumented
            % [OptionNames,ObjectIndex,OptionObjects] = getAlternativeTypes(obj)

            mbcboundary.AbstractBoundary.assertScalar(obj)

            c = obj.Object;
            if ~isempty(c)
                opts = BoundaryClasses(obj);
                [OptionObjects, OptionNames, ObjectIndex] = pGenerateObjectList(c, opts);
                OptionNames = OptionNames(:);
            else
                error(message('mbc:mbcboundary:AbstractBoundary:InvalidState', class( obj )))
            end
        end
        
        function C = designconstraint(C)
            %DESIGNCONSTRAINT convert boundary model to a design constraint
            %    C = designconstraint(C)
            %    To use a boundary model as a design constraint you must
            %    convert it to a mbcdoe.designconstraint object. The
            %    boundary model must be fitted (Fitted=true) before it can
            %    be converted to a design constraint.
            %
            %See also mbcdoe.designconstraint, mbcdoe.design.AddConstraint
        
            mbcboundary.AbstractBoundary.assertScalarFitted(C);
            C = mbcdoe.designconstraint(C.Object);

        end
        
        function B = CreateBoundary(B,Type,varargin)
            %CREATEBOUNDARY create boundary model from existing model
            %    NEWMODEL = CreateBoundary(MODEL,Type);
            %    NEWMODEL = CreateBoundary(MODEL,Type,Property,Value,...);
            %    A new boundary model with the same inputs as the current
            %    boundary model MODEL is created. You can get a list of valid
            %    types with getAlternativeTypes. Property, value pairs can be
            %    used to set properties of the boundary model.
            %    
            %See also getAlternativeTypes, mbcboundary.CreateBoundary
            
            narginchk(1,Inf)
            mbcboundary.AbstractBoundary.assertScalar(B)

            [OptionNames,~,OptionObjects] = getAlternativeTypes(B);
            Index = strcmp(Type,OptionNames);
            if any(Index)
                con = OptionObjects{Index};
                try
                    B = pInitialise(B,con);
                    B = mbcSetPropValuePairs(B,varargin{:});
                catch ME
                    createME = MException('mbc:mbcboundary:AbstractBoundary:InvalidType',...
                        'Error creating new boundary model type');
                    createME = createME.addCause(ME);
                    throw(createME)
                end
            else
                list = mbcListString(OptionNames,' ','or');
                if length(list)>1
                    error(message('mbc:mbcboundary:AbstractBoundary:InvalidType', list))
                elseif length(list)==1
                    error(message('mbc:mbcboundary:AbstractBoundary:InvalidType1', list))
                else
                    error(message('mbc:mbcboundary:AbstractBoundary:InvalidType2', B.Type))
                end
            end
            
        end
        
        function B = and(B1,B2)
            %AND intersection of boundary constraints
            %    B = B1 & B2;
            %    Both B1 and B2 must be scalar and fitted before they can
            %    be used in a logical expression.  

            mbcboundary.AbstractBoundary.assertScalarFitted(B1);
            mbcboundary.AbstractBoundary.assertScalarFitted(B2,'second');

            con = B1.Object & B2.Object;
            
            B = boundarymodel(con,[],true);
        end
        
        function B = or(B1,B2)
            %OR union of boundary constraints
            %    B = B1 | B2;
            %    Both B1 and B2 must be scalar and fitted before they can
            %    be used in a logical expression.  
            
            mbcboundary.AbstractBoundary.assertScalarFitted(B1);
            mbcboundary.AbstractBoundary.assertScalarFitted(B2,'second');

            con = B1.Object | B2.Object;
            B = boundarymodel(con,[],true);
        end
        
        function B = not(B1)
            %NOT complement of boundary constraint
            %    B = ~B1;
            %    B1 must be scalar and fitted before it can be used in a
            %    logical expression.  

            mbcboundary.AbstractBoundary.assertScalarFitted(B1);
            con = ~B1.Object;
            
            B = boundarymodel(con,[],true);
        end

    end
    
    methods (Access=protected)
        function B = Reset(B)
            %RESET reset boundary
            B.Fitted = false;
        end
        
        function B = resetAlgorithm(B)
        
            % empty algorithm
            B.pFitAlgorithm = [];
            B = Reset(B);
        end
        
        
        function B = pInitialise(B,con)
            %PINITIALISE initialise boundary with new con object
            if isempty(B.Object) || ~isequal(con,B.Object)
                B.Object = con;
                B = resetAlgorithm(B);
            end
        end
        function ok = CanEvaluate(obj)
            %CANEVALUATE
            ok = obj.Fitted;
        end

        
        function opts = BoundaryClasses(B)
            %BOUNDARYCLASSES list of compatible con* classess
            opts = BoundaryClasses(B.Object);
        end
    end
    
    methods (Access=protected,Static)
        function assertScalarFitted(B,Position)
            %assertScalarFitted check that the boundary model is scalar and been fitted 
            if nargin<2
                Position = 'first';
            end
            if ~(isscalar(B) && isa(B,'mbcboundary.AbstractBoundary') && CanEvaluate(B))
                ME = MException('mbc:mbcboundary:AbstractBoundary:InvalidValue',...
                    'The %s input must be a scalar boundary model that has been fitted.',Position);
                % throw as caller to avoid showing this stack trace.
                throwAsCaller(ME)
            end
        end
        
        function assertScalar(B,Position)
            %assertScalar check that the boundary model is scalar 
            if nargin<2
                Position = 'first';
            end
            if ~(isscalar(B) && isa(B,'mbcboundary.AbstractBoundary')) 
                ME = MException('mbc:mbcboundary:AbstractBoundary:ScalarObjectRequired',...
                    'The %s input must be a scalar boundary model.',Position);
                % throw as caller to avoid showing this stack trace.
                throwAsCaller(ME)
            end
        end        
        
    end

end %classdef