www.gusucode.com > mbcmodels 工具箱 matlab 源码程序 > mbcmodels/mbcCheckInput.m

    function [OK,msg] = mbcCheckInput(Value,Type,Options,Property,ThrowError)
%MBCCHECKINPUT type checking for  new input values 
% 
% OK = mbcCheckInput(Value,Type,Property)
% [OK,msg] = mbcCheckInput(Value,Type,Property,ThrowError)
%
% Inputs
%   Value:  
%   Type :   Check Type Details
%   Property: Property name (Default = 'Property')
%   ThrowError: throw an error if Value is not correct (default = true)
%
%      List of supported types for mbcCheckInput
%
%
% +---------------+-------------------------+----------+-------------------
% |Type	          | Identifier	            | Options  | Criteria
% +---------------+-------------------------+----------+-------------------
% |Scalar numbers |'real','numeric','double'|range	   | Scalar, not complex, not NaN 
% |Scalar integers|'int'                    |range     | Scalar integer, Not complex, not NaN
% |Ranges	      |'range'	                |range	   | Two element numeric range [min,max]
% |               |                         |          |  Min < Max 
% |               |                         |          | There is also a one element range! 
% |Vectors        |'vector','vector int'    | range	   | A vector has numeric elements and is row vector
% |               |'vector real'            | length   |
% |Matrices       |'matrix','matrix int'    | range	   | A matrix has numeric elements 
% |               |'matrix real'            | size     |
% |Logical	      |'boolean','bool','logical'          |
% |Cell String	  |'cellstr'		        |          |
% |Eval String	  |'evalstr',               |          | {TryExpressionString,CatchExpressionString}
% |               |'MATLAB Callback'        |          | or ExpressionString
% |Enumerated	  |'enum','vector enum'     |EnumList  |The old enumerated type with a | separated list 
% |               |                         |  length  | is still supported.
% |Sparse         |'sparse'                 |          | issparse - sparse is no longer a class in MATLAB
% |Class          |'ClassName'              |		   | isa(Value,'ClassName')
% |Function	      | function_handle	        |Cell array| msg = F(Property,Value,Options{:});
% |               |                         |of extra  |
% |               |                         |arguments |	
% +---------------+-------------------------+----------+-------------------
%
% All the above numeric types (numbers, integers, ranges, vectors) support a range option
% 
% {'Type',[min,max]} user-defined range
% {'Type','positive'}		 strictly positive numbers
% {'Type','negative'}		 strictly negative numbers
% 
%  The length and range options can be used together or separately for vector options
%    {'vector',{[min,max},Length}}
%    {'vector',[min,max]}
%    {'vector',Length}
%  The length and range options can be used together or separately for vector options
%    {'matrix',{[min,max},Size}}
%    {'matrix',[min,max]}
%    {'matrix',Size}


% The vector enum type does not require the Length option but does require the EnumList 
%    {'vector enum',{EnumList,Length}}
%    {'vector enum',EnumList}

%  Copyright 2006-2011 The MathWorks, Inc. and Ford Global Technologies, Inc.

persistent CHECKFCNS

if isempty(CHECKFCNS)
    % supported types
    %    msg = CHECKFCNS{cind,2}(Property,Value,Options);
    CHECKFCNS= {'numeric',@iCheckNumeric
        'real',@iCheckNumeric
        'double',@iCheckNumeric
        'int',@iCheckInteger
        'boolean',@iCheckLogical
        'bool',@iCheckLogical
        'range',@iCheckRange
        'vector',@iCheckVector
        'vector real',@iCheckVector
        'vector int',@iCheckVectorInt
        'vector enum',@iCheckVectorEnumerated
        'matrix',@iCheckMatrix
        'cellstr',@iCheckCellStr
        'evalstr',@iCheckEvalStr
        'MATLAB Callback',@iCheckEvalStr
        'enum',@iCheckEnumerated
        'sparse',@iCheckSparse};
end

if nargin<4
    Property = 'Property';
end
if nargin<5
    ThrowError = true;
end



if ~isempty(Type) && ischar(Type)
    pbar = strfind(Type,'|');
    if ~isempty(pbar)
        % options are emnumerated strings separated by |'s
        msg = iCheckEnumeratedBar(Property,Value,Type);
    else
        % look in one of the predefined check function
        cind=  strcmpi(Type,CHECKFCNS(:,1));
        if any(cind)
            msg = CHECKFCNS{cind,2}(Property,Value,Options);
        else
            % check the class
            msg = iCheckClass(Property,Value,Type);
        end
    end
elseif isa(Type,'function_handle')
    msg = Type(Value,Options{:});
else 
    % no checking
    msg = '';
end

OK = isempty(msg);
if ~OK && ~ischar(msg)
    % we might get here with an old function handle call
    OK = msg;
    if ~OK 
        msg = 'Unknown Error';
    end
end

if ~OK && ThrowError
    error('mbc:mbcCheckInput:InvalidValue',msg);
end


% range checker
function msg= iRange(Property,Value,Options)

OK = true;
if isempty(Options)
    msg = '';
elseif isnumeric(Options) && numel(Options)==2
    OK =  ~(any(Value<Options(1)) || any(Value>Options(2)));
    msg = sprintf('All numeric inputs must be in the range [%g,%g].', Options(1), Options(2) );
elseif ischar(Options)
    switch lower(Options)
        case 'positive'
            OK = ~any(Value<=0);
            msg = 'All numeric inputs must be positive';
        case 'negative'
            OK = ~any(Value>=0);
            msg = 'All numeric inputs must be negative';
        otherwise
            OK = false;
            msg = 'Unknown range option';
    end
else 
    OK = false;
    msg = 'Unknown range option';
end
if OK
    % empty message if all OK
    msg = '';
end

% Enumerated with | Separators
function msg = iCheckEnumeratedBar(Property,Value,Type)

% options are emnumerated strings separated by |'s
TextStrings = textscan( Type,'%s','delimiter','|' );
c = TextStrings{1};
valid_strings = ['''',strrep(Type, '|', ''','''),''''];
msg = '';
if ~ischar(Value)
    msg = sprintf('Enumerated type for %s must be one of {%s}.', Property, valid_strings );
else
    optind = strcmpi(Value, c);
    if ~any(optind)
        msg = sprintf('Enumerated type for %s must be one of {%s}.', Property, valid_strings );
    end
end


% Enumerated with list in Options
function msg = iCheckVectorEnumerated(Property,Value,Options)

[Options,RequiredLength] = iVectorOptions(Options);

List = sprintf('''%s'',',Options{:});
List(end)= '';
msg = '';
if ~iscellstr(Value)
    msg = sprintf('Enumerated type for %s must be cell array of {%s}.', Property, List );
else
    optind = ismember(Value, Options);
    if ~all(optind)
        msg = sprintf('Enumerated type for %s must be a cell array of {%s}.', Property, List );
    end
end

if isempty(msg) && ~isempty(RequiredLength) && length(Value)~=RequiredLength
    msg = sprintf('A row vector with %d elements is required for %s.', RequiredLength,Property );
end

% iCheckEnumerated
function msg = iCheckEnumerated(Property,Value,Options)

List = sprintf('''%s'',',Options{:});
List(end)= '';
msg = '';
if ~ischar(Value)
    msg = sprintf('Enumerated type for %s must be one of {%s}.', Property, List);
else
    optind = ismember(Value, Options);
    if ~all(optind)
        msg = sprintf('Enumerated type for %s must be one of {%s}.', Property, List);
    end
end



% Basic numeric
function msg = iCheckNumeric(Property,Value,Options)

if ~isscalar(Value) || ~isnumeric(Value)
    msg = sprintf('A scalar numeric input is required for %s', Property);
elseif isnan(Value)
    msg = sprintf('NaN is not supported for %s.', Property );
elseif ~isreal(Value)
    msg = sprintf('Complex numbers are not supported for %s.', Property);
else  
    msg = iRange(Property,Value,Options);
end


% Integer
function msg = iCheckInteger(Property,Value,Options)

msg = iCheckNumeric(Property,Value,Options);
if isempty(msg) &&  Value~=fix(Value) 
    msg = sprintf('Integer input is required for %s.',Property);
end

% Logical
function msg = iCheckLogical(Property,Value,Options)

msg = '';
if ~isscalar(Value) || (~islogical(Value) && ~(isnumeric(Value) && any(Value == [0 1])))
    msg = sprintf('Scalar boolean input is required for %s.', Property);
end



% Range
function msg = iCheckRange(Property,Value,Options)

if ~isnumeric(Value)
    msg = sprintf('The range for %s must be numeric.', Property );
elseif ~isreal(Value) || any(isnan(Value))
    msg = sprintf('Ranges with complex numbers or NaN''s are not supported for %s.',Property );
elseif any(numel(Value) == [1 2])
    msg = iRange(Property,Value,Options);
    if isempty(msg) && numel(Value)==2 && Value(1) >= Value(2)
        msg = sprintf('The range of %s must be strictly increasing.', Property);
    end
else
    msg = sprintf('One or two numeric values are required for %s.',Property);
end

% iVectorOptions
function [MainOption,RequiredLength] = iVectorOptions(Options)

MainOption = [];
RequiredLength = [];
if iscell(Options) && numel(Options)==2 && (isnumeric(Options{2}) && isscalar(Options{2}))
    % cell array with main option as first element 
    MainOption = Options{1};
    RequiredLength = Options{2};
elseif isnumeric(Options) && isscalar(Options)
    RequiredLength =Options;
else
    MainOption = Options;
end


% Vector
function msg = iCheckVector(Property,Value,Options)

[RangeOpts,RequiredLength] = iVectorOptions(Options);

msg = '';
if any(~isnumeric(Value))
    msg = sprintf('Numeric values are required for %s.', Property);
elseif ~isreal(Value) || ~all(isfinite(Value))
    msg = sprintf('Complex numbers, NaN''s and Inf''s are not supported for %s.', Property );
elseif ~isempty(Options) 
    msg= iRange(Property,Value,RangeOpts);
end
if isempty(msg) && size(Value, 1) > 1
    msg = sprintf('A row vector is required for %s.', Property );
end

if isempty(msg) && ~isempty(RequiredLength) && length(Value)~=RequiredLength
    msg = sprintf('A row vector with %d elements is required for %s.', RequiredLength,Property );
end


% iMatrixOptions
function [MainOption,RequiredSize] = iMatrixOptions(Options)

MainOption = [];
RequiredSize = [];
if iscell(Options) && numel(Options)==2 && (isnumeric(Options{2}) && isscalar(Options{2}))
    % cell array with main option as first element 
    MainOption = Options{2};
    RequiredSize = Options{1};
elseif isnumeric(Options) && numel(Options)==2
    RequiredSize =Options;
else
    MainOption = Options;
end

% Matrix
function msg = iCheckMatrix(Property,Value,Options)

[RangeOpts,RequiredSize] = iMatrixOptions(Options);

msg = '';
if any(~isnumeric(Value))
    msg = sprintf('Numeric values are required for %s.', Property);
elseif ~isreal(Value) || ~all(isfinite(Value(:)))
    msg = sprintf('Complex numbers, NaN''s and Inf''s are not supported for %s.', Property );
elseif ~isempty(Options) 
    msg= iRange(Property,Value,RangeOpts);
end

if isempty(msg) && ~isempty(RequiredSize) && any(size(Value)~=RequiredSize)
    msg = sprintf('A %dx%d matrix is required for %s.', RequiredSize,Property );
end



% Vector Int
function msg = iCheckVectorInt(Property,Value,Options)

msg = iCheckVector(Property,Value,Options);
if isempty(msg) && (any(Value~=fix(Value)) || any(~isreal(Value)) || any(isnan(Value)))
    msg = sprintf('A vector of integers is required for %s.',Property);
end

% Cell String
function msg = iCheckCellStr(Property,Value,Options)

if ~iscellstr(Value)
    msg = sprintf('A cell array of strings is required for %s.',Property);
else
    msg = '';
end
    

% EvalStr
function msg = iCheckEvalStr(Property,Value,Options)

msg = '';
if isnumeric(Value)
    % check input is a valid number
    msg = iCheckNumeric(Property,Value,[]);
    if isempty(msg)
        Value = num2str(Value);
    end
end
if  isempty(msg) && ~ischar(Value) && ~(iscellstr(Value) && numel(Value)==2)
    msg = sprintf('Evalstr must either be ExpressionString or {TryExpression,CatchExpression}');
end

% Sparse
function msg = iCheckSparse(Property,Value,Options)

if ~issparse(Value)
    % sparse is no longer a class
    msg = sprintf('Input for %s must be sparse.', Property);
else
    msg = '';
end


% Class
function msg = iCheckClass(Property,Value,cls)
if isa(Value,cls)
    msg = '';
else
    % check class
    msg = sprintf('Input for %s must be a %s.', Property, cls);
end