How to propagate tensors in MATLAB without a loop?

Suppose I have:

A = rand(1,10,3); B = rand(10,16); 

And I want to get:

 C(:,1) = A(:,:,1)*B; C(:,2) = A(:,:,2)*B; C(:,3) = A(:,:,3)*B; 

Is there any way to multiply this by one line to make it faster?

What if I create a new tensor b, like this

 for i = 1:3 b(:,:,i) = B; end 

Can I multiply A and b to get the same C, but faster? The time taken to create b by the above loop does not matter, since I will need C for many different As, while B will remain the same.

+7
performance vectorization multidimensional-array matlab multiplication
source share
4 answers

Move dimensions A and B , and then apply matrix multiplication:

 C = B.'*permute(A, [2 3 1]); 
+7
source share

If A is a true 3D array, something like A = rand(4,10,3) and it is assumed that B remains as a 2D array, then each A(:,:,1)*B A = rand(4,10,3) A(:,:,1)*B will give a 2D array .

So, assuming you want to store these 2D arrays as slices in the third dimension of the output array, C also -

 C(:,:,1) = A(:,:,1)*B; C(:,:,2) = A(:,:,2)*B; C(:,:,3) = A(:,:,3)*B; and so on. 

To solve this in a vectorized way, one approach would be to use reshape A in a 2D array combining the first and third dimensions and then performing matrix multiplication. Finally, so that the size of the output is the same as the previous one specified by C , we need the last stage of the change.

The implementation will look something like this:

 %// Get size and then the final output C [m,n,r] = size(A); out = permute(reshape(reshape(permute(A,[1 3 2]),[],n)*B,m,r,[]),[1 3 2]); 

Run Example -

 >> A = rand(4,10,3); B = rand(10,16); C(:,:,1) = A(:,:,1)*B; C(:,:,2) = A(:,:,2)*B; C(:,:,3) = A(:,:,3)*B; >> [m,n,r] = size(A); out = permute(reshape(reshape(permute(A,[1 3 2]),[],n)*B,m,r,[]),[1 3 2]); >> all(C(:)==out(:)) %// Verify results ans = 1 

According to comments , if A is a three-dimensional array with always a singlet dimension at the beginning, you can simply use squeeze and then matrix multiplication like this:

 C = B.'*squeeze(A) 
+5
source share

EDIT: @LuisMendo indicates that it is indeed possible for this particular use case. However, this is not possible (generally) if the first dimension of A is not 1.

I grabbed this for a while now, and I could never find a solution. Performing elementary computations becomes enjoyable with bsxfun , but tensor multiplication is something that is highly unsupported. Sorry and good luck!

You can check out this mathworks file sharing file , which will make your work easier and support the behavior you are looking for, but I find it also relies on loops. Edit : it relies on MEX / C ++, so this is not a pure MATLAB solution if that is what you are looking for.

+1
source share

I have to agree with @GJSein, the for loop is very fast

 time 0.7050 0.3145 

Here is the timer function

 function time n = 1E7; A = rand(1,n,3); B = rand(n,16); t = []; C = {}; tic C{length(C)+1} = squeeze(cell2mat(cellfun(@(x) x*B,num2cell(A,[1 2]),'UniformOutput',false))); t(length(t)+1) = toc; tic for i = 1:size(A,3) C{length(C)+1}(:,i) = A(:,:,i)*B; end t(length(t)+1) = toc; disp(t) end 
0
source share

All Articles