Help with vectorizing Diag command

I have an MxN matrix, which I would like to turn into an MxNxN matrix, where the elements in the second and third dimensions are a diagonal matrix. It can be done in a for loop by
for ii=1:M
newMat(ii,:,:)=diag(oldMat(ii,:))
end
Any ideas on how to vectorize this? Thanks

 Akzeptierte Antwort

Jan
Jan am 7 Jul. 2012
Bearbeitet: Jan am 7 Jul. 2012

0 Stimmen

Pre-allocate:
clear
M = 200;
N = 300;
oldMat = rand(M, N);
tic; % ORIGINAL
for ii=1:M
newMat(ii,:,:) = diag(oldMat(ii,:));
end
toc % 16.71 seconds (Matlab 2009a/64, Win7, Core2Duo)
tic; % REPMAT
[m, n] = size(oldMat);
idx = permute(repmat(logical(eye(n)), [1, 1, m]), [3, 2, 1]);
nM = idx+0;
nM(idx) = oldMat;
toc % 1.10 sec
clear newMat
tic; % WITH PRE-ALLOCATION
newMat = zeros(M, N, N); % Pre-allocate!!!
for ii=1:M
newMat(ii,:,:) = diag(oldMat(ii,:));
end
toc % 0.68 seconds
clear newMat
tic; % BSXFUN
newMat = zeros(M,N,N);
newMat(bsxfun(@plus,(1:M)', (0:N-1)*(M*N+M))) = oldMat;
toc % 0.076 seconds

Weitere Antworten (3)

Sven
Sven am 7 Jul. 2012
Bearbeitet: Sven am 7 Jul. 2012

0 Stimmen

Hi Brendan, is this the answer you're looking for?
M = 2, N = 3
oldMat = reshape(1:M*N,M,N)
newMat = zeros(M,N,N)
newMat(bsxfun(@plus,(1:M)',(0:N-1)*M*(N+1))) = oldMat
It uses the bsxfun command to build a list of indices equivalent to the non-zero elements of your newMat, and just populates these elements directly from oldMat.
I haven't tested, but I suspect it will be faster than the loop. Hope it's helpful.
[Edit]
Just tested for M = 200, N = 300:
Elapsed time is 8.962171 seconds. <- loop method
Elapsed time is 1.915089 seconds. <- bsxfun method

2 Kommentare

Jan
Jan am 7 Jul. 2012
In my measurements BSXFUN is much faster.
Sven
Sven am 7 Jul. 2012
Oh, I wasn't timing just once... I gave it a few loops which is why my numbers are over 1 second :) Either that or my pc runs like treacle.
And for fairness to the loop method, my comparison used preallocation.

Melden Sie sich an, um zu kommentieren.

Andrei Bobrov
Andrei Bobrov am 7 Jul. 2012

0 Stimmen

[m,n] = size(oldMat);
idx = permute(repmat(logical(eye(n)),[1,1,m]),[3 2 1]);
nM = idx+0;
nM(idx)=oldMat;

Kategorien

Mehr zu Performance and Memory finden Sie in Hilfe-Center und File Exchange

Gefragt:

am 7 Jul. 2012

Community Treasure Hunt

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

Start Hunting!

Translated by