2

I have 2 matrices A (nxm) and B (nxd) and want to multiply element-wise each column of A with a row of B. There are m columns in A and n 1xd vectors in B so the results are m nxd matrices. Then I want to sum(result_i, 1) to get m 1xd vectors, which I want to apply vertcat to get a mxd matrix. I'm doing this operations using for loop and it is slow because n and d are big. How can I vectorize this in matlab to make it faster? Thank you.

EDIT:
You're all right: I was confused by my own question. What I meant by "multiply element-wise each column of A with a row of B" is to multiply n elements of a column in A with the corresponding n rows of B. What I want to do with one column of A is as followed (and I repeat this for m columns of A, then vertcat the C's vector together to get an mxd matrix):

column_of_A =

     3
     3
     1


B =

     3     1     3     3
     2     2     1     2
     1     3     3     3


C = sum(diag(column_of_A)*B, 1)

     16    12    15    18
4
  • 2
    If you multiply each col of A with each row of B, then you get m*n matrices, not m. If not, then how do you choose a row from B for a given col of A? Is it given in advance? Commented Apr 7, 2011 at 12:13
  • @Itamar Katz: I should say multiply each element of the m columns of A elementwise with each row of B, i.e. [1 2 3]' * [1 1]=[1 1; 2 2; 3 3]. Commented Apr 7, 2011 at 12:36
  • this is not element-wise multiplication, but instead, it is a matrix multiplication. Commented Apr 7, 2011 at 13:06
  • Just to re-state what @Itamar Katz said: Say you multiply the first col of A with the first row of B to get a mxd array. Then you multiply the first col of A with the second row of B. Then the first col of A with the third row of B, and so on. Then you start multiplying the second col of A with the first row of B, etc. Thus, you'll end up with m*n arrays of size mxd. Commented Apr 7, 2011 at 13:17

3 Answers 3

6

You can vectorize your operation the following way. Note, however, that vectorizing comes at the cost of higher memory usage, so the solution may end up not working for you.

%# multiply nxm A with nx1xd B to create a nxmxd array
tmp = bsxfun(@times,A,permute(B,[1 3 2]));

%# sum and turn into mxd
out = squeeze(sum(tmp,1));

You may want to do everything in one line, which may help the Matlab JIT compiler to save on memory.

EDIT

Here's a way to replace the first line if you don't have bsxfun

[n,m] = size(A);
[n,d] = size(B);
tmp = repmat(A,[1 1 d]) .* repmat(permute(B,[1 3 2]),[1,m,1]);
Sign up to request clarification or add additional context in comments.

7 Comments

@Jonas This doesn't seem to generate an mxd matrix. It gives me an nxd (same size as B). That or I'm doing something horribly stupid (quite possible).
@Darhuuk: Oh, I summed along the wrong dimension. Thanks for the heads-up!
@Jonas No problem :). Nice method, didn't know about bsxfun, seems to be about 3-10x faster than what I proposed on the small matrices I'm testing with.
@Jonas: Thank you. Can you explain a bit about how you chose the permute order [1 3 2]? Thanks.
@Martin08: I want to turn a nxd array into a nx1xd array. Thus, I need to turn dimension #2 into dimension #3. Permute allows me to reorder dimensions of a matrix, so I want to write permute(B,[1,X,2]). For X, I can choose any of the dimensions of B that have length 1. One of them is the current dimension 3 (since B is a nxdx1 array), but I could also have set X to 4 (since B is a nxdx1x1 array).
|
1

It's ugly, but as far as I can see, it works. I'm not sure it will be faster than your loop though, plus, it has a large memory overhead. Anyway, here goes:

A_3D = repmat(reshape(A, size(A, 1), 1, size(A, 2)), 1, size(B, 2));
B_3D = repmat(B, [ 1 1 size(A, 2)]);
result_3D = sum(A_3D .* B_3D, 1);
result = reshape(result_3D, size(A, 2), size(B, 2))

What it does is: make A into a 3D matrix of size n x 1 x m, so one column in each index of the 3rd dimension. Then we repeat the matrix so we get an n x d x m matrix. We repeat B in the 3rd dimension as well. We then do a piecewise multiplication of all the elements and sum them. The resulting matrix is a 1 x d x m matrix. We reshape this into a m x d matrix.

I'm pretty sure I switched around the size of the dimensions a few times in my explanation, but I hope you get the general gist.

Multiplying with a diagonal matrix seems at least twice as fast, but I couldn't find a way to use diag, since it wants a vector or 2D matrix as input. I might try again later tonight, I feel there must be a faster way :).

[Edit] Split up the command in parts to at least make it a little bit readable.

Comments

0

This is the way I would do this:

sum(repmat(A,1,4).*B)

If you don't know the number of columns of B:

sum(repmat(A,1,size(B,2)).*B)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.