Best practice for validation of two related inputs in Matlab - 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

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.

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

Related

How to parse optional inputs in MATLAB?

I think inputparser is doing that, but I couldn't find an example that shows how.
In my function, I define a struct named opts which contain the parameters that control the function. Example :
function y = f(x, extraOpts)
opts= struct( ...
'N', 100, ...
'visualize', 1, ... % etc
);
do_things(x, opts);
end
Fields of opts have default values, but I want to be able to change them selectively. So I want to call the function with something like this:
f(x, {'visualize', 0});
in which case .N remains 100 but .visualize becomes 0.
How can I achieve this with MATLAB? Also not sure if it will require the extraOpts parameter. I would of course prefer a way with function y = f(x) :)
Thanks for any help !
You can use MATLAB's inputParser class:
http://www.mathworks.com/help/matlab/ref/inputparser-class.html
http://blogs.mathworks.com/community/2012/02/13/parsing-inputs/
EDIT: I guess I'll just put the code in as well...
function y = f(x, extraOpts)
p = inputParser;
p.addRequired('x', #(x) length(x)>1);
p.addOptional('visualize', 1, #isscalar);
p.addOptional('N', 100, #isscalar);
p.parse(x, extraOpts{:});
do_things(x, extraOpts);
end
You might need to store the results of the parse, perhaps something along the lines of:
inputs = p.parse(x, extraOpts{:});
do_things(inputs)
END EDIT
Alternatively, you could do something like redefine your function to take the number of values in your struct though it's not as powerful as the input parser solution:
function y = f(N, visualize)
if nargin < 2
visualize = 0
end
if nargin < 1
visualize = 0
N = 100
end
I couldn't make the answer work, but I found another solution with inputParser, let me paste here for future reference :
function y = f2(extraOpts)
p = inputParser;
p.addParamValue('par1', 'defaultValue1');
p.addParamValue('par2', def2, #isnumeric);
p.addParamValue('par3', def3, #isnumeric);
p.parse(extraOpts{:});
extraOpts = p.Results;
end
the drawback is that I needed to separate the two inputs x and extraOpts and had to call f2 as a subroutine, defined in the same file as f. Maybe there is a more elegant way for this (i.e. one that does not require another function), but the example I have seen was also doing like that, and since it works, it's good for me :)

MATLAB: passing two arguments to nlfilter using a handle

I am trying to provide two parameters to the fun argument of nlfilter function. I would like to do this by using a handle to the function assign_value I created. This is my function:
function y = assign_value(x, ii)
index= x([1 2 3 4 6 7 8 9]);
if ismember(ii, index)==1
x(5)= ii; % 'ii' is the cloud object ID
end
y=x;
end
I already red some MATLAB documentation (e.g. 1, 2, 3), and saw some answers (4, 5, etc.), but I still would need a help to solve my specific problem in order to understand how handles to functions work.
Here is what I'm trying to do (x is a 9by9 double-class matrix)
ii= 127
y= nlfilter(x, [3 3], #assign_value)
The error I get is:
??? Subscripted assignment dimension mismatch.
Error in ==> nlfilter at 75
b(i,j) = feval(fun,x,params{:});
Any help would be really appreciated, thanks in advance.
ANSWER
Thanks to Acorbe comments,I finally make it. As my y output of assign_value function was an array, and the fun parameter of nlfilter has to output only scalars, I changed my function to:
function y = assign_value(x, ii)
index= x([1 2 3 4 6 7 8 9]);
if ismember(ii, index)==1
x(5)= ii; % 'ii' is the cloud object ID
end
y=x(5);
end
And doing:
y= nlfilter(x, [3 3], #(x) assign_value(x, ii));
my result is fine.
Thanks again to Acorbe for his precious contribution.
If I understand your question correctly you want to produce a one-variable version of your function assign_value parametrized by the value of ii. This function will operate the local filtering procedure when called by nlfilter.
Function handles as you were saying can help; specifically you can define
my_ii = 127;
assign_value_parametric = #(x) assign_value(x,my_ii);
and use it as
y= nlfilter(x, [3 3], assign_value_parametric).
The lambda function assign_value_parametric depends upon one single dependent variable (x) since the parameter ii has been fixed once and for all.
In general, consider that this allows a remarkable series of mechanisms.
In particular when you return the function handle outside the function where it has been defined, the parameters it depends upon are automatically shadowed, nonetheless, they are implicitly used when the function handle is called.
EDIT: further comments on your filtering kernel and on the error you get.
I am afraid the kernel you designed does not produce the behavior you need. Consider that a kernel should return a scalar value which is the filter output at point x of a given filtering window around x. In your case you are always returning the original filtering window, possibly with a value changed.

defining different cases for function im matlab (symfun)

i want to create a function (symfun), and i want to divide it to cases, i.e if t> then then answer will be a and if t<0 the answer will be b.
the thing is, that matlab wont allow me to put an if statements after a sym function.
>> l = symfun(0, [m]);
>> l(m) = if m>0 3
also i tried to create a function:
function [x1] = xt_otot_q3(t)
and tried to connect between the two functions:
>> l(m) = xt_otot_q3(m)
Conversion to logical from sym is not possible.
is there any way to break a symfun into cases?
Not sure that I understand what you want.
This code 'combines' the functions symfun and xt+otot_q3 defined below:
function test;
m=randn(4); % N(0,1) random numbers
l=xtotot_q3(symfun(0,m)) % combine xt_otot_q3 and symfun
l=symfun(0,xtotot_q3(m)) % combine symfun and xt_otot_q3
return
function lval=symfun(thr,rval);
lval=ones(size(rval)); % output, size of input, = 1
lval(rval<thr)=-1; % output = -1 if input < thr
return
function lval=xtotot_q3(rval);
lval=3*rval+1; % some function, in this case 3 * input + 1
return
You can save the whole bit as test.m and then call test from the matlab prompt. Maybe if you start with this then you can modify it to fit your needs.

Is there a Matlab conditional IF operator that can be placed INLINE like VBA's IIF

In VBA I can do the following:
A = B + IIF(C>0, C, 0)
so that if C>0 I get A=B+C and C<=0 I get A=B
Is there an operator or function that will let me do these conditionals inline in MATLAB code?
How about simply using the fact that MATLAB automatically converts variable types when required by the operation? E.g., logical to double.
If your variables are scalar double, your code, I believe, can be replaced by
a = b + (c > 0) * c;
In this case, the operator (c > 0) values 1 (logical type) whenever c > 0 and values to 0 otherwise.
There is no ternary operator in Matlab. You can, of course, write a function that would do it. For example, the following function works as iif with n-d input for the condition, and with numbers and cells for the outcomes a and b:
function out = iif(cond,a,b)
%IIF implements a ternary operator
% pre-assign out
out = repmat(b,size(cond));
out(cond) = a;
For a more advanced solution, there's a way to create an inline function that can even do elseif, as outlined in this blog post about anonymous function shenanigans:
iif = #(varargin) varargin{2*find([varargin{1:2:end}], 1, 'first')}();
You use this function as
iif(condition_1,value_1,...,true,value_final)
where you replace the dots with any number of additional condition/value pairs.
The way this works is that it picks among the values the first one whose condition is true. 2*find(),1,'first') provides the index into the value arguments.
There is no built-in solution for this, but you can write an IIF yourself.
function result=iif(cond, t, f)
%IIF - Conditional function that returns T or F, depending of condition COND
%
% Detailed
% Conditional matrix or scalar double function that returns a matrix
% of same size than COND, with T or F depending of COND boolean evaluation
% if T or/and F has the same dimensions than COND, it uses the corresponding
% element in the assignment
% if COND is scalar, returns T or F in according with COND evaluation,
% even if T or F is matrices like char array.
%
% Syntax
% Result = iif(COND, T, F)
% COND - Matrix or scalar condition
% T - expression if COND is true
% F - expression if COND is false
% Result - Matrix or scalar of same dimensions than COND, containing
% T if COND element is true or F if COND element is false.
%
if isscalar(cond)
if cond
result = t;
else
result = f;
end
else
result = (cond).*t + (~cond).*f;
end
end
Others have said already that there is no ternary ?: operator in Matlab. As a solution I suggest this function, which takes three functions instead of values. Therefore the amount of unnecessary calculations is minimized and you can check conditions before starting calculations, e.g. if a value is really numeric, or finite, or nonzero:
function [ out ] = iif( condition, thenF, elseF, in, out)
%iif Implements the ternary ?: operator
% out = iif (#condition, #thenF, #elseF, in[, out])
%
% The result is equivalent to:
% condition(x) ? thenF(x) : elseF(x)
%
% The optional argument out serves as a template, if the output type is
% different from the input type, e.g. for mapping arrays to cells and
% vice versa.
%
% This code is in the public domain.
mask = condition(in);
if nargin <= 4
out = in;
end
if sum(mask)
out(mask) = thenF(in(mask));
end
if sum(~mask)
out(~mask) = elseF(in(~mask));
end
end
Use it like this:
f = #(y)(iif(#(x)(x > 3), #(x)(x.^2), #(x)(x/2), y))
f(linspace(0,6,10))
Inspired by Jonas' answer the function below also works for mixed type input and chars, for which his function isn't stable.
function out = iif(cond, a, b)
%IIF implements a ternary operator
% Use cell output for either char or mixed type input
if ischar(a) || ischar(b) || ~strcmp(class(a), class(b))
out = cell(size(cond));
[out{cond}] = deal(a);
[out{~cond}] = deal(b);
else
% Use array output and logical indexing
out = repmat(b, size(cond));
out(cond) = a;
end
end
Edit: weeded out the extra conditional options in the cell branch, which were apparently remnants of a previous mistake, this is probably faster, and definitely cleaner.
What you refer to is a ternary operator, in C-like notation, ?:. The expression
tern = bool ? T : F
returns T if bool evaluates to true, F otherwise. MATLAB has no ternary operator, however it can be implemented in different ways as an inline expression.
Arrays
% cell array version (any type)
tern = {F,T}{bool+1} % only Octave
tern = subsref({F,T}, struct('type', '{}', 'subs', {{bool+1}}))
% vector array version (numeric types only)
tern = [F,T](bool+1) % only Octave
tern = subsref([F,T], struct('type', '()', 'subs', {{bool+1}}))
Note that T and F have been swapped, and that different brackets are used. The vector array version is a specialization for numeric types. MATLAB does not allow direct indexation of fresh arrays, hence the use of subsref.
Pros: Works for any type and any value. Can be used inline.
Cons: Before returning the result to tern, both T and F
are evaluated.
Logical operators and eval
( bool && eval('tern=T') ) || eval('tern=F')
Note that the logical operators are short-circuited.
Pros: Works for any type and any value. Only one, T or F, is evaluated.
Cons: Works only in Octave. Can't be used inline, but through the variable tern. eval is not efficient but required.
Basic arithmetic
tern = bool*T + !bool*F
Pros: Can be used inline.
Cons: Works only for numeric types, and might fail when T or F are NaN or Inf. Both, T and F, are evaluated.
Maximum
tern = max(T,F) % bool = T>F
Note that this solution fits the particular requirements of the initial question with max(C,0).
Pros: Can be used inline.
Cons: Works only for numeric types, and might fail when T or F are NaN. Both, T and F, are evaluated. Use is strongly limited.
There is now a tern function on the MathWorks file exchange:
http://www.mathworks.com/matlabcentral/fileexchange/39735-functional-programming-constructs/content/tern.m
The code is reproduced here:
function varargout = tern(condition, true_action, false_action)
% out = tern(condition, true_action, false_action)
%
% Ternary operator. If the first input is true, it returns the second
% input. Otherwise, it returns the third input. This is useful for writing
% compact functions and especially anonymous functions. Note that, like
% many other languages, if the condition is true, not only is the false
% condition not returned, it isn't even executed. Likewise, if the
% condition is false, the true action is never executed. The second and
% third arguments can therefore be function handles or values.
%
% Example:
%
% >> tern(rand < 0.5, #() fprintf('hi\n'), pi)
% ans =
% 3.1416
% >> tern(rand < 0.5, #() fprintf('hi\n'), pi)
% hi
%
% It works with multiple outputs as well.
%
% >> [min_or_max, index] = tern(rand < 0.5, ...
% #() min([4 3 5]), ...
% #() max([4 3 5]))
% min_or_max =
% 5
% index =
% 3
%
% Tucker McClure
% Copyright 2013 The MathWorks, Inc.
if condition() % Works for either a value or function handle.
[varargout{1:nargout}] = true_action();
else
[varargout{1:nargout}] = false_action();
end
end
This is more of an addenum to Alex's answer.
Alex's method doesn't work when you want to return inf
In these cases you often end up getting a 0*inf figure, which MATLAB will evaluate to NaN. Problematic... We can avoid this multiplication using a lookup instead.
As an example, a useful barrier function in convex optimization is something that behaves like log everywhere positive, and -inf elsewhere. Here is how you might create such a function using a lookup:
INF_CONDITION = [0, inf];
fn_logbr = #(x) (x>0)*log(x) - INF_CONDITION( 1+(x<=0) )
Inline conditionals are a hack, and you lose lazy evaluation. You have to be careful. However, having semantic code is really nice, and its easier to share your code when you can't guarantee everyone's environments are the same.
If you're looking for an option that doesn't force you to build a function and can take care fairly simple expressions, you can take advantage of anonymous functions. The anonymous function returns a logical, which can be a numeral 1 or 0. Because of this, they can be used to multiply with other numbers to determine if they still hold a value after the expression, or lose their value.
For your case (including if A, B, and C are vectors or not): A = B .+ (#() C>0)()
Using:
eval('input;', 'input = 1;');
is very helpful where 'input' might not exist in the first place.

need explanation about a matlab code snippet about moran process

I am new to Matlab. I was reading this code snippet, but in some parts (marked with asterisks) I don't understand what it means, so if anybody could help would be very much appreciated
function [A1nmb] = moran(initsize, popsize)
% MORAN generates a trajectory of a Moran type process
% which gives the number of genes of allelic type A1 in a population
% of haploid individuals that can exist in either type A1 or type A2.
% The population size is popsize and the initial number of type A1
% individuals os initsize.
% Inputs: initsize - initial number of A1 genes
% popsize - the total population size (preserved)
if (nargin==0)
initsize=10;
popsize=30;
end
A1nmb=zeros(1,popsize);
A1nmb(1)=initsize;
**lambda = inline('(x-1).*(1-(x-1)./N)', 'x', 'N');
mu = inline('(x-1).*(1-(x-1)./N)', 'x', 'N');**
x=initsize;
i=1;
while (x>1 & x<popsize+1)
if (lambda(x,popsize)/(lambda(x,popsize)+mu(x,popsize))>rand)
x=x+1;
A1nmb(i)=x;
else
x=x-1;
A1nmb(i)=x;
end;
i=i+1;
end;
nmbsteps=length(A1nmb);
***rate = lambda(A1nmb(1:nmbsteps-1),popsize) ...
+mu(A1nmb(1:nmbsteps-1),popsize);***
**jumptimes=cumsum(-log(rand(1,nmbsteps-1))./rate);**
jumptimes=[0 jumptimes];
stairs(jumptimes,A1nmb);
axis([0 jumptimes(nmbsteps) 0 popsize+1]);
The first line you marked
lambda = inline('(x-1).*(1-(x-1)./N)', 'x', 'N');
creates something called an inline function. It is equivalent to defining a mathematical function. Example:
y = inline('x^2')
would allow you to do
>> y(2)
4
This immediately explains the second line you marked.
rate = lambda(A1nmb(1:nmbsteps-1),popsize) ...
+mu(A1nmb(1:nmbsteps-1),popsize);
will compute the value of the function lambda(x,N) at x = A1nmb(1:nmbsteps-1) and N = popsize.
I will say immediately here that you should take a look at anonymous functions, a different format used to accomplish the same as inline. Only, anonymous functions are generally better supported, and usually a lot faster than inline functions.
Then, for the final line,
jumptimes = cumsum(-log(rand(1,nmbsteps-1))./rate);
is a nested command. rand will create a matrix containing pseudorandom numbers, log is the natural logarithm ("ln"), and cumsum creates a new matrix, where all the elements in the new matrix are the cumulative sum of the elements in the input matrix.
You will find the commands doc and help very useful. Try typing
doc cumsum
or
help inline
on the Matlab command prompt. Try that again with the commands forming the previous statement.
As a general word of advice: spend an insane lot of time reading through the documentation. Really, for each new command you encounter, read about it and play with it in a sandbox until you feel you understand it. Matlab only becomes powerful if you know all its commands, and there are a lot to get to know.
It defines an inline function object. For example this
lambda = inline('(x-1).*(1-(x-1)./N)', 'x', 'N')
defines lambda as a function with 2 variables. When you call lambda(A,n) Matlab simply expands the function you define in the first string. Thus lambda(A,n) using the variables you provide in the function call. lambda(A,n) would will evaluate to:
(A-1).*(1-(A-1)./n)
it just expands the function using the parameters you supply. Take a look at this link for more specific details http://www.mathworks.co.uk/help/techdoc/ref/inline.html
The cumsum function just returns the cumulative sum of a matrix along a particular dimension. Say we call cumsum on a vector X, then the value at element i in the result is equal to the sum of elements in X from index 1 to i. For example X = [1 2 1 3] we would get
AA = cumsum(X);
we would have
AA = [1 3 5 8]
See this link for more details and examples http://www.mathworks.co.uk/help/techdoc/ref/cumsum.html