## Copyright (C) 2013 Carnë Draug ## ## This file is part of Octave. ## ## Octave is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## Octave is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} validateattributes (@var{A}, @var{classes}, @var{attributes}) ## @deftypefnx {Function File} {} validateattributes (@var{A}, @var{classes}, @var{attributes}, @var{arg_idx}) ## @deftypefnx {Function File} {} validateattributes (@var{A}, @var{classes}, @var{attributes}, @var{func_name}) ## @deftypefnx {Function File} {} validateattributes (@var{A}, @var{classes}, @var{attributes}, @var{func_name}, @var{arg_name}) ## @deftypefnx {Function File} {} validateattributes (@var{A}, @var{classes}, @var{attributes}, @var{func_name}, @var{arg_name}, @var{arg_idx}) ## Check validity of input argument. ## ## Confirms that the argument @var{A} is valid by belonging to one of ## @var{classes}, and holding all of the @var{attributes}. If it does not, ## an error is thrown, with a message formatted accordingly. The error ## message can be made further complete by the function name @var{fun_name}, ## the argument name @var{arg_name}, and its position in the input ## @var{arg_idx}. ## ## @seealso{nargin, varargin, isa, validatestring} ## @end deftypefn function validateattributes (A, cls, attr, varargin) if (nargin < 3 || nargin > 6) print_usage (); elseif (! iscellstr (cls)) error ("validateattributes: CLASSES must be a cell array of strings"); elseif (! iscell (attr)) error ("validateattributes: ATTRIBUTES must be a cell array"); endif ## Built start of error message from the extra optional arguments func_name = ""; var_name = "input"; if (nargin > 3) fourth = varargin{1}; if (nargin == 4 && valid_arg_idx (fourth)) var_name = sprintf ("input %d", fourth); elseif (ischar (fourth)) func_name = [fourth ": "]; else error ("validateattributes: 4th input argument must be ARG_IDX or FUNC_NAME"); endif if (nargin > 4) var_name = varargin{2}; if (! ischar (var_name)) error ("validateattributes: VAR_NAME must be a string"); endif endif if (nargin > 5) arg_idx = varargin{3}; if (! valid_arg_idx (arg_idx)) error ("validateattributes: ARG_IDX must be a positive integer"); endif var_name = sprintf ("%s (argument #%i)", var_name, arg_idx); endif endif err_ini = [func_name var_name]; check_cl = cellfun (@(x) isa (A, x), tolower (cls)); if (! any (check_cl)) numeric = { "int8" "int16" "int32" "int64" ... "uint8" "uint16" "uint32" "uint64" ... "single" "double"}; num_pos = strcmpi (cls, "numeric"); if (any (num_pos)) ## We need to actually replace the numeric with the long list of ## types because isa does not deal well with the numeric option ## when taking a cell array of classes. cls(num_pos) = []; cls(end+1:end+numel(numeric)) = numeric; endif classes = sprintf (" %s", cls{:}); error ("%s must be of class:\n\n %s\n\nbut was of class %s", err_ini, classes, cl); endif ## We use a while loop because some attributes require to check ## the next value in the cell array. Also, we can't just get the ## boolean value for the test and check at the end the error ## message since idx = 1; problem = false; while (idx < numel (attr)) switch (tolower (attr{idx++})) case "2d", problem = ndims (A) != 2; case "3d", problem = ndims (A) != 3; case "column", problem = ! iscolumn (A); case "row", problem = ! isrow (A); case "scalar", problem = ! isscalar (A); case "vector", problem = ! isvector (A); case "square", problem = ! issquare (A); case "nonempty", problem = isempty (A); case "nonsparse", problem = issparse (A); case "binary", problem = ! all ((A(:) == 1) | (A(:) == 0)); case "even", problem = any (rem (A(:), 2) != 0); case "odd", problem = any (mod (A(:), 2) != 1); case "integer", problem = any (ceil (A(:)) != A(:)); case "real", problem = ! isreal (A); case "finite", problem = ! any (isfinite (A(:))); case "nonnan", problem = any (isnan (A(:))); case "nonnegative", problem = any (A(:) < 0); case "nonzero", problem = any (A(:) == 0); case "positive", problem = any (A(:) <= 0); case "decreasing", problem = (any (isnan (A(:))) || any (diff (A(:)) >= 0)); case "increasing", problem = (any (isnan (A(:))) || any (diff (A(:)) <= 0)); case "nondecreasing", problem = (any (isnan (A(:))) || any (diff (A(:)) > 0)); case "nonincreasing", problem = (any (isnan (A(:))) || any (diff (A(:)) < 0)); case "size", A_size = size (A); w_size = attr{idx++}; A_size(isnan (w_size)) = NaN; if (! isequaln (A_size, w_size)) A_size_str = sprintf ("%dx", size (A))(1:end-1); w_size_str = sprintf ("%ix", w_size)(1:end-1); w_size_str = strrep (w_size_str, "NaN", "N"); error ("%s must be of size %s but was %s", err_ini, w_size_str, A_size_str); endif case "numel", if (numel (A) != attr{idx++}) error ("%s must have %d elements", err_ini, attr{idx-1}); endif case "ncols", if (columns (A) != attr{idx++}) error ("%s must have %d columns", err_ini, attr{idx-1}); endif case "nrows", if (rows (A) != attr{idx++}) error ("%s must have %d rows", err_ini, attr{idx-1}); endif case "ndims", if (ndims (A) != attr{idx++}) error ("%s must have %d dimensions", err_ini, attr{idx-1}); endif case ">" if (! all (A(:) > attr{idx-1})) error ("%s must be greater than %f", err_ini, attr{idx-1}); endif case ">=" if (! all (A(:) >= attr{idx-1})) error ("%s must be greater than or equal to %f", err_ini, attr{idx-1}); endif case "<" if (! all (A(:) < attr{idx-1})) error ("%s must be less than %f", err_ini, attr{idx-1}); endif case "<=" if (! all (A(:) <= attr{idx-1})) error ("%s must be less than or equal to %f", err_ini, attr{idx-1}); endif otherwise error ("validateattributes: unknown ATTRIBUTE %s", attr{idx}); endswitch if (problem) error ("%s must be %s", err_ini, attr{idx}); endif endwhile endfunction function retval = valid_arg_idx (arg) retval = isnumeric (arg) && isscalar (arg) && arg > 0 && ceil (arg) == arg; endfunction