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

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.

Related

Vectorization of a small code snippet

q=
2
4
6
1
6
8
From=
1
4
2
To=
3
6
3
q is a sequence of points. For instance, q(From(1):To(1)) gives 2,4,6. I want to vectorize this example.
This is non-vectorized working code:
J=3;
L=cell(J,1);
for j=1:J
L{j}=q(From(j):To(j));
end
Its result is:
L=
2,4,6 % j=1
1,6,8 % j=2
4,6 % j=3
I cannot figure out how to get a vectorized form of this code. I tried to convert L into 2-dim array, but anyway nothing works.
You can get rid of the for loop by using arrayfun to apply a specific function on all elements of the inputs. However, I'm not sure if it will be much faster than the loopy version.
The code below produces output equivalent to your original cell array L:
L2 = arrayfun(#(x,y)q(x:y), From, To, 'UniformOutput', false);
Here, #(x,y)q(x:y) defines an anonymous function that returns subvectors from q according to the inputs x and y, which are picked by arrayfun from your input vectors From and To.
As suggested in the comments, if you desire extra genericity you can specify another function handle like this:
L_fun = #(q)arrayfun(#(x,y)q(x:y), From, To, 'uniformoutput', false);
...and then call it for an arbitrary vector (not necessarily your original q) as such:
q2 = rand(10,1); %// Random vector for testing
Lout = L_fun(q2); %// Use From and To to pick from q2
Or even define a handle which takes all inputs:
L_fun = #(q,From,To)arrayfun(#(x,y)q(x:y), From, To, 'uniformoutput', false);
but in this case it might be better to actually write a named function already.

element by element matrix multiplication in Matlab

So I have the following matrices:
A = [1 2 3; 4 5 6];
B = [0.5 2 3];
I'm writing a function in MATLAB that will allow me to multiply a vector and a matrix by element as long as the number of elements in the vector matches the number of columns. In A there are 3 columns:
1 2 3
4 5 6
B also has 3 elements so this should work. I'm trying to produce the following output based on A and B:
0.5 4 9
2 10 18
My code is below. Does anyone know what I'm doing wrong?
function C = lab11(mat, vec)
C = zeros(2,3);
[a, b] = size(mat);
[c, d] = size(vec);
for i = 1:a
for k = 1:b
for j = 1
C(i,k) = C(i,k) + A(i,j) * B(j,k);
end
end
end
end
MATLAB already has functionality to do this in the bsxfun function. bsxfun will take two matrices and duplicate singleton dimensions until the matrices are the same size, then perform a binary operation on the two matrices. So, for your example, you would simply do the following:
C = bsxfun(#times,mat,vec);
Referencing MrAzzaman, bsxfun is the way to go with this. However, judging from your function name, this looks like it's homework, and so let's stick with what you have originally. As such, you need to only write two for loops. You would use the second for loop to index into both the vector and the columns of the matrix at the same time. The outer most for loop would access the rows of the matrix. In addition, you are referencing A and B, which are variables that don't exist in your code. You are also initializing the output matrix C to be 2 x 3 always. You want this to be the same size as mat. I also removed your checking of the length of the vector because you weren't doing anything with the result.
As such:
function C = lab11(mat, vec)
[a, b] = size(mat);
C = zeros(a,b);
for i = 1:a
for k = 1:b
C(i,k) = mat(i,k) * vec(k);
end
end
end
Take special note at what I did. The outer-most for loop accesses the rows of mat, while the inner-most loop accesses the columns of mat as well as the elements of vec. Bear in mind that the number of columns of mat need to be the same as the number of elements in vec. You should probably check for this in your code.
If you don't like using the bsxfun approach, one alternative is to take the vector vec and make a matrix out of this that is the same size as mat by stacking the vector vec on top of itself for as many times as we have rows in mat. After this, you can do element-by-element multiplication. You can do this stacking by using repmat which repeats a vector or matrices a given number of times in any dimension(s) you want. As such, your function would be simplified to:
function C = lab11(mat, vec)
rows = size(mat, 1);
vec_mat = repmat(vec, rows, 1);
C = mat .* vec_mat;
end
However, I would personally go with the bsxfun route. bsxfun basically does what the repmat paradigm does under the hood. Internally, it ensures that both of your inputs have the same size. If it doesn't, it replicates the smaller array / matrix until it is the same size as the larger array / matrix, then applies an element-by-element operation to the corresponding elements in both variables. bsxfun stands for Binary Singleton EXpansion FUNction, which is a fancy way of saying exactly what I just talked about.
Therefore, your function is further simplified to:
function C = lab11(mat, vec)
C = bsxfun(#times, mat, vec);
end
Good luck!

How to take elements of a Matrix and use each one as Input-Variable for the same function?

I have given a matrix with 485x1 elements. MatLab shall take the first 12 of them and make them a new matrix.
Then I have a variable named C and a function f(C).
MatLab shall take the first element of the new matrix and make it C. Then it shall perform f(C) and save the result as result1.
Then it should take the second element of the new matrix and make it C. Then it shall perform f(C) again and save the result as result2 and so on.
So in the end I need 12 result variables.
How can I program this?
This is question asks for very basic stuff. Like adressing the first 12 elements of a matrix. You might want to consider reading a few FAQs.
However a basic solution can look like this:
M = [1:485]'; %// a 485x1 matrix (vector)
newMatrix = M(1:12); %// newMatrix contains the first 12 elements of M (also vector)
result = cell(1,12); %// result as a cell
f = #(x) x+1; % a function f
for i = 1:12
C = newMatrix(i); % get each value from newMatrix, call it C
result{i} = f(C); % apply f() on c and store the result
end
It is not a good idea to generate variables result1, result2, ..., result12, you can read more about it here. Better use a cell for storing the variables, you can then adress the i-th result as result{i}.

MATLAB - avoiding loops to create a matrix based on the elements of other vectors

Suppose I have vectors x,y,z, of lengths n,m,l. I want to create a cell matrix Q using the elements of those vectors. Naively one could use a for loop as so:
for i = 1:n
for j = 1:m
for k = 1:l
Q{i,j,k} = someFunction(x(i), y(j), z(k));
end
end
end
Each element of Q is a vector.
Is there a more elegant (and probably less slow) way to do this?
x=[1 2 3 4];
y=[5 6];
z=[7 8 9];
[X Y Z]=meshgrid(x,y,z);
someFunc = #(a,b,c)[a b c]; #% test function; use whatever you want
Q = arrayfun(someFunc,X,Y,Z,'UniformOutput',false);
Q{1,1,1} #% output: [1 5 7]
If someFunction is defined elsewhere, use arrayfun(#someFunction,X,Y,Z); to get a handle to it. (arrayfun uses each element of the arguments as args to the function handle you provide - it, and the related cellfun, are key in avoiding loops.)
With someFunction is designed this way, then it does not look possible.
You should change someFunction to take matrices and return a matrix. Then the problem becomes writing the specific someFunction using matrix operations. Altough a generic solution to the original problem seems not possible, when you consider a specific function (like I suggested here) it can be possible.

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.