MATLAB Answers

Determining Order of flattening an array using colons

28 views (last 30 days)
Vassilis Lemonidis
Vassilis Lemonidis on 23 Sep 2021 at 15:38
Edited: Vassilis Lemonidis on 23 Sep 2021 at 20:10
Hello, I need help understanding how Matlab applies flattening of arrays.
I know it uses a Fortran way of accessing information, so, given an N-D array, the dimension order that will change faster during eg. a reshape will be 1,2,3 etc. (and not N,N-1,N-2 etc as in C-manner). One would expect that, when one tries to reduce the dimensions of an array using colons, the reduction will be done in the same manner as the accessing. However this seems not to hold.
For example, we have an array A with dimensions (X,Y,Z). If we use A(:,:,:) we get the copy of the array. If we use A(:,:) we expect an array with dimensions (X*Y, Z), with the i,j element pointing at (i mod X, i div Y, j) element of A . However, no, what we get is an array (X, Y*Z), with the i,j element pointing at (i, j mod Y, j div Y) element of A. Why does this happen? Is it possible to determine/change this behavior?
Example:
x = cat(3,eye(3), eye(3), eye(3));
x(:,:)
ans =
1 0 0 1 0 0 1 0 0
0 1 0 0 1 0 0 1 0
0 0 1 0 0 1 0 0 1
whereas I would expect
1 1 1
0 0 0
0 0 0
0 0 0
1 1 1
0 0 0
0 0 0
0 0 0
1 1 1
same as when there is the 2 d analog
x = eye(3);
x(:)
1
0
0
0
1
0
0
0
1
  1 Comment
Stephen
Stephen on 23 Sep 2021 at 18:54
"However this seems not to hold."
It most certainly does hold! Lets try it. Your example 3D array:
format compact
x = cat(3,eye(3), eye(3), eye(3))
x =
x(:,:,1) = 1 0 0 0 1 0 0 0 1 x(:,:,2) = 1 0 0 0 1 0 0 0 1 x(:,:,3) = 1 0 0 0 1 0 0 0 1
has its elements stored in this order:
x(:) = 1:27
x =
x(:,:,1) = 1 4 7 2 5 8 3 6 9 x(:,:,2) = 10 13 16 11 14 17 12 15 18 x(:,:,3) = 19 22 25 20 23 26 21 24 27
Using two subscripts keeps exactly the same order (just as expected):
y = x(:,:)
y = 3×9
1 4 7 10 13 16 19 22 25 2 5 8 11 14 17 20 23 26 3 6 9 12 15 18 21 24 27
y(:) % absolutely no change in the order!
ans = 27×1
1 2 3 4 5 6 7 8 9 10
Your example appears to have the elements in exactly the same order, so it seems that you are mixing up the order of elements with the array size: whilst certainly related, these are not the same thing.

Sign in to comment.

Accepted Answer

Stephen
Stephen on 23 Sep 2021 at 18:26
Edited: Stephen on 23 Sep 2021 at 18:56
"If we use A(:,:) we expect an array with dimensions (X*Y, Z), with the i,j element pointing at (i mod X, i div Y, j) element of A"
No, we don't expect that at all.
In fact the last given index refers to that dimension and also to all infinite trailing dimensions. Your test-case is entirely consistent with that (and this paradigm also informs us that the concept of linear indexing is really just an edge-case of subscript indexing). So a general rule that describes both linear and subscript indexing is actually this:
A(dim1,dim2,..,dimN,ThisDimAndAllTrailingDim)
where N>=0.
And yes, it is documented here:
Loren writes: "Indexing with fewer indices than dimensions If the final dimension i<N, the right-hand dimensions collapse into the final dimension. E.g., if A = rand(1,3,4,1,7) and we type A(1,2,12), then we get the element as if A were reshaped to A(1,3,28) and then indexed into. 28 repesents the product of the final size of the final dimension addressed and the other "trailing" ones."
and she then proceeds to give a detailed example. Take a look!
"One would expect that, when one tries to reduce the dimensions of an array using colons, the reduction will be done in the same manner as the accessing."
It is.
" Is it possible to determine/change this behavior?"
I doubt that you would convince TMW to redesign this very simple indexing concept into your much more complicated concept that requires MOD and DIVISION and whatnot, but you can certainly try:
  1 Comment
Vassilis Lemonidis
Vassilis Lemonidis on 23 Sep 2021 at 20:08
I see, so the notation is to be perceived as "freezing" early dimensions and squeezing the ones not included in the indexing, that makes sense. So, to see that the reduction is done in the same manner as the accessing, reshape(A, [], size(A,3)) gives out an (X*Y,Z) array and reshape(A, size(A,1), []) gives out a (X, Y*Z) array, the same as the one being produced by A(:,:) . With the third index missing, the former correspondence would seem more matching, under the Python/C way of thinking, but it is the latter one. Thus, through comparison, it indeed matches the Fortran way of accessing. Thank you for clearing this out to me. Nonetheless pretty complete and resourceful answer.

Sign in to comment.

More Answers (1)

Sulaymon Eshkabilov
Sulaymon Eshkabilov on 23 Sep 2021 at 16:20
How about this:
A = cat(3, eye(3), eye(3), eye(3))
B =reshape(A(:,:).',3,[])
  1 Comment
Vassilis Lemonidis
Vassilis Lemonidis on 23 Sep 2021 at 17:02
Sure, thanks for the effort, but what I am seeking here is the reason behind what is happening, and whether this can be alleviated. Coming from a numpy environment, I face something that looks so ugly in implementation, and it makes no sense to me why. Is it speed? Is it something else? Can I change globally this behavior in my program? It does not make any mathematical sense.

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!