Make a 3D matrix block diagonal

5 views (last 30 days)
KostasK
KostasK on 17 Apr 2022
Answered: Aman Banthia on 28 Sep 2023
Hi all,
I have a 3-D matrix which I would like to make block-diagonal on its 2nd dimention. In my case I have:
clear ; clc
v = 1:3672 ;
Nc = 18 ; % Rows
Nb = 4 ; % Columns
nn = 51 ; % Pages
M = reshape(v, Nc, Nb, nn) ; % 3D matrix which contains experimental data in my case
a small section of which looks like this:
>> M(:,1:3,1)
ans =
1 19 37 55
2 20 38 56
3 21 39 57
and I would want to make it look like this:
>> M(:,1:3,1)
ans =
1 19 37 55 0 0 0 0 0 0 0 0
0 0 0 0 2 20 38 56 0 0 0 0
0 0 0 0 0 0 0 0 3 21 39 57
And my attempt to make this happen is the following code:
clear ; clc
v = 1:3672 ;
Nc = 18 ; % Rows
Nb = 4 ; % Columns
nn = 51 ; % Pages
M = reshape(v, Nc, Nb, nn) ; % 3D matrix which contains experimental data in my case
Mn = zeros(Nc, Nc*Nb, nn) ; % Preallocated new matrix with extended number of columns
% Convert subscripts to linear indices for the new matrix
ind = sub2ind(size(Mn), repmat(1:Nc, 1, Nb*nn), ...
repmat(reshape(reshape(1:(Nc*Nb), Nb, Nc)', Nb*Nc, 1), nn, 1)', ...
repelem(1:Nb, Nc*nn)) ;
% Allocate the old matrix M into the new Mn for the above calculated indices
Mn(ind) = M ;
However, the above doesn't work as with a quick test even though the Mn matrix has the right shape, the allocation of the elements is not done in the appropriate places.
Preferably I would like to avoid blkdiag because I have to perform this for a very large number of other matrices and I have noticed from past experience that this function is fairly slow.
Thanks for your help in advance.

Accepted Answer

Aman Banthia
Aman Banthia on 28 Sep 2023
Hi Kostas,
It seems like you're trying to reshape a 3D matrix into a block-diagonal matrix on its 2nd dimension. The issue you're encountering is due to the incorrect calculation of linear indices for the new matrix.
You can try the following code which uses a loop over the third dimension of your matrix ‘M’. This code will create a block-diagonal structure where each block comes from the corresponding 2D slice of ‘M’. It's not using ‘blkdiag’ function, thus it should be faster.
clear ; clc
v = 1:3672 ;
Nc = 18 ; % Rows
Nb = 4 ; % Columns
nn = 51 ; % Pages
M = reshape(v, Nc, Nb, nn) ; % 3D matrix which contains experimental data in my case
Mn = zeros(Nc, Nc*Nb, nn) ; % Preallocated new matrix with extended number of columns
for k = 1:nn
for i = 1:Nc
Mn(i, ((i-1)*Nb+1):i*Nb, k) = M(i,:,k);
end
end
This code will create a new matrix ‘Mn’ where each row of each 2D slice of ‘M’ is placed on the diagonal of the corresponding 2D slice of ‘Mn’.
If you face performance issues with this code, you might need to consider using a sparse matrix representation or other optimization techniques.
Refer to the following MATLAB Documentation Link to know more about ‘blkdiag’ function:
Hope the above solution helps you.
Best Regards,
Aman Banthia

More Answers (0)

Community Treasure Hunt

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

Start Hunting!