Validate

This class contains methods to validate data according to class type, length, and definiteness.

SYNTAX [valid_flag value] = Validate.SCALAR(in,'PropertyName',Propertyvalue,...); [valid_flag value] = Validate.ARRAY(in,'PropertyName',Propertyvalue,...);

INPUTS in : Input object that is to be validated

PROPERTIES type {double} : The required class type of the input object. Cell ( true | {false} ) : Specifies if cell arrays are permitted in which case the properties are applied to all elements of the cell array. MinVal {-inf} MaxVal {inf} MinLen {0} MaxLen {inf}

EXAMPLES

 [valid_flag value] = Validate.ARRAY(in);
     ==> array of doubles (empty permitted)
 [valid_flag value] = Validate.ARRAY(in,'Cell',true);
     ==> array of doubles (cell array of array of doubles permitted)
 [valid_flag value] = Validate.ARRAY(in,'type','int');
     ==> array of integer values
 [valid_flag value] = Validate.SCALAR(in,'minLen',1);
     ==> scalar double (empty not permitted)
 [valid_flag value] = Validate.SCALAR(in,'type','Name','Cell',true);
     ==> scalar Name object (cell array of scalar Name objects permitted)
 [valid_flag value] = Validate.ARRAY(in,'minLen',1,'minVal',eps);
     ==> array of positive definite doubles with at least one element.
 [valid_flag value] = Validate.SCALAR(in,'maxVal',0);
     ==> scalar negative semidefinite double.
 [valid_flag value] = Validate.ARRAY(in,'type','int','minLen',3','maxLen',3,'minVal',0,'maxVal',255);
     ==> 3-element array of integers between 0 and 255.

Contents

classdef Validate < hgsetget
    % This class is a static class that provides input validation services.

    %   URL : $URL: $
    %   Log : $Id: Validate.html,v 1.1 2008/07/23 12:51:20 jberg Exp $
    %   Copyright (c) 2008 The MathWorks, Inc.

Class Properties

    properties ( SetAccess = 'public', GetAccess = 'public' )
        Cell;       % default Cell Permitted;
        maxLen;		% default Max Length;
        maxVal;		% default Max Value;
        minLen;		% default Min Length;
        minVal;		% default Min Value;
        Type;       % default Type;
    end
    properties ( SetAccess = 'private', GetAccess = 'private', Constant = true )
        % Default properties
        CELL_PERMITTED  = false;	% default Cell Permitted;
        MAX_LEN         = inf;		% default Max Length;
        MAX_VAL         = inf;		% default Max Value;
        MIN_LEN         = 0;		% default Min Length;
        MIN_VAL         = -inf;		% default Min Value;
        TYPE            = 'double';	% default Type;
    end

    methods
        function obj = Validate(varargin)

        end
    end
    methods (Static = true)

Public STATIC Helper Methods

        function [valid_flag out] = SCALAR(varargin)
            varargin(end+1) = {'MaxLen'};
            varargin(end+1) = {1};
            [valid_flag out] = Validate.GENERIC(varargin{:});
        end

        function [valid_flag out] = ARRAY(varargin)
            [valid_flag out] = Validate.GENERIC(varargin{:});
        end

        function [valid_flag out] = GENERIC(varargin)
            in = varargin{1};
            [type,cell_permitted,min_val,max_val,min_len,max_len] = ...
                Validate.assemble_vargs(varargin{2:end});

            % Because there are different ways to represent logical values, we
            % must first convert valid values to logical before checking type.
            if strcmpi(type,'logical')
                in = Validate.Convert2Logical(in);
            end

            % Check size
            valid_flag = Validate.check_size(in,min_len,max_len,cell_permitted);

            % Is input empty?  If valid_flag = true, then empty must be
            % acceptable.
            if valid_flag && ~isempty(in)
                % Check type
                valid_flag = Validate.check_type(in,type,cell_permitted,min_len);

                % Some types require further validation
                if valid_flag && isnumeric(in) % Check val
                    valid_flag = Validate.check_val(in,min_val,max_val,cell_permitted);
                end

                if valid_flag && strcmpi(type,'int')
                    valid_flag = Validate.check_int(in,cell_permitted);
                end
            end

            if valid_flag % Passed all hurdles, send back input
                out = in;
            else
                out = NaN;
                warning('%s.GENERIC could not interpret input as a valid %s',...
                    mfilename,type) %#ok<WNTAG>
            end
        end

        function in = Convert2Logical(in)
            % Here, we want to allow other representations of true and false
            if iscell(in)
                in(cellfun(@(x) x==1,in))               = {true};
                in(cellfun(@(x) strcmpi(x,'true'),in))  = {true};
                in(cellfun(@(x) strcmpi(x,'t'),in))     = {true};
                in(cellfun(@(x) strcmpi(x,'yes'),in))   = {true};
                in(cellfun(@(x) strcmpi(x,'y'),in))     = {true};
                in(cellfun(@(x) strcmpi(x,'on'),in))    = {true};
                in(cellfun(@(x) x==0,in))               = {false};
                in(cellfun(@(x) strcmpi(x,'false'),in)) = {false};
                in(cellfun(@(x) strcmpi(x,'f'),in))     = {false};
                in(cellfun(@(x) strcmpi(x,'no'),in))    = {false};
                in(cellfun(@(x) strcmpi(x,'n'),in))     = {false};
                in(cellfun(@(x) strcmpi(x,'off'),in))   = {false};
            else
                true_idx    = false(size(in));
                false_idx   = false(size(in));
                nonlogical_idx     = true(size(in));

                true_idx(arrayfun(@(x) x==1,in))              = true;
                true_idx(arrayfun(@(x) strcmp(x,'true'),in))  = true;
                true_idx(arrayfun(@(x) strcmp(x,'t'),in))     = true;
                true_idx(arrayfun(@(x) strcmp(x,'yes'),in))   = true;
                true_idx(arrayfun(@(x) strcmp(x,'y'),in))     = true;
                true_idx(arrayfun(@(x) strcmp(x,'on'),in))    = true;

                false_idx(arrayfun(@(x) x==0,in))              = true;
                false_idx(arrayfun(@(x) strcmp(x,'false'),in)) = true;
                false_idx(arrayfun(@(x) strcmp(x,'f'),in))     = true;
                false_idx(arrayfun(@(x) strcmp(x,'no'),in))    = true;
                false_idx(arrayfun(@(x) strcmp(x,'n'),in))     = true;
                false_idx(arrayfun(@(x) strcmp(x,'off'),in))   = true;

                in = true_idx;
                in(false_idx) = false;
                nonlogical_idx(true_idx) = false;
                nonlogical_idx(false_idx) = false;
                if any(any(nonlogical_idx))
                    in = double(in);
                end
            end
        end

        function [type,Cell,MinVal,MaxVal,MinLen,MaxLen] = assemble_vargs(varargin)
            % Input Properties
            in_prop = {'type','Cell','MinVal','MaxVal','MinLen','MaxLen'};

            % Retrieve default properties
            in_val{1} = Validate.TYPE;
            in_val{2} = Validate.CELL_PERMITTED;
            in_val{3} = Validate.MIN_VAL;
            in_val{4} = Validate.MAX_VAL;
            in_val{5} = Validate.MIN_LEN;
            in_val{6} = Validate.MAX_LEN;

            % Override the default properties according to varargin
            propertyArgIn = varargin;
            while length(propertyArgIn) >= 2,
                prop = propertyArgIn{1};
                val = propertyArgIn{2};

                idx = strmatch(lower(prop),lower(in_prop),'exact');
                if isempty(idx)
                    warning('%s.%s not sure how to handle property %s',...
                        mfilename,'assemble_vargs',prop) %#ok<WNTAG>
                else
                    in_val{idx} = val; %#ok<AGROW>
                end
                propertyArgIn = propertyArgIn(3:end);
            end
            [type,Cell,MinVal,MaxVal,MinLen,MaxLen] = deal(...
                in_val{1},in_val{2},in_val{3},in_val{4},in_val{5},in_val{6});
        end
        function valid_flag = check_type(in,type,cell_permitted,min_len)
            valid_flag = false;
            % Use min_len to determine if empty is acceptable
            if isempty(in) && min_len == 0
                valid_flag = true;
            else
                is_cell = iscell(in);
                if is_cell
                    if cell_permitted
                        valid_flag = all(all(cell2mat(cellfun(@(x) isa(x,type),in,'uniformoutput',false))));
                    else
                        return;
                    end
                end
                if isa(in,type)
                    valid_flag = true;
                end
            end
        end
        function valid_flag = check_size(in,min_limit,max_limit,cell_permitted)
            valid_flag = false;
            is_cell = iscell(in);
            if isempty(in)
                the_lengths = 0;
            elseif is_cell
                if cell_permitted
                    % size limits pertain to cell elements
                    the_lengths = cell2mat(cellfun(@(x) length(x(:)),in,'uniformoutput',false));
                else
                    return;
                end
            else
                the_lengths = length(in(:));
            end
            if (min(min(the_lengths)) >= min_limit) && (max(max(the_lengths)) <= max_limit)
                valid_flag = true;
            end
        end
        function valid_flag = check_val(in,min_limit,max_limit,cell_permitted)
            valid_flag = false;
            is_cell = iscell(in);
            if is_cell
                if cell_permitted
                    % value limits pertain to cell elements
                    the_mins = min(min(cell2mat(cellfun(@(x) min(min(x)),in,'uniformoutput',false))));
                    the_maxs = max(max(cell2mat(cellfun(@(x) max(max(x)),in,'uniformoutput',false))));
                else
                    return;
                end
            else
                the_mins = min(min(in));
                the_maxs = max(max(in));
            end
            if isempty(in) || ((min(the_mins) >= min_limit) && (max(the_maxs) <= max_limit))
                valid_flag = true;
            end
        end
        function valid_flag = check_int(in,cell_permitted)
            valid_flag = false;
            is_cell = iscell(in);
            if is_cell
                if cell_permitted
                    % values pertain to cell elements
                    is_int = call2mat(cellfun(@(x) round(x)==x,in,'uniformoutput',false));
                else
                    return;
                end
            else
                is_int = round(in)==in;
            end
            if all(all(is_int))
                valid_flag = true;
            end
        end
    end
end