Applying bsxfun to function with multiple output arguments - matlab

Let us assume we have a function myfunction with two output arguments
function [ arg1, arg2 ] = myfunction( a, b )
arg1 = a*b;
arg2 = a+b;
end
I want to apply myfunction to vector A and B:
fun = #myfunction;
A = 1:10;
B = 1:17;
[C, D] = bsxfun(fun,A,B)
This gives an error. How can I use bsxfun with functions having multiple output arguments?

bsxfun generates the output from all combinations of orthogonal matrices / vectors. Therefore to make your example work for even one output you have to transpose one of the inputs:
output1 = bsxfun(#myfunction,A,B.');
But as rayryeng commented, the problem with bsxfun is that it can return only one output. As Cris Luengo suggested in a comment you can instead use arrayfun. The difference is that for arrayfun you have to explicit generate all input combinations by expanding the input 1xN and 1xM vectors to NxM matrices:
For Matlab 2016b and later:
[output1, output2] = arrayfun(#myfunction,A.*ones(numel(B),1),B.'.*ones(1,numel(A)));
Matlab pre-2016b:
[output1, output2] = arrayfun(#myfunction,bsxfun(#times,A,ones(numel(B),1)),bsxfun(#times,B.',ones(1,numel(A))))
Instead of using bsxfun to expand the matrices you could also use repmat- but that's generally a bit slower.
Btw., If you have a function with many outputs and can't be bothered with writing [output1, output2, output3, ...] = ... you can just save them in a cell:
outputs = cell(nargout(#myfunction),1);
[outputs{:}] = arrayfun(#myfunction,....);

You cannot, the bsxfun is only for binary operations

Related

MATLAB: return both arguments from ISMEMBER when used inside SPLITAPPLY

How can I access both arguments of ismember when it is used inside splitapply?
slitapply only returns scalar values for each group, so in order to compute nonscalar values for each group (as returned by the first argument of ismemebr), one has to enclose the anonymous function (in this case ismember) inside curly brackets {} to return a cell array.
But now, when I provide two output arguments to splitapply, I get an error:
Output argument "varargout{2}" (and maybe others) not assigned during call to
"#(x,y) {ismember(x,y)}"
ADD 1
I can create another function, say, ismember2cell which would apply ismember and turn outputs into cell arrays:
function [a, b] = ismember2cell(x,y)
[a,b] = ismember(x,y);
a = {a};
b = {b};
end
but maybe there is a solution which doesn't require this workaround.
One potentially faster option is to just do what splitapply is already doing under the hood by splitting your data into cell arrays (using functions like mat2cell or accumarray) and then using cellfun to apply your function across them. Using cellfun will allow you to easily capture multiple outputs (such as from ismember). For example:
% Sample data:
A = [1 2 3 4 5];
B = [1 2 1 5 5];
G = [1 1 1 2 2]; % Group index
% Group data into cell arrays:
cellA = accumarray(G(:), A(:), [], #(x) {x(:).'}); % See note below about (:).' syntax
cellB = accumarray(G(:), B(:), [], #(x) {x(:).'});
% Apply function:
[Lia, Locb] = cellfun(#ismember, cellA, cellB, 'UniformOutput', false);
NOTE: My sample data are row vectors, but I had to use the colon operator to reshape them into column vectors when passing them to accumarray (it wants columns). Once distributed into a cell array, each piece of the vector would still be a column vector, and I simply wanted to keep them as row vectors to match the original sample data. The syntax (:).' is a colon reshaping followed by a nonconjugate transpose, ensuring a row vector as a result no matter the shape of x. In this case I probably could have just used .', but I've gotten into the habit of never assuming what the shape of a variable is.
I cannot find a global solution, but the accepted answer of this post helps me to define a helper function for your problem:
function varargout = out2cell(varargin)
[x{1:nargout}]=feval(varargin{:});
varargout = num2cell(x);
I think that you may succeed in calling
splitapply(#(x,y) out2cell(#ismember, x, y), A, B);

MATLAB: How to evaluate a function with multiple inputs on all possible combinations of input vectors

Say I have a simple function with three inputs
f = #(a,b,c) a+b+c
I would like to evaluate this function on combinations of inputs
A = 1:10
B = 2:2:10
C = 0.1:0.1:1
and store the output in a matrix F.
Right now I am doing this as follows:
F = NaN(length(A),length(B),length(C));
for ia = 1:length(A)
for ib = 1:length(B)
for ic = 1:length(C)
F(ia,ib,ic) = f(A(ia),B(ib),C(ic))
end
end
end
I am wondering if there is an efficient way to do this without the use of sloppy for loops, *and without having to vectorize the function f.
If you want neat syntax and don't care much about memory or speed, you can use:
ndgrid to generate all combinations; and then
arrayfun to call f on each combination:
The second step exploits the fact that arrayfun can be called with several arrays as input, and in that case it takes corresponding elements from each array:
[aa, bb, cc] = ndgrid(A,B,C); %// step 1
result = arrayfun(f, aa, bb, cc); %// step 2
As for the memory and speed concerns I mentioned above:
Step 1 requires quite a lot of memory if the input vectors are large, because all combinations are generated at once.
Step 2 may result in code slower than using for loops; see for example here.

How do I designate y as a vector of 2 functions in Matlab?

I am trying to create a for loop to run through my program and call out a function program I have created. I have been successful in getting it to run but now I would like to simplify it one more step and shorten my program by defining y as a vector of two functions instead of y1 and y2. I tried creating a 2 cell array with the functions inside but this is a failed effort. Here is what I have.
f =cell(size(a));
f(1) =[#(t) 4*t];
f(2) =[#(t) 20+(5-t).^2];
Any advice on organizing these 2 into a vector for a single input of y?
What if you use a cell array instead:
f =cell(2,1);
f(1) ={#(t) 4*t}; %// Note the curly braces
f(2) ={#(t) 20+(5-t).^2};
OR using the following, which is more intuitive using cell arrays (thanks #rayryeng!). Assign the content of the cell with curly braces instead of doing the opposite as above.
f{1} =#(t) 4*t;
f{2} =#(t) 20+(5-t).^2;
celldisp(f)
f{1} =
#(t)4*t
f{2} =
#(t)20+(5-t).^2
Another possibility would be to define a vector-valued function whose components are your two functions:
f1 = #(t) 4*t;
f2 = #(t) 20+(5-t).^2;
f = #(t) [f1(t) f2(t)];
So for example
>> f(2.5)
>> ans =
10.0000 26.2500

Converting Cell array of function handle into a single array of function handle

I need to build up a vector of non-linear equations to be used in fsolve to solve it. But I should make each element of the vector in each loop iteration. How can I make up such a vector? In fact, I can not use cell array. How can I convert a cell array like {#(x) x(1)+x(2)^2; #(x) x(1)-2*(x(2))} into an array like #(x) [ x(1)+x(2)^2 ; x(1)-2*(x(2))]? Because I want to use fsolve to solve the system of non-linear equations.
Use func2str to get the function definitions in string and use str2func to get the desired function, if A is the cell array containing the function handles:
B = strcat(regexprep(cellfun(#func2str, A, 'uni', 0), '^#\(x\)', ''), ';');
F = str2func(strcat('#(x) [', B{:}, ']'));
Now F contains the desired function handle.
Why convert? Why not use something like
% Your cell array
Fs = {#(x) x(1)+x(2)^2; #(x) x(1)-2*x(2)};
% Just use cellfun
solution = fsolve(#(y) cellfun(#(x) x(y), Fs), [0 0])

Apply function to every pair of columns in two matrices in MATLAB

In MATLAB, I'd like to apply a function to every pair of column vectors in matrices A and B. I know there must be an efficient (non for) way of doing this, but I can't figure it out. The function will output a scalar.
Try
na = size(A,1);
nb = size(B,1);
newvector = bsxfun(#(j,k)(func(A(j,:),B(k,:))),1:na,(1:nb)');
bsxfun performs singleton expansion on 1:na and (1:nb)'. The end result, in this case, is that func will be applied to every pair of column vectors drawn from A and B.
Note that bsxfun can be tricky: it can require that the applied function support singleton expansion itself. In this case it will work to do the job you want.
Do you mean pairwise? So in a for-loop the function will work as scalar_val = func(A(i),B(i))?
If A and B have the same size you can apply ARRAYFUN function:
newvector = arrayfun(#(x) func(A(x),B(x)), 1:numel(A));
UPDATE:
According your comment you need to run all combinations of A and B as scalar_val = func(A(i), B(j)). This is a little more complicated and for large vectors can fill the memory quickly.
If your function is one of standard you can try using BSXFUN:
out = bsxfun(#plus, A, B');
Another way is to use MESHGRID and ARRAYFUN:
[Am, Bm] = meshgrid(A,B);
out = arrayfun(#(x) func(Am(x),Bm(x)), 1:numel(Am));
out = reshape(out, numel(A), numel(B));
I believe it should work, but I don't have time to test it now.