Passing a function to arrayfun - matlab

If I pass an anonymous function to arrayfun as follows:
arrayfun(#(x)sprintf('%.2g\\pi', x/pi), [0 6 7 8], 'uni', 0)
I get the following result:
ans =
'0\pi' '1.9\pi' '2.2\pi' '2.5\pi'
However, if I declare a separate function:
function y = sprint_func_0(x)
sprintf('%.2g\\pi', x/pi)
end
and pass it to arrayfun:
arrayfun(#(x)sprint_func_0(x), [0 6 7 8], 'uni', 0)
The result is:
ans =
0\pi
ans =
1.9\pi
ans =
2.2\pi
ans =
2.5\pi
Why do I get one output in the first case and many outputs in the second case? This is probably stupid, but I can't find the answer anywhere.

In the first case the anonymous function returns a string, so arrayfun returns a cell array of strings.
In the second case the function does not assign a value to the output parameter y (essentially printing the output of sprintf to the command window).
If you modify the function sprint_func_0 to:
function y = sprint_func_0(x)
y = sprintf('%.2g\\pi', x/pi); %// Note the assignment to y
end
you should get the same result.

Related

How do I retain the number of arguments of a function handle when passing it to some other function in Matlab?

I am trying to write a function that takes a cell array of functions as an input and that outputs the same functions, but in a somewhat different format.
Specifically, I want a row vector, of say length N, of functions fVec = [f1(x, y, z), f2(x,y,z), ..., fn(x, y, z)] all of which always output a column vector of the same length, say M. Now I want the evaluation of fVec(x, y, z) to output an MXN matrix, where each column represents the output of its corresponding vector.
However, because Matlab doesn't accept regular function handle arrays, it must be done using cell arrays. (, right?)
Moreover, I want a general function that works for several sets of functions, that don't necessarily have three inputs. That is, I want the function fVec(1, ..., x) = [f1(1, ..., x), f2(1, ..., x), fn(1, ..., x)], meaning that each of the funtions f1, f2, fn always have the same number of inputs.
Therefore, I need some function that takes as an input a cell array of function handles {f1(1, ..., x), f2(1, ..., x), fn(1, ..., x)} and outputs some overarching function fVec(1, ..., x).
I already tried writing a function that I thought should do this:
function overArchingFunction = transformFunctionArray(functionArray)
if length(functionArray) == 1
if isa(functionArray, 'cell')
overArchingFunction = functionArray{:};
else
overArchingFunction = functionArray;
end
else
disp(cellfun(#(fun) fun(x), functionArray, ...
'UniformOutput', false))
overArchingFunction = #(vars) cell2mat(cellfun(#(fun) fun(vars), functionArray, ...
'UniformOutput', false));
end
end
This works for "arrays of length 1", obviously. However, there is a problem with this code. Let's make a test function, say testfun = #(a, b, c, d, e) a(:,3) - a(:,2) (where testfun is a function of b, c, d, e to replicate the most general scenario), and make an array of this function, functionArray = {testfun, testfun}.
Now we call our function overArchingFunction = transformFunctionArray(functionArray). However, when calling solution = transfun([[10 1 2]; [3 4 5]], 0, 0, 0, 0), I want the output to be:
solution =
1 1
1 1
This is not the case, because with the #(vars) and fun(vars) statements, I'm restricting the number of input variables to this function to only one variable, whereas I am trying to pass five arguments (namely [[10 1 2]; [3 4 5]], 0, 0, 0, 0). I though I'd fix this by replacing vars with
varargin, but this gives me the error:
Attempt to execute SCRIPT varargin as a function:
/MATLAB/toolbox/matlab/lang/varargin.m
Summarising, how do I retain the original number of input arguments of f1, f2, ..., fn in the overArchingFunction?
I found it. The answer indeed lay in using varargin. However, because varargin passes a cell structure input, you need to access those cells' contents by using varargin{:}. The function should thus be:
function overArchingFunction = transformFunctionArray(functionArray)
if length(functionArray) == 1
if isa(functionArray, 'cell')
overArchingFunction = functionArray{:};
else
overArchingFunction = functionArray;
end
else
overArchingFunction = #(varargin) cell2mat(cellfun(#(fun) fun(varargin{:}),
functionArray, ...
'UniformOutput', false));
end
end
Such that the following commands give the required answer.
>> testfun = #(a, b, c, d, e) a(:,3) - a(:,2)
testfun =
function_handle with value:
#(a,b,c,d,e)a(:,3)-a(:,2)
>> transfun = transformFunctionArray({mytestfun, mytestfun})
transfun =
function_handle with value:
#(varargin)cell2mat(cellfun(#(fun)fun(varargin{:}),functionArray,'UniformOutput',false))
>> myans = transfun([[10 1 2]; [3 4 5]], 0, 0, 0, 0)
myans =
1 1
1 1

MATLAB: Using cellfun with multi level cell array

I have a multi-level cell array. The individual levels could be of different size. I am wondering how I can apply cellfunto the lowest level. Imagine the following mulit-level cell array:
a = {randi(10,5,1), randi(5,5,1)}
b = randi(100,5,1,10)
f = {a,b}
Now, I would like to drill down as much as possible and apply cellfun to the deepest level possible of f. At the and of each level, there is a 2D/3D matrix. Let's say, I simply want to add 5 to each value. What's the most efficient way?
Here's the result I am looking for.
[a_nRows, a_nCols, a_nPages] = size(a)
x = cellfun(#plus, f{1}, repmat({5}, a_nRows, a_nCols, a_nPages), 'UniformOutput', false)
y = cellfun(#plus, f(2), {5}, 'UniformOutput', false)
You can use recursion for this.
Firstly, define a function which does one of two things
If the input is a numeric matrix, apply some operation.
If the input is a cell, call this same function with the cell's contents as inputs.
The function would look something like this (defined locally to another function or in its own m file):
function out = myfunc( in, op )
if iscell( in )
out = cellfun( #(x) myfunc(x, op), in, 'UniformOutput', false );
elseif isnumeric( in )
out = op( in );
else
error( 'Cell contents must be numeric or cell!' )
end
end
Then you can call myfunc on your cell. Here is an example similar to yours:
a = {[1 2; 3 4], {eye(2), 10}}; % Nested cell arrays with numeric contents
op = #(M) M + 5; % Some operation to apply to all numeric contents
myfunc( a, op )
% >> ans =
% { [6 7; 8 9], {[6 5; 5 6], 15}}
Directly using your example, the output of myfunc(f, #(M)M+5) is the same as your {x, y{1}} - i.e. the operation op is applied to every cell and nested cell with the result structured the same as the input.

Applying "or" function to more than two vectors Matlab

I wish to include or (or any) within a function where the number of arguments (logical vectors) passed in can be more than two and can vary in number.
For example, the parent function may create
a=[1;0;0;0]
b=[0;1;0;0]
c=[0;0;0;1]
but the next time may add
d=[0;0;1;0]
how do I get it, in this case, to give me X=[1;1;0;1] the first time around and Y=[1;1;1;1] the second time? The number of vectors could be up to twenty so it would need to be able to recognise how many vectors are being passed in.
This is how I would do it:
function y = f(varargin)
y = any([varargin{:}], 2);
varargin is a cell array with the function input arguments. {:} generates a comma-separated list of those arguments, and [...] (or horzcat) concatenates them horizontally. So now we have a matrix with each vector in a column. Applying any along the second dimension gives the desired result.
Since the function contains a single statement you can also define it as an anonymous function:
f = #(varargin) any([varargin{:}], 2);
Example runs:
>> f([1; 1; 0; 0], [1; 0; 0; 1])
ans =
4×1 logical array
1
1
0
1
>> f([1; 1; 0; 0], [1; 0; 0; 1], [0; 0; 1; 0])
ans =
4×1 logical array
1
1
1
1
I'm sure you already thought of this:
a=[1;0;0;0]
b=[0;1;0;0]
c=[0;0;0;1]
a|b|c % returns [1;1;0;1]
However there is a much simpler answer to this:
any([a,b,c,d],2);
easily extendable by just concatinating the variables as above, before inputting it into the anyfunction. If you want to put it into a function here's way to do it:
function customOr(varargin)
any(cell2mat(varargin),2) % equivalent to any([varargin{:}],2);
end
customOr(a,b,c) % returns [1;1;0;1]
customOr(a,b,c,d) % returns [1;1;1;1]

Vectorize function that outputs a row using arrayfun, returning a matrix

I'm using Octave and would like to vectorize a function that accepts as input a single real number and outputs a row vector of fixed length. I understand that arrayfun should be able to do this from its unclear documentation. From help arrayfun in Octave 3.2:
If the parameter VAL after a further string input argument
"UniformOutput" is set 'true' (the default), then the named
function FUNC must return a single element which then will be
concatenated into the return value and is of type matrix.
Otherwise, if that parameter is set to `false', then the outputs
are concatenated in a cell array.
It seems however that Matlab's version is more forgiving:
[B1,...,Bm] = arrayfun(func,A1,...,An) calls the function specified by function handle func and passes elements from arrays A1,...,An, where n is the number of inputs to function func. Output arrays B1,...,Bm, where m is the number of outputs from function func, contain the combined outputs from the function calls. The ith iteration corresponds to the syntax [B1(i),...,Bm(i)] = func(A1{i},...,An{i}). The arrayfun function does not perform the calls to function func in a specific order.
It looks like this works in Matlab but not in Octave. Am I correct that this generalization cannot be performed using arrayfun in Octave? Is there some more clever way to achieve this without resorting to unvectorized loops?
For reference, here is my Octave result:
octave:5> nums
nums =
#(c) ([c, c + 2, c + 4])
octave:6> arrayfun(nums,[1,2,3])
error: cellfun: expecting all values to be scalars for UniformOutput = true
error: called from:
error: /opt/local/share/octave/3.2.4/m/general/arrayfun.m at line 168, column 21
octave:6>
Use arrayfun to apply the function, nums to an array [1,2,3]
CellArray = arrayfun(nums, [1,2,3], "UniformOutput", false);
That gives you a cell array. If you want the answer in a matrix, use cell2mat
cell2mat(CellArray);
If your actual nums is more complicated, then we'll need a better example of it to suggest a solution.
The error already suggests how to solve the problem:
arrayfun(nums,[1,2,3],'UniformOutput',false)
There is no difference between Matlab and Octave.
Matlab:
>> nums=#(c) ([c, c + 2, c + 4])
nums =
#(c)([c,c+2,c+4])
EDU>> arrayfun(nums,[1,2,3])
Error using arrayfun
Non-scalar in Uniform output, at
index 1, output 1.
Set 'UniformOutput' to false.
>> arrayfun(nums,[1,2,3],'UniformOutput',false)
ans =
Columns 1 through 2
[1x3 double] [1x3 double]
Column 3
[1x3 double]
Octave:
octave:1> nums=#(c) ([c, c + 2, c + 4])
nums =
#(c) ([c, c + 2, c + 4])
octave:2> arrayfun(nums,[1,2,3])
error: arrayfun: all values must be scalars when UniformOutput = true
octave:2> arrayfun(nums,[1,2,3],'UniformOutput',false)
ans =
{
[1,1] =
1 3 5
[1,2] =
2 4 6
[1,3] =
3 5 7
}
octave:3>
If your function is really that simple, I suggest to use:
nums([1,2,3]')

Can I specify nargout as part of a MATLAB function call?

The problem:
I want to index into the result of a function call that returns a variable number of output arguments without storing the result in a temporary.
getel = #(x,i) x(i); #% simple anonymous function to index into a vector
x = zeros(2,2,2);
row = getel(ind2sub(size(x), 8), 1) #% desired: 2 (row 2)
#% actual: 8 (linear index)-because ind2sub is returning 1 value only
[row col dep]=ind2sub(size(x),8) #% row=2, ind2sub returning 3 values
Example usage:
x(1).val1 = [1 2 3];
x(1).val2 = [2 1 2];
x(2).val1 = [2 1 2];
x(2).val2 = [1 0 0];
#% The normal way I would do this, with a temporary variable
[~,ind] = min(x(1).val2); #% ind=2
v(1) = x(1).val1(ind);
[~,ind] = min(x(2).val2); #% ind=2
v(2) = x(2).val1(ind);
#% I'd like to be able to do this with arrayfun:
v = arrayfun(#(s) s.val1(min(s.val2), x);
-------^ returns value of minimum, not index
The above arrayfun doesn't work - the form of min that is called returns one output: the minimum value. To make it work right, one option would be the following hypothetical function call:
v = arrayfun(#(s) s.val1(getoutputnum(2, 2, #min, s.val2)), x);
hypothetical function -----------^ ^ ^ ^-func ^--func args
which form (nargout) of func ---| |- which arg to return
I realize that for the above scenario, I could use
s.val1(find(s.val2==min(s.val2),1,'first'))
or other tricks, but that isn't possible in all cases.
In the case of ind2sub, I may want to know the index into a particular dimension (columns, say) - but the 1-output form of the function returns only a linear index value - the n-dimensional form needs to be called, even if the value of dimension 1 is what I care about.
Note: I realize that writing a function file would make this trivial: use ~ and the [out] = func(in) form. However, when writing scripts or just on the command line, it would be nice to be able to do this all within anonymous functions. I also realize that there are undoubtedly other ways to get around the problem; I would just like to know if it is possible to specify which form of a function to call, and perhaps which output number to be returned, without using the out=func(in) syntax, thus allowing functions to be nested much more nicely.
Could you do something like this?
In its own file:
function idx=mymin(x)
[~,idx] = min(x);
In your code:
v = arrayfun(#(s) s.val1(mymin(s.val2), x);
Might have syntax errors; I don't have MATLAB on the computer I'm writing this on. The idea is there though: just wrap MATLAB's min and capture the second argument, which is the logical indexing for the position of the minimum value in x.
I can get ind2sub() to return the variable number of args like this:
x = zeros(2,2,2);
c = cell(ndims(x),1);
[c{:}] = ind2sub(size(x), 8);
The c cell array will now have the 3D indices c = {2;2;2}.
[c{:}] = ind2sub(size(x), 2);
would produce c = {2;1;1}.
Is this what you were looking for?