Ben
Ben

Reputation: 375

Best practice for validation of two related inputs in Matlab

I have a question about the best practices for input validation in Matlab functions with multiple inputs. It's a bit philosophical. I've looked around in the forum and I have not seen a comprehensive discussion of this. I care about the case where the validation conditions involves two or more of the input variables. Here is an example.

Suppose that I write a function with two inputs, a and b. I know that the inputs must satisfy the conditions

a > 0 and b > 0.

If I want to validate these inputs, I would normally write a function like this (just for illustration purposes, what the function does is not important):

% My function
function [result] = myLogSum(a,b)

% Create an input parser
p = inputParser;
% Add required inputs with validation
isPositive = @(x) all(x>0);
addRequired(p, 'a', isPositive);
addRequired(p, 'b', isPositive);
% Parse the inputs
parse(p,a,b);

% Calculate the log sum
result = log(a) + log(b);

end

But now suppose that a and b are arrays, and that I also need to check if they are the same size:

all(size(a) == size(b)) == true.

Is there a way to deal with such a situation with the input parser? If not, what is the best way to deal with this?

I can think of four solutions, but I can't figure out which is the best.

1) Should I lump a and b in a single input cell array variable sumInput of the form {a,b} and write a custom validation function for the cell array? That's fine, but I don't know if it's always good practice to lump inputs together like that. Here it seems very natural to be able to write myLogSum(a,b) instead of myLogSum(sumInput).

2) Or in such instances, should I write this part of the input validation in the function, i.e., modify the above code like this:

% My function
function [result] = myLogSum(a,b)

% Create an input parser
p = inputParser;
% Add required inputs with validation
isPositive = @(x) all(x>0);
addRequired(p, 'a', isPositive);
addRequired(p, 'b', isPositive);
% Parse the inputs
parse(p,a,b);

% Check that the input arrays have the same size
if ~all(size(a)==size(b))
   message = 'The arrays a and b must have the same size.';
   error(message);
end

% Calculate the log sum
result = log(a) + log(b);

end

That's fine too, but it makes the validation a bit inhomogeneous and inaesthetic because now I the inputs a and b are validated twice in different ways and for different reasons.

3) Should I just give up on the input parser and just write my own validation functions, as is suggested here:

Best practice when validating input in MATLAB

But I quite like the input parser because it's a neat way to manage options.

4) I could just let Matlab handle the error by itself when the program reaches the last line result = log(a) + log(b) and the array sizes don't match. But somehow I feel like this is asking for trouble in the long run.

If you have experience in Matlab, just let me know what you think is the most robust and comprehensive validation strategy when the two inputs are related.

Ben

Upvotes: 4

Views: 603

Answers (2)

Ben
Ben

Reputation: 375

As of Matlab 2019b, I would recommend the use of the arguments validation block:

https://de.mathworks.com/help/matlab/ref/arguments.html?searchHighlight=arguments&s_tid=srchtitle

It still has some limitations, but overall it is still quite versatile. It forces some uniformity in validation.

% My function
function result = myLogSum(a,b)

% Arguments validation block
arguments
    a;
    b {mustBeEqualSize(a,b)};
end

% Calculate the log sum
result = log(a) + log(b);

end

function mustBeEqualSize(a,b)
% Test for equal size
if ~isequal(size(a),size(b))
    eid = 'mustBeEqualSize:sizesNotEqual';
    msg = 'Size of first input must equal size of second input.';
    throwAsCaller(MException(eid,msg))
end
end

Upvotes: 1

nekomatic
nekomatic

Reputation: 6284

There's nothing to stop you from calling parse once, then adding new inputs and calling parse again - at which point you can use the previously parsed value(s) in your validation function. The validateattributes function is useful here for building validation functions with multiple conditions. For example:

% My function
function [result] = myLogSum(a,b)

% Create an input parser
p = inputParser;
% Add required inputs with validation
addRequired(p, 'a', @(x) validateattributes(x, {'numeric'}, {'>', 0}));
% Check the first input was valid
p.parse(a);
addRequired(p, 'b', @(x) validateattributes(x, {'numeric'}, {'>', 0, 'size', size(a)}));
% Parse the inputs
p.parse(a,b);

% Calculate the log sum
result = log(a) + log(b);

end

validateattributes also generates reasonably explanatory error messages for you:

>> myLogSum(30, 40)

ans =

    7.0901

>> myLogSum([30 20], 40)
Error using myLogSum (line 12)
The value of 'b' is invalid. Expected input to be of size 1x2 when it is
actually size 1x1.

>> myLogSum([30 20], [40 1])

ans =

    7.0901    2.9957

>> myLogSum([30 20], [40 -1])
Error using myLogSum (line 12)
The value of 'b' is invalid. Expected input to be an array with all of the
values > 0.

Upvotes: 4

Related Questions