Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Advanced Matlab: colon indexing of singleton dimension in assignment

Consider this in Matlab:

>> clear M, M(:,:,:,1,:)=rand(10,10,2,1,5); size(M)
ans =
    10 10 2 1 5
>> clear M, M(:,:,:,1,:)=rand(10,10,1,1,5); size(M)
ans =
    10 10 5
>> clear M, M(:,:,1,1,:)=rand(10,10,1,1,5); size(M)
ans =
    10 10 1 1 5

Why doesn't the 2nd code line behave like the 1st one and the 3rd one do? (i.e. maintaining the 5D shape of the array)

Isn't a colon allowed to represent a singleton dimension? (3rd dimension in the second code line)

Can you please pinpoint the corresponding passage in the documentation?

like image 903
root Avatar asked Jun 16 '17 22:06

root


2 Answers

I couldn't find any specific documentation on this matter, so, in addition to speculation, I will be referring to a blog post by Loren Shure: "All about the Colon Operator". Much of it isn't germane to this question. But there is one particular piece of information worth elaborating on, and a quote she ends with that I will begin with:

The : operator behaves differently in MATLAB depending on its usage. This can lead to confusion.

The pertinent piece of information follows an assignment of 2-by-2 to a 1-by-1-by-1-by-4. For example:

>> v(1,1,1,1:4) = 1:4;
>> v(:) = [5,6;7,8]
v(:,:,1,1) =
     5
v(:,:,1,2) =
     7
v(:,:,1,3) =
     6
v(:,:,1,4) =
     8

How did this assignment work? Loren explains:

Notice that I only have to have the same number of elements on both the left- and right-hand sides. The values are poured in from the right-hand side ordered as if that array had been turned into a column vector.

So even though the left-hand and right-hand objects have very different sizes, the appearance of the indexing-: in the assignment will coerce the shape of the right-hand array since there is an element equivalence. And the assignment will be carried out as if the vectors were column-ified, and v was reshape-d to its original shape.


Before moving on to the question examples, I would like to point out that trailing singleton dimensions (1s subscripts) are infinitely implicit on all arrays in MATLAB. To quote from Matrix Indexing:

The number of subscripts specified for [an array at assignment], not including trailing subscripts equal to 1, does not exceed ndims(B).

And we can, indeed, see this:

>> clear A; A(:,:,1,1,1,1,1,1,1,1,1) = rand(2,2)
A =
    0.6355    0.7823
    0.8439    0.2646
>> A(2,2,1,1,1,1,1,1,1,1,1)
ans =
    0.2646
>> clear A; A = 5; A(1,1,1,1,1,1,1,1,1,1,1,1,1,1)
ans =
     5

The trailing singletons, like multiplying by one or adding zero, are always there.


Moving on the question examples, I think the appearance of the indexing-: in an array that is being allocated at-assignment leaves MATLAB in a bit of a bind when it comes to figuring out how to assign the values given the flexibility described above. Unlike Loren's example, M has no shape to preserve (given the preceding clear), but the assignment will still coerce the shape of the right-hand side into something like a column vector. And that coerced arrays does have a shape.

More than likely, the most intuitive behavior, given the code as-is, would be to preserve the right-hand side's shape when assigning its values to M. However, another perspective may be to preserve as much of the shape of M as possible will minimizing the size of the result of the assignment.

The first behavior is immediately accomplished by having no indexing whatsoever in the assignment. And I think the latter behavior is more in-line with Loren's statement that "values are poured in from the right-hand side ordered as if that array had been turned into a column vector". Once the right-hand has been column-ified, the singleton dimensions are mostly gone, and MATLAB will fill each of the : buckets as much as it can while respecting explicit dimensions, like the 1s present in the examples.

So M(:,:,:,1,:)=rand(10,10,2,1,5); works great because the size of M is minimized exactly by matching the size of the right-hand side. M(:,:,:,1,:)=rand(10,10,1,1,5); size(M) will remove the middle singletons during the shape coercion, the three consecutive assignment-:s will be filled like buckets with the ten-ten-five array to minimize the size of the output, and the remaining singleton dimensions will be ignored since they are implicitly there. And M(:,:,1,1,:)=rand(10,10,1,1,5); works exactly like the first since the third : bucket has been replaced with an explicit index that MATLAB will respect.

I'm not sure if there is an explicit squeeze anywhere in this behavior or if it's just a natural outcome somewhere in the MATLAB engine of the shape coercion. So I think it's best to end with saying that if an array's shape is important, it should be explicitly sized without assignment indexing as much as possible.

like image 158
TroyHaskin Avatar answered Sep 27 '22 20:09

TroyHaskin


See the definition of the squeeze function in matlab:

B = squeeze(A) returns an array B with the same elements as A, but with all singleton dimensions removed. A singleton dimension is any dimension for which size(A,dim) = 1. Two-dimensional arrays are unaffected by squeeze; if A is a row or column vector or a scalar (1-by-1) value, then B = A.

One solution might be in the source of the core, which squeeze the given matrix in some cases. This can be varies in different cases and might be applied to part of the matrix, not on the whole of it.

like image 42
OmG Avatar answered Sep 27 '22 18:09

OmG