Multiplying rows of matrix without bsxfun or for loops

I have two matrices A and B generated as follows:
x = 2;
y = 4;
A = kron(eye(x), ones(1,y));
littleB = horzcat(zeros(y-1,1),eye(y-1));
B = repmat(littleB, [1,x]);
I now want to multiply (element-wise) each row of A with each row of B to get a matrix output like:
0 1 0 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 1
I want to avoid the use of for-loops. I tried to use bsxfun but get an error (Non-singleton dimensions of the two input arrays must match each other), which I understand is caused by the fact that A has two rows (if A was just one row this would work). What would be the best way to achieve what I am trying to do? Any help would be much appreciated.

 Akzeptierte Antwort

Roger Stafford
Roger Stafford am 18 Sep. 2014
a = size(A,1);
b = size(B,1);
C = A(repmat(1:a,b,1),:).*repmat(B,a,1);

5 Kommentare

Note, in older versions of MATLAB, repmat uses an MCoded for-loop.
I am hoping they have improved it since then. It can be a very useful function.
Yes, it is a built-in function in the latest versions, but still greedier in memory-consumption than bsxfun, of course.
Thanks Roger - I have accepted this answer. Do you know if it would be computationally more efficient than the answer provided by Matt?
I have seen several instances where a replication of the kind achieved by
A(repmat(1:a,b,1),:)
would be useful - that is, where the first row is repeated so many times, then the next row and so forth. It can also be accomplished using 'kron' and 'ones', but that may not be any more efficient than the above method. Perhaps Mathworks ought to consider providing a built-in function to do repetition of this kind efficiently - or perhaps they could expand the functionality of the existing 'repmat' to achieve this.
I can also conceive of a more general alternate to 'bsxfun' that could operate in such a manner - that is, perform operations with various prescribed kinds of repetition similar to the above for two different arrays instead of merely expanding singleton dimensions.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (1)

Matt J
Matt J am 18 Sep. 2014
Bearbeitet: Matt J am 18 Sep. 2014
This is almost what you want, I think,
Bp=permute(B,[3 2 1]);
C=bsxfun(@times,A,Bp);
apart from the shape of the final result C. Although I don't see why you wouldn't prefer a 3D output.

3 Kommentare

Matt J
Matt J am 18 Sep. 2014
Bearbeitet: Matt J am 18 Sep. 2014
If you want the result presented in the 2D form you propose,
Ap=permute(A,[2,3,1]);
C=bsxfun(@times,Ap,B.');
C=reshape(C,size(A,2),[]).'
This requires more transposing/permuting operations, which are expensive for large matrices. You could avoid this by organizing your data column-wise instead of row-wise.
Thanks for this. It does answer my original question. As you point out that this code could be expensive for larger matrices I accepted Roger's answer instead as it seems computationally more efficient - although I do not know for sure...
Matt J
Matt J am 18 Sep. 2014
Bearbeitet: Matt J am 18 Sep. 2014
No, Roger's is less efficient computationally (it requires data copying via repmat of A and B data whereas bsxfun does not), but his does have a simpler syntax, which can sometimes be just as important! Time you save in computation can be lost on debugging complicated-looking code.

Melden Sie sich an, um zu kommentieren.

Kategorien

Gefragt:

am 18 Sep. 2014

Bearbeitet:

am 18 Sep. 2014

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by