3

When running following code in Matlab:

a = magic(3);
b = [];

a([],:) = [] % works
a([],:) = b  % doesn't work

I get an error when using variable 'b':

>> tmp
a =
     8     1     6
     3     5     7
     4     9     2
Subscripted assignment dimension mismatch.
Error in tmp (line 5)
a([],:) = b 

Does anyone know what's going on here? Why one assignment works and the other doesn't?

u9rZTV9QAc
  • 83
  • 6
  • 1
    When you say `a([],:) = []` works... you mean it runs without error but it doesn't actually change anything right? So why are you trying to do this? – Dan Jun 19 '14 at 09:52
  • I have much more complex script that has an equivalents of variables 'a' and 'b' from the question. In that script 'b' is sometimes empty and I was wondering if I need to use an if statement or is there some way around it. – u9rZTV9QAc Jun 19 '14 at 10:03
  • I'm assuming the index `ind` used in `a(ind) = b` is also _sometimes_ empty, and sometimes not? – Stewie Griffin Jun 19 '14 at 10:04
  • 1
    Well `a([],:)` expects `0xsize(a,2)`, thus an alternative would be `a([],:) = zeros(0,size(a,2))` I think, but not sure if this would work for your actual case. – Divakar Jun 19 '14 at 10:06
  • I think use an `if` statement, it should also make your code more explicit and thus easier to comprehend – Dan Jun 19 '14 at 10:23
  • @RobertP.: Yes, you're correct, more precisely it's a(ind,:)=b and sometimes both ind and b are empty. – u9rZTV9QAc Jun 19 '14 at 10:38
  • @jjj I still advocate for using an `if`, but it looks like this works: `a([],:) = b(:)` when `b=[]` – Dan Jun 19 '14 at 10:50

1 Answers1

3

Here's my guess at why Matlab behaves like that:

I think that assigning to [] can be considered a special operator, i.e. a(1,:) = [] will essentially delete the first row of a. So even though size(a(1,:)) differs from size([]), I reckon the Matlab interpreter knows that this special case is not an assignment.

However a(1,:) = b when b=[] will give you a subscript dimension mismatch. I think this is correct behaviour because in this case you are assigning, and you're trying to assign a 0-by-0 to a 1-by-3 which is a dimension mismatch. The same goes for a([],:) = b, you're trying to fit a 0-by-0 into a 0-by-3 space which is again a mismatch.

So in conclusion, the second case is an assignment operator and so the error makes sense. The first case is a special delete operator and hence no error.

I have no references for any of this (this is all I could find in the docs but it doesn't really cover everything)


However I don't think this explains all the behaviour, some examples brought up from the comments:

Assume:

a = magic(3);
a2 = magic(4);
b = [];
  1. a([],:) + a2([],:) gives a dimension mismatch error as expected.
  2. a([],:) = a2([],:) does not throw an error... which to me is not expected
  3. a([],:) = b(:) also does NOT throw an error... which is again quite strange, unless we can assume that the (:) operation returns a comma separated list like the {:} does (although I know that is not the case)???

These cases seem inconsistent to me.

We can expand on case 2:

a([],:) = zeros(0,0)
a([],:) = zeros(0,2)
a([],:) = zeros(0,3)
a([],:) = zeros(0,4)

only he first case throws an error and the other 3 are accepted by Matlab. Looks like this answer is just creating further questions :/

Dan
  • 45,079
  • 17
  • 88
  • 157
  • People must not confuse `=[]` with scalar assignment, as `[]` is definitely not scalar. So calling the `assignment to []` a special operation, would make sense for what's going on here. +1 – Divakar Jun 19 '14 at 10:24
  • @Nishant `=[]`, `=b` and `=some_scalar` are three different things here, at least the last two are, because b is `0x0` that isn't scalar and first two are different, if Dan's assumption of "special operator` is trusted. – Divakar Jun 19 '14 at 10:29
  • @Nishant I can't find the documentation for Matlab's assignment operator so this is all guessing, but I agree with Divakar. Matlab also views assigning a scalar as a special case as this is the only time that Matlab does automatic broadcasting. So it's another special case for assigning a 1-by-1 I guess – Dan Jun 19 '14 at 10:29
  • 1
    But if `b` was a scalar i.e, a `1-by-1` matrix instead of `0-by-0` matrix, then the assignment goes through, i.e, `b=3; a([],:) =b;` throws no error. Even if the assignment is `1-by-1` to `0-by-3`. Reason may be that `1-by-1` matrix is converted into a `0-by-3` matrix before the assignment. Then why that conversion does not happens in this case. Is there an explanation for this. – Nishant Jun 19 '14 at 10:30
  • @Nishant I'll stick with my scalars are automatically broadcast argument again, even though broadcasting to a 0 sized dimension is odd. But you raise a good point. I do think that these cases point to some inconsistencies of the design of the language, it would be great to see some documentation to clarify this s bit. – Dan Jun 19 '14 at 10:32
  • 1
    I also thought at first that it's a plain size mismatch, but if you add another matrix `a2 = magic(4);` and run this `a([],:) = a2([],:)`, you get no error even though sizes do not match. – u9rZTV9QAc Jun 19 '14 at 10:41
  • @jjj interesting, Octave does through the error in that case but it seems like Matlab does not. Yet from reading that doc I linked to states "*As with all matrices in MATLAB, you must follow the rules concerning compatible dimensions*" so you would think it should error in this case... – Dan Jun 19 '14 at 10:47
  • @Dan good catch. So it seems that Matlab is inconsistent with size checks in assignment operator. – u9rZTV9QAc Jun 19 '14 at 10:58
  • Found another curious one: say `a3 = zeros(0,3);` and try `a3([],:) = b` - you'll get an error. but run `a3(:,:) = b` - no error. mind that both `a3([],:)` and `a3(:,:)` are `Empty matrix: 0-by-3`. – u9rZTV9QAc Jun 19 '14 at 11:49
  • @jjj That makes a bit of sense to me because `a3(:,:)=b` is the same as `a=b` and so the dimenstions don't matter. Have a look at this question for example: http://stackoverflow.com/questions/18959702/difference-between-first-element-of-1x1-matrix-and-all-elements-of-1x1-matrix/18960060#18960060 – Dan Jun 19 '14 at 11:55
  • @Dan I'm not sure if that's the same - a3 would be `0x0` after that and actually is `0x3`. I would say that `a3([],:)` and `a3(:,:)` are the same in case of empty matrices (or should be) since one says 'take all rows' and the other says 'take no rows'. – u9rZTV9QAc Jun 19 '14 at 11:58