I want to be able to find the parameter names of an anonymous function in Matlab.
I tried to see if there was any information about the parameter names in the functions() command, but to no avail.
Say I have an anonymous function f:
f = #(x, y) x^2 + y^2
I need to be able to find the parameter names 'x' and 'y' from this equation. Is there a built in method in Matlab which can do this? Or would I somehow have to parse the function to receive the parameter names?
The function field in the output of functions (or equivalently the output of func2str) gives the function definition as a string. You then use a regular expression to match each sequence of one or more non-), non-, characters that are between a #( or , and a , or ):
s = functions(f);
inputVarNames = regexp(s.function, '(?<=(,|#\())[^\)]+?(?=(,|\)))', 'match');
Related
It was suggested in this comment that there is a difference between how Matlab and Python pass around functions. From what I can tell by looking and using the two, there is no difference between the two, but maybe I'm missing something?
In Matlab, you would create a quick function handle like this:
fun = #(x) x.^2 + 1;
In Python, using a lambda function, you could create a similar function like this:
def fun(x):
return x^2
In both languages, it's possible to send the term 'fun' to another function as an argument - but the commenter I linked to insinuated that they are not the same and/or need to be used differently.
What am I missing?
The first comment seems to simply reiterate the idea that you can pass a MATLAB function handle as an argument (although the answer didn't state anything that would make me think otherwise). The second comment seemed to interpret this to mean that the first commenter thought that you couldn't do this in Python and responded to state that you can use either a lambda or pass the function directly.
Regardless, assuming that you use them correctly, a function handle in MATLAB is functionally equivalent to using either a lambda or function object as an input argument in Python.
In python, if you don't append the () to the end of the function, it doesn't execute the function and instead yields the function object which can then be passed to another function.
# Function which accepts a function as an input
def evalute(func, val)
# Execute the function that's passed in
return func(val)
# Standard function definition
def square_and_add(x):
return x**2 + 1
# Create a lambda function which does the same thing.
lambda_square_and_add = lambda x: x**2 + 1
# Now pass the function to another function directly
evaluate(square_and_add, 2)
# Or pass a lambda function to the other function
evaluate(lambda_square_and_add, 2)
In MATLAB, you have to use a function handle because MATLAB attempts to execute a function even if you omit the ().
function res = evaluate(func, val)
res = func(val)
end
function y = square_and_add(x)
y = x^2 + 1;
end
%// Will try to execute square_and_add with no inputs resulting in an error
evaluate(square_and_add)
%// Must use a function handle
evaluate(#square_and_add, 2)
I have a MATLAB file that contains a single top-level function, called sandbox. That function in turn contains two nested functions, mysum and myprod, which are identical in functionality and what parameters they allow except that one uses #sum internally and the other uses #prod internally. My goal is to create a wrapper function to use in both mysum and myprod that takes care of all the validation and input parsing. This function is called applyFunc.
Here's where it gets tricky. mysum and myprod come in two forms:
mysum(v) returns sum(v, 1).
mysum(v, 'imag') returns sum(v, 1) + 1i
Any other combinations of input should throw an error.
I'm having trouble using inputParser to parse these various combinations of input, specifically the optional string input. Here's the code:
function sandbox()
%% Data
v = [1 4; 3 3];
%% Calculations
s = mysum(v);
si = mysum(v, 'imag');
p = myprod(v);
pi = myprod(v, 'imag');
%% Accuracy tests
assert(isequal(s, [4 7]))
assert(isequal(si, [4+1i 7+1i]))
assert(isequal(p, [3 12]))
assert(isequal(pi, [3+1i 12+1i]))
function x = mysum(varargin)
x = applyFunc(#sum, varargin{:});
end
function x = myprod(varargin)
x = applyFunc(#prod, varargin{:});
end
end
function x = applyFunc(func, varargin)
p = inputParser();
p.addRequired('func', #(x) validateattributes(x, {'function_handle'}, {'scalar'}));
p.addRequired('v', #(x) validateattributes(x, {'double'}, {}, 'applyFunc:msg', 'v'));
p.addOptional('imag', '', #(x) validatestring(x, {'imag', ''})); % THIS LINE IS THE PROBLEM
p.parse(func, varargin{:});
f = p.Results.func;
v = p.Results.v;
strflag = p.Results.imag;
x = f(v);
if ~isempty(strflag)
validatestring(strflag, {'imag'});
x = x + 1i;
end
end
The line that's causing the problem is this one (as marked in the code above):
p.addOptional('imag', '', #(x) validatestring(x, {'imag', ''}));
The documentation for inputParser says that:
For optional string inputs, specify a validation function. Without a validation function, the input parser interprets valid string inputs as invalid parameter names and throws an error.
Unfortunately I don't have any idea how to do this. Is there something simple Im missing or what? If the 'imag' argument isn't passed at all (as in the assignment of s and p), the code works fine, but if I do pass it, I get this error:
Error using sandbox>applyFunc (line 32)
The value of 'imag' is invalid. It must satisfy the function:
#(x)validatestring(x,{'imag',''}).
Error in sandbox/mysum (line 18)
x = applyFunc(#sum, varargin{:});
Error in sandbox (line 7)
si = mysum(v, 'imag');
Any help?
The problem is that validatestring returns the matching string from the cell argument ({'imag',''}) rather than a Boolean indicating if it passes validation. Instead, use strcmp and any:
#(x) any(strcmp(x,{'imag', ''}))
Also, with validatestring, if the input string did not match either 'imag' or '' (actually just 'imag' since empty strings only match in R2014a+), it would throw an error rather than returning false so that the inputParser could return the appropriate error.
Another nice way to fix the problem is to change the syntax of applyFunc entirely so that instead of just 'imag' as an optional string input argument, use a Parameter-Value with 'imag' as the parameter and a validated boolean as the input.
The input definition suggested by Amro in the comments:
p.addParameter('imag', false, #(x)validateattributes(x, {'logical'}, {'scalar'}))
The usage:
mysum(x,'imag',true)
mysum(x) % default is equivalent to mysum(x,'imag',false)
This would simplify the rest of the code with p.Result.imag being a logical scalar. I would suggest:
x = f(v) + p.Result.imag*1i;
The problem is not inputParser, I think the issue is with validatestring.
1) First it does not match on empty strings:
>> x = ''
x =
''
>> validatestring(x, {'imag',''})
Expected input to match one of these strings:
imag,
The input did not match any of the valid strings.
Caused by:
Error using validatestring>checkString (line 85)
Expected input to be a row vector.
2) Second, if it successfully matches, it returns the resolved string (from one of the valid choice), instead of true/false. inputParser requires that the validation function either return a boolean, or nothing but throws error on failure.
I know that the custom function myfun outputs the variable names that are passed to it using the inputname command.
However, when I pass variables through a cellfun the inputname command ceases to work, as shown below (where I am passing in the variable names j, lat, and lon. Here, it just somehow outputs all the variables as 'x'.
>> cellfun(#(x)myfun(x, y), {j, lat, lon}, 'UniformOutput', false)
First calling variable is "x".
First calling variable is "x".
First calling variable is "x".
ans =
'x' 'x' 'x'
And if I try:
cellfun(#myfun, {j}, 'UniformOutput', false)
I get:
First calling variable is "".
ans =
{''}
I'm doing this because I'm creating a bunch of plots with a function, and would like all the plots auto-labeled with the variable name of the variable I'm passing into the plots.
You lose the connection between the name of the variable you pass and inputname in this scenario. The only solution I see is to send the name of the variable as an additional argument to myfun. You need to extract the names using a separate function like this:
function [values, names] = getNames(varargin)
values = varargin;
names = cell(size(varargin));
for iArg = 1:nargin
names{iArg} = inputname(iArg);
end
end
Then your code should look like this
[values, names] = getNames(j,lat,lon);
cellfun(#(x,n)myfun(x,y,n),values,names,'UniformOutput',false);
Now the third argument passed to myfun contains the name of its first argument.
Update:
This means you need to edit myfun to accept a third argument as the name of the variable instead of using inputname.
Suppose we have a function defined as:
function(f, df, x0)
where f is a function, df is its derivative, and x0 is an initial point. How do we defined f on the command line? Do you use an inline definition? What about df and x0? What if df is a gradient? Also if x0 is an ordered pair, how do you define it in the command line?
To pass a function as a variable, you need to use a function handle. A simple way to demonstrate this is to use a function handle to an anonymous function. A simple anonymous function can be defined as follows:
handle = #(arglist)anonymous_function
So, to make an anonymous function that adds 2 numbers, you could do something like the following:
f = #(a,b)a+b;
You can use this like any other function
>> f(1,2)
ans =
3
If df is just a simple numeric value, it can be defined as follows:
df = 0.4
To define a pair of values, you could do it like so:
X0=[1 2]
Finally, you can put it all together with this example function (put this in a file called myfunc) . . .
function out = myfunc(f,df,x0)
out = df * f(x0(1), x0(end));
Is this what you want? I was slightly confused by "x0 is an ordered pair".
I need to declare a function that has 32 arguments, so it would be handy to put an unique argument: an array of 32 elements.
I don't find the syntax to do that, I've tried everythinh like:
function x=myfunction(str(32)) (etc...)
But without success.
Unlike other languages, MATLAB can accept matrices as a single argument; so you could just check that the input argument is a vector of length 32:
function x = myfunction(arg)
if length(arg) ~= 32
error('Must supply 32 arguments!');
end
%# your code here
end
If it's a variable number of arguments, check out varargin:
function x = myfunction(varargin)
But for 32 arguments, consider using an input structure:
function x = myfunction(argStruct)
if length(fieldnames(argStruct)) ~= 32
error('not enough arguments!');
end
Supply arguments in the structure, then pass the structure:
>> myArgs = struct();
>> myArgs.arg1 = 5;
>> myArgs.arg2 = 7;
>> %#(etc)
>> x = myfunction(myArgs);
Then in the function, you could either call argStruct.arg1, etc, directly; or unpack it into 32 different variables inside the function. I would give the fields descriptive names so you don't refer to them as arg1, etc inside your function. For that many input arguments, people using the function probably won't remember the order in which your function requires them to pass inputs to. Doing it with a struct lets users pass in arguments without needing to think about what order those inputs are defined.
To add to #strictlyrude27's awesome answer, it looks like you may misunderstand how function declarations work in Matlab. You wrote:
function x=myfunction(str(32))
However, you don't need to declare the type of input in matlab. Just give it a name, and then use it. So, the proper syntax for a declaration would be:
function x = myfunction(myInput)