Is there a good way to validate that all inputs to a function have compatible sizes when using a (Repeating) arguments block?
19 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
Matthew Dvorsky
el 7 de Nov. de 2022
Editada: Matthew Dvorsky
el 18 de Nov. de 2022
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 comentario
chrisw23
el 8 de Nov. de 2022
The Repeating attribute will only work if you really have repeating arguments like
multiArrayOperation2(Arrays,Arrays,Arrays)
arguments (Repeating)
Respuesta aceptada
Andrew Ouellette
el 10 de Nov. de 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
Más respuestas (0)
Ver también
Categorías
Más información sobre Loops and Conditional Statements en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!