Is there a good way to validate that all inputs to a function have compatible sizes when using a (Repeating) arguments block?

36 views (last 30 days)
Setup
Let's say I have some function that a number of arrays as an input and does something with them that requires the arrays to have compatible sizes (i.e., to have the same sizes after implicit singleton dimension expansion). I have written a function "mustBeCompatibleSize" that throws an error if it's arguments have incompatible sizes. This works as expected. It correctly points out which argument is causing the error to the user.
function multiArrayOperation1(Array1, Array2, Array3)
arguments
Array1;
Array2 {mustBeCompatibleSize(Array1, Array2)};
Array3 {mustBeCompatibleSize(Array1, Array2, Array3)};
end
% Do something with Array1, Array2, and Array3.
end
For example, calling the following will result in MATLAB telling the user that the 3rd argument was not compatible with previous arguments.
multiArrayOperation1(ones(5, 1), ones(1, 5), ones(5, 6))
I'm adding the validation function for completeness.
function [] = mustHaveCompatibleSizes(Arrays)
arguments (Repeating)
Arrays;
end
maxInputDim = max(cellfun(@(x) ndims(x), Arrays));
inputDims = cell2mat(cellfun(@(x) size(x, 1:maxInputDim).', Arrays, UniformOutput=false)).';
outputDims = max(inputDims, [], 1);
isMismatch = any((inputDims ~= outputDims) & (inputDims ~= 1), 1);
if any(isMismatch)
throwAsCaller(MException("MATLAB:mustHaveCompatibleSizes", ...
"Invalid argument at position %d. Arguments must have compatible sizes", ...
find(isMismatch, 1)));
end
end
Issue
The issue comes about when I want to make a function that accepts any number of input arrays, using the (Repeating) arguments block, like in the example below. This example does not work, as the argument validator passes only one element at a time into the "mustBeCompatibleSize" function, and thus no error is thrown.
function multiArrayOperation2(Arrays)
arguments (Repeating)
Arrays {mustBeCompatibleSize};
end
% Do something with Arrays.
end
Calling the following does not result in an error being thrown.
multiArrayOperation2(ones(5, 1), ones(1, 5), ones(5, 6))
Nonoptimal Solution
Of course, we can just call the validation function manually after the arguments block. However, this does not display to the user which argument is causing the error as it does in the first example, and doesn't really utilize the arguments block for validation.
function multiArrayOperation3(Arrays)
arguments (Repeating)
Arrays;
end
mustBeCompatibleSize(Arrays{:});
% Do something with Arrays.
end
While the following code throws an error as it should, the user is not informed which specific argument is causing the error.
multiArrayOperation3(ones(5, 1), ones(1, 5), ones(5, 6))
Question
Is there a better solution to this issue? Hopefully, there is a way to implement something similar to the second example.
  1 Comment
chrisw23
chrisw23 on 8 Nov 2022
The Repeating attribute will only work if you really have repeating arguments like
multiArrayOperation2(Arrays,Arrays,Arrays)
arguments (Repeating)

Sign in to comment.

Accepted Answer

Andrew Ouellette
Andrew Ouellette on 10 Nov 2022
Hi Matthew,
I was able to achieve the behavior you desire by looping through the variable arguments and passing the argument number to the check function.
function multiArrayOp(varargin)
for ii = 2:nargin
mustBeCompatibleSize(ii,varargin{1:ii})
end
end
I added an additional input before the repeating arrays so that you can tell which input is being evaluated.
function [] = mustBeCompatibleSize(nArray,Arrays)
arguments
nArray
end
arguments (Repeating)
Arrays;
end
maxInputDim = max(cellfun(@(x) ndims(x), Arrays));
inputDims = cell2mat(cellfun(@(x) size(x, 1:maxInputDim).', Arrays, UniformOutput=false)).';
outputDims = max(inputDims, [], 1);
isMismatch = any((inputDims ~= outputDims) & (inputDims ~= 1), 1);
if any(isMismatch)
msg = sprintf('Invalid argument at position %g. Arguments must have compatible sizes.',nArray);
throwAsCaller(MException("MATLAB:mustHaveCompatibleSizes", msg));
end
end
  1 Comment
Matthew Dvorsky
Matthew Dvorsky on 18 Nov 2022
Thanks for the suggestion. While this does show the argument number, it still seems like a non-ideal solution, since it doesn't show the same detail as it would when using the argument block validation directly (e.g., it doesn't show the line of calling code with an arrow pointing to the argument causing the error).
I'm guessing there's no way to get this behavior using the arguments block directly as of MATLAB R2022a.

Sign in to comment.

More Answers (0)

Products


Release

R2022a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!