Vectorized or single line evaluation of function array in MATLAB - matlab

In a previous question, a user asked about iterating over a cell array of anonymous functions. I am wondering whether there is a way to evaluate a set of functions without the explicit use of a for loop.
As an example, the following code creates an array of (simple) functions, evaluates them for a fixed value and stores the results:
fcnList = {#(x) (x+1), #(x) (x+2)};
a = 2;
for i = 1:numel(fcnList)
y(i) = fcnList{i}(a);
end
Is there a way to do this without looping?

For your example, you could do the following using the cellfun function:
fcnList = {#(x) (x+1), #(x) (x+2)};
a = 2;
cellfun(#(func) func(a),fcnList)
ans =
3 4
Where I have created a handle called func which accepts as input a function from the fcnList variable. Each function is then evaluated for a.
If you need to pass a vector instead of a scalar, for instance b, you will need to set the 'UniformOutput' option to false:
b=[3 4]
fcnList = {#(x) (x+1), #(x) (x+2)};
cellfun(#(func) func(b),fcnList,'UniformOutput',false)
ans =
{
[1,1] =
4 5
[1,2] =
5 6
}

To avoid a for loop or cellfun (which is more or less the same as a loop), you can define a single function with vector output:
fcn = #(x) [x+1, x+2];
Then fcn(a) gives you a vector cointaining the results:
>> fcn = #(x) [x+1, x+2];
>> a = 2;
>> fcn(a)
ans =
3 4
If the results of each original function have different sizes you can define a single function with cell array output:
>> fcn = #(x) {x+1, [x+2; x+3]};
>> a = 2;
>> x = fcn(a)
x =
[3] [2x1 double]
>> celldisp(x)
x{1} =
3
x{2} =
4
5

Related

anonymous function returning updated length of an array - matlab

I'm trying to write a simple anonymous function which returns the length of an array
>> a=[1 2 3];
>> f = #() length(a);
>> f()
3
>> a = [1 2 3 4];
>> f()
3
Is it possible to write a function that returns the length of the updated array every time it's called?
An ugly method to accomplish what you want
global a;
a = [1 2 3];
f = #() eval('global a; length(a)')
f()
a = [1 2 3 4];
f()
I'm compelled to say that I strongly recommend against this type of code as it relies on both globals and calls to eval, both of which should be avoided when possible.
A better method would be to pass in a as an argument to the function
a = [1 2 3];
f = #(x) length(x)
f(a)
a = [1 2 3 4];
f(a)
or, because in this case calling f is identical to calling length, then there's really no reason to use anonymous functions at all.
a = [1 2 3];
length(a)
a = [1 2 3 4];
length(a)
Defining an anonymous function in terms of a variable makes that variable static within the function. i.e.
% this...
a = [1 2 3];
f = #() length(a);
% ... is equivalent to this...
f = #() length([1 2 3]);
You want to create an anonymous function which can take an argument
f = #(x) length(x);
a = [1 2 3];
f(a); % >> ans = 3
a = [1 2 3 4];
f(a); % >> ans = 4
Although at that point, just use length(a) and don't define some pointer-function!

Assign multiple function outputs to a vector using indexing in MATLAB

I have a simple MATLAB function outputting multiple variables:
function [a,b] = MultipleOutputs()
a = 6;
b = 8;
end
I want to assign the two output variables to 2 certain elements in an existing vector:
x = ones(1,4);
x(2:3) = MultipleOutputs()
However, this gives me:
x =
1 6 6 1
Instead of:
x =
1 6 8 1
I have had this problem in multiple cases, was never able to find the solution.
You have 2 choices:
Concatenate the vectors after outputting them separately
[a,b] = MultipleOutputs();
x = ones(1,4);
x(2:3) = [a,b];
concatenate the vectors before outputting them
function a = MultipleOutputs()
a(1) = 6;
a(2) = 8;
end
x(2:3) = MultipleOutputs();
when you run MultipleOutputs() like that in another function, it only outputs only the first element, which in this case is a.
So eventually your statement x(2:3) = MultipleOutputs() is equivalent to x(2:3) = 6.
A simple fix would be to extract all the elements:
[a,b] = MultipleOutputs();
x(2:3) = [a b];

Syntax for evaluating multiple variables for function

I'm trying to do something like
f = [x+1 y+2]
values = [1 2]
f(values) = [2 4]
(not proper syntax)
f(values) only works for taking one variable?
Try this:
f = {#(x) (x+1); #(y) (y+2)}; %//create a cell array of your function handlers
values = [1 2];
%//convert your input values to a cell array
length = numel(values);
v = mat2cell( values, 1, ones(length,1) ).' ;
%// f(v)
results = cellfun(#(x,y) x(y), f, v);

How to create a matrix of functions dynamically

I want to create a matrix of functions, however I'd like to dynamically generate it. For example:
myMatrix = zeros(3);
test = #(x) x*y;
for ii = 1:3
myMatrix(ii) = test(ii);
end
something like that to generate: #(y) [y, 2*y, 3*y]
I do not have access to the sym library.
You can't make a matrix of functions, but you can make cell of function handles, e.g.
cellOfFunctions = {};
for i = 1:3
cellOfFunctions{end + 1} = #(y) y*i;
end
Then you can get each handle as follows (for the first function handle):
fh1 = cellOfFunctions{1};
Then execute it with y = 3:
result = fh1(3);
Depending on your purposes, you can make a single function which generates the matrix you have in your example:
>> f = #(y) bsxfun(#times, 1:3, y(:));
>> f(2:5)
ans =
2 4 6
3 6 9
4 8 12
5 10 15

How to select one element from each column of a matrix in matlab?

a = [1 1 1; 2 2 2; 3 3 3];
b = [1 2 3];
How can I call one function to get a vector v[i] = a[b[i],i]?
v = a(sub2ind(size(a), b, 1:length(b)))
sub2ind transforms subscripts into a single index.
Another thing to try, keeping very close to your description, you can use the arrayfun function.
First define a function that maps a value x to the desired output.
fn = #(x) a(b(x), x);
Then call that function on each input in the the i vector.
i = 1:3;
v = arrayfun(fn, i);
Or, this can all be done in a single line, in the obvious way:
v = arrayfun(#(x) a(b(x), x), 1:3);
This arrayfun is simply shorthand for the loop below:
for ixLoop = 1:3
v(ixLoop) = a(b(ixLoop),ixLoop);
end
The related functions arrayfun, cellfun, and structfun have similar uses, and are strangely empowering. This Joel article convinced me to be a believer.