How to operate properly with multidimensional matrices and cells.

13 views (last 30 days)
Let's create as an example the following 3D-cell:
l=0;for i=1:3;for j=1:3;for k=1:3;l=l+1;C{i,j,k}=l;end;end;end
Or the corresponding 3D matrix:
M=cell2mat(C);
Then my issue is that, unlike what I expected, Matlab doesn't appear to be able to operate on multidimensional matrices and cells the way it can handle a simple 2D object, when it should be straight forward. Matlab appears to consider the objects as a series of 2D matrices/cells with the first two entries being their dimensions, and the last entry being the series.
This shows when I want to extract a 2D set from the 3D matrix.
If we ask for
M(:,:,1)
Then there's no issue. Matlab can extract the matrix just fine and we get:
ans =
1 4 7
10 13 16
19 22 25
For the other two, however, it goes wrong:
M(1,:,:)
ans(:,:,1) =
1 4 7
ans(:,:,2) =
2 5 8
ans(:,:,3) =
3 6 9
M(:,1,:)
ans(:,:,1) =
1
10
19
ans(:,:,2) =
2
11
20
ans(:,:,3) =
3
12
21
So here's my question:
I'm working on a project that gives me results in Vector and matrix forms. However, there are several ways of doing these.
For example, I have several modes, identification methods, and correlation functions, and my objective is to compare their performance.
If I were to only do one method, the problem of course does not exist, as the dimension would be e.g. m*n*1*1*1,which means the results are 2D. But because I want to compare the different approaches, the results become multidimensional.
So for the 3D example above, imagine the 2D matrix as a square, and the 3D as a cube, and me as the person wanting to be able to slice it into bits orthogonal to any of the 3 dimensions.
In short, what is the straight forward way to do this? It's permute, right?
I.e:
permute(M(:,:,1),[1 2 3])%essentially the same as just skipping the permutation
permute(M(:,1,:),[1 3 2])
permute(M(1,:,:),[3 2 1])
And the answer to slicing it any way other than standard will have to be to do a permutation first?
So I think I answered my own question whilst asking it, but just to make sure, I'd greatly appreciate any feedback to this.
I'm wondering if there's a more straight forward way, if I've overlooked something, and if anyone here has some tips as to what one should or shouldn't do in this regard? Thank you in advance for having read through this and any answer you might be about to give.
Also, I haven't yet gone ahead and tested it on 4D, but if anyone has, can you give me a heads up as to whether this extrapolates to this additional dimension or if there are additional pitfalls?
  2 Comments
SALAH ALRABEEI
SALAH ALRABEEI on 14 Jun 2021
This might be semi-automatic but not sure if it fix ur issue
[a,b,c] = size(M);
r2 = cat(1,M(a-2:b*c:end),M(a-1:b*c:end),M(a:a*b:end));
r1 = reshape(M(1:a:end),b,c)';
% whereas for r3, u already know it M(:,:,1);
Stephen23
Stephen23 on 14 Jun 2021
Edited: Stephen23 on 14 Jun 2021
"Matlab doesn't appear to be able to operate on multidimensional matrices and cells the way it can handle a simple 2D object, when it should be straight forward."
It is very straightforward.
The simple constistency of MATLAB'S everything-is-an-array-regardless-of-how-many-dimensions-it-has philosophy is one of the main reasons that I am still using it, even after using Julia (ugh, the transpose confusion), numpy, R, etc...
"For the other two, however, it goes wrong:"
How exactly are they "wrong"?
In this example your indexing specifies one row, all columns, and all pages... and that is exactly what MATLAB returns:
M(1,:,:)
ans(:,:,1) =
1 4 7
ans(:,:,2) =
2 5 8
ans(:,:,3) =
3 6 9
In this example your indexing specifies all rows, one column, and all pages... and that is exactly what MATLAB returns:
M(:,1,:)
ans(:,:,1) =
1
10
19
ans(:,:,2) =
2
11
20
ans(:,:,3) =
3
12
21
"Matlab appears to consider the objects as a series of 2D matrices/cells with the first two entries being their dimensions, and the last entry being the series."
MATLAB's multi-dimensional arrays behave like multi-dimensional arrays. Your explanation does not match my experience of using multi-dimensional arrays inm MATLAB, nor what the MATLAB documentation explains:
Because "series" is not defined in your question (nor used in the MATLAB documentation), it is unclear what you expect those (apparently perfectly consistent, correct, reliable) indexing operations to achieve.
Are you expecting MATLAB to make dimensions disappear when you perform indexing? (e.g. to magically remove scalar dimensions, thus leading to unpredictable, totally unusable code and everyone abandoning MATLAB) Or to return everything as a 2D matrix, regardless of the actual dimensions the data really has? (ugh... the horror!) Or to automatically permute the dimensions according to some (so far unwritten) rule that suits only your needs?
"So for the 3D example above, imagine the 2D matrix as a square, and the 3D as a cube"
Seems reasonable... and it explains exactly the examples shown in your question.
So far you have not explained why you think that those correct outputs are "wrong".

Sign in to comment.

Accepted Answer

Jan
Jan on 14 Jun 2021
Edited: Jan on 14 Jun 2021
"For the other two, however, it goes wrong:"
No, nothing goes wrong. This is exactly what is expected and needed.
Only the display in the command window might look different to what you expect. But for calculations you can use X(:, :, 1) as well as X(1, :, :). The first has the advantage, that the memory for the data is contiguos, while the latter uses slices in the memory. But Matlab handles this automatically, so you do not have to care for it.
Do you know the command squeeze() to remove singelton dimensions? Using reshape directly is an option also to remove singelton dimensions.
  3 Comments
Stephen23
Stephen23 on 14 Jun 2021
Edited: Stephen23 on 14 Jun 2021
"If I use it well I can effectively skip out on the permute() command and avoid the memory slicing"
Personally I would avoid SQUEEZE and always use PERMUTE, because SQUEEZE is a latent bug in your code: consider what happens if you write your code and test your code on a few ND-arrays which all have 2nd dimension >1. Then one day you run the code on some data with 2nd dimension =1. Ooopss... all of the other dimensions have completely changed position, no warning, if you are lucky you might get an error later in your code... Unless you fill your code with lots of ASSERTS containing size checks, SQUEEZE is just a bug waiting to happen.
Memory slicing is not a concept that can be usefully applied to MATLAB's memory management. Whatever you learned from other languages should remain with those other languages. Trying to second-guess and micro-manage MATLAB's memory manage usually does not end well: first write code that is clear and does what you need it to do.
Jan
Jan on 14 Jun 2021
Instead of using squeeze I prefer to call reshape directly, because this save some microseconds.

Sign in to comment.

More Answers (1)

J. Alex Lee
J. Alex Lee on 14 Jun 2021
You might be looking for squeeze()?
l=0;
% preallocate
C = cell(3,3,3);
M = nan(3,3,3);
% construct 3D cell and matrix together
for i=1:3
for j=1:3
for k=1:3
l=l+1;
C{i,j,k} = l;
M(i,j,k) = l;
end
end
end
C2M = cell2mat(C);
% here is a way to generate inline depending on what you need
MIL = permute(reshape(1:27,3,3,3),[3,2,1]);
% check equality of results
isequal(M,C2M)
isequal(M,MIL)
% i believe this is what you are looking for
squeeze(M(1,:,:))

Products


Release

R2020b

Community Treasure Hunt

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

Start Hunting!