How to parse optional inputs in MATLAB? - 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 :)

Related

Summation of N function handles in MATLAB

I have N functions in MATLAB and I can define them using strcat, num2str and eval in a for loop. So without defining by hand I am able to define N functions. Let N=4 and let them be given as follows:
f1=#(x) a1*x+1;
f2=#(x) a2*x+1;
f3=#(x) a3*x+1;
f4=#(x) a4*x+1;
Now I add these four functions and I can do this by hand as follows:
f=#(x)(f1(x)+f2(x)+f3(x)+f4(x));
Here I can do it by hand because I know that N=4. However, in general I never know how many functions I will have. For all cases I cannot write a new function.
Is there any way to do this automatically? I mean if I give N=6 I am expecting to see MATLAB giving me this:
f=#(x)(f1(x)+f2(x)+f3(x)+f4(x)+f5(x)+f6(x));
Whenever I give N=2 then I must have the function f, defined as follows:
f=#(x)(f1(x)+f2(x));
How can we do this?
First of all, you should read this answer that gives a series of reasons to avoid the use of eval. There are very few occasions where eval is necessary, in all other cases it just complicates things. In this case, you use to dynamically generate variable names, which is considered a very bad practice. As detailed in the linked answer and in further writings linked in that answer, dynamic variable names make the code harder to read, harder to maintain, and slower to execute in MATLAB.
So, instead of defining functions f1, f2, f3, ... fN, what you do is define functions f{1}, f{2}, f{3}, ... f{N}. That is, f is a cell array where each element is an anonymous function (or any other function handle).
For example, instead of
f1=#(x) a1*x+1;
f2=#(x) a2*x+1;
f3=#(x) a3*x+1;
f4=#(x) a4*x+1;
you do
N = 4;
a = [4.5, 3.4, 7.1, 2.1];
f = cell(N,1);
for ii=1:N
f{ii} = #(x) a(ii) * x + 1;
end
With these changes, we can easily answer the question. We can now write a function that outputs the sum of the functions in f:
function y = sum_of_functions(f,x)
y = 0;
for ii=1:numel(f)
y = y + f{ii}(x);
end
end
You can put this in a file called sum_of_functions.m, or you can put it at the end of your function file or script file, it doesn't matter. Now, in your code, when you want to evaluate y = f1(x) + f2(x) + f3(x)..., what you write is y = sum_of_functions(f,x).

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
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

Specify at function declaration that it should be applied to invidual arguments

Is it possible in Matlab to specify at function declaration that this specific function is to be applied to indiviual arguments (as opposed to vectors)? An if so, what about anonymous functions?
What I mean is, instead of writing something like
f = #(x, y) x.^2+2*x.*y.^2-x./(y.^3)...
One might be able to write something like
f = .#(x, y) x^2+2*x*y^2-x/y^3
This would help a lot light-headed people like me who tend to forget dots.
Sorry if it's a duplicate, I searched but as you can see I have trouble putting it in clear words so I cannot find an answer.
not sure if that does the trick for you, but you can but an arrayfun inside the anonymous function like:
f = #(x,y) x.^2+2*x.*y.^2-x./(y.^3);
g = #(x,y) arrayfun(#(A,B) A^2+2*A*B^2-A/B^3 ,x,y) %for matrix output
h = #(x,y) arrayfun(#(A,B) A^2+2*A*B^2-A/B^3 ,x,y,'UniformOutput',false); % for cell output
with A being an element of x and B being an element of y

Is it possible to use an anonymous function as an event-function when solving an ODE in Matlab

Is it possible to use an anonymous function as an event function in Matlab. What I want to do is basically
opt = odeset('Events', #(t,y) (deal(y(end)-t^2,1,0)));
[T,Y] = ode45(#odefun,[tstart tend],y0,opt);
However, this returns an error complaining that the number of outputs to deal must be matched exactly. Is there some other way to make the anonymous function return multiple arguments?
I noticed this post looking for the answer to the same question. This means that for some people the question may be still valid. Since finally I found the solution by myself, I'd like to give a little bit "outdated" answer.
Actually, yes - it's possible but not straightforward. Try this:
evnt_fun = #(t, f)subsref({'some stop condition', 1, 0}, struct('type', '{}', 'subs', {{':'}}));
I'm not able to fully check the backward-compatibility of the code. However, it works with R2011 and later MATLAB versions.
No, you can't do it. Anonymous functions in Matlab only ever return one value.
Instead, you could define a thin wrapper around deal and pass your wrapper as a handle:
function [a b c] = wrapper(t,y)
[a b c] = deal('some stop condition', 1, 0);
end
opt = odeset('Events', #wrapper);
[T, Y] = ode45(#odefun, [tstart tend], y0, opt);
Also (this is very late in the game to be adding to this, but this frustrates me). Here is a solution with nested functions:
function [ dealfunchandle ] = dealwithit( arrayfunc )
% Takes as input an event function of (t,z) that returns a 3 array (in same order as event syntax).
function [a, b, c] = dealfunc(t,z)
output = arrayfunc(t,z);
a = output(:,1);
b = output(:,2);
c = output(:,3);
end
dealfunchandle = #dealfunc;
end
This function only has to be written once (handy if you have to use lots of different event functions). This can be used to generate an anonymous event function within the code as follows:
arrayfunc = #(t,y) [y(1), 0, 1];
events = dealwithit(arrayfunc);
opts = odeset('Events', events);
And then ode45 as per normal.

MATLAB Function (Solving an Error)

I have one file with the following code:
function fx=ff(x)
fx=x;
I have another file with the following code:
function g = LaplaceTransform(s,N)
g = ff(x)*exp(-s*x);
a=0;
b=1;
If=0;
h=(b-a)/N;
If=If+g(a)*h/2+g(b)*h/2;
for i=1:(N-1)
If=If+g(a+h*i)*h;
end;
If
Whenever I run the second file, I get the following error:
Undefined function or variable 'x'.
What I am trying to do is integrate the function g between 0 and 1 using trapezoidal approximations. However, I am unsure how to deal with x and that is clearly causing problems as can be seen with the error.
Any help would be great. Thanks.
Looks like what you're trying to do is create a function in the variable g. That is, you want the first line to mean,
"Let g(x) be a function that is calculated like this: ff(x)*exp(-s*x)",
rather than
"calculate the value of ff(x)*exp(-s*x) and put the result in g".
Solution
You can create a subfunction for this
function result = g(x)
result = ff(x) * exp(-s * x);
end
Or you can create an anonymous function
g = #(x) ff(x) * exp(-s * x);
Then you can use g(a), g(b), etc to calculate what you want.
You can also use the TRAPZ function to perform trapezoidal numerical integration. Here is an example:
%# parameters
a = 0; b = 1;
N = 100; s = 1;
f = #(x) x;
%# integration
X = linspace(a,b,N);
Y = f(X).*exp(-s*X);
If = trapz(X,Y) %# value returned: 0.26423
%# plot
area(X,Y, 'FaceColor',[.5 .8 .9], 'EdgeColor','b', 'LineWidth',2)
grid on, set(gca, 'Layer','top', 'XLim',[a-0.5 b+0.5])
title('$\int_0^1 f(x) e^{-sx} \,dx$', 'Interpreter','latex', 'FontSize',14)
The error message here is about as self-explanatory as it gets. You aren't defining a variable called x, so when you reference it on the first line of your function, MATLAB doesn't know what to use. You need to either define it in the function before referencing it, pass it into the function, or define it somewhere further up the stack so that it will be accessible when you call LaplaceTransform.
Since you're trying to numerically integrate with respect to x, I'm guessing you want x to take on values evenly spaced on your domain [0,1]. You could accomplish this using e.g.
x = linspace(a,b,N);
EDIT: There are a couple of other problems here: first, when you define g, you need to use .* instead of * to multiply the elements in the arrays (by default MATLAB interprets multiplication as matrix multiplication). Second, your calls g(a) and g(b) are treating g as a function instead of as an array of function values. This is something that takes some getting used to in MATLAB; instead of g(a), you really want the first element of the vector g, which is given by g(1). Similarly, instead of g(b), you want the last element of g, which is given by g(length(g)) or g(end). If this doesn't make sense, I'd suggest looking at a basic MATLAB tutorial to get a handle on how vectors and functions are used.