Why does MATLAB not allow this assignment with the + operator?

Please see these results:
K>> [EndX,EndY,EndZ] = size(planneddose)
EndX =
135
EndY =
180
EndZ =
129
K>> size(planneddose)+[1 1 1]
ans =
136 181 130
K>> [EndX,EndY,EndZ] = size(planneddose)+[1 1 1]
Error using +
Too many output arguments.
I understand what is shown here is some functionality that calls multiple outputs for multiple inputs, whereas size(...)+[...] returns only a single array, but I think this use is intuitive and MATLAB should add it as a feature in the next release. (That is to say, I encounter this problem fairly often...) Is there a better way to accomplish this task, or must I add 1 to each using three additional commands?

7 comentarios

Was going to suggest deal but I don't think it works for numeric vectors the way you want it to.
My follow-up question what's wrong with the 1x3 and just index rather than three distinct variables?
I don't think it's likely to be added as a feature.
size(v)
returns a numeric vector, while
[x,y,z] = size(v)
probably uses the equivalent of varargout, which is a cell array. You'd have to modify arithmetic operations so something like
{2,3,4} + [1 1 1]
was allowed. But then they would have to choose - should the sum be cell or numeric?
Stephen23
Stephen23 el 30 de En. de 2018
Editada: Stephen23 el 30 de En. de 2018
" but I think this use is intuitive and MATLAB should add it as a feature in the next release."
This is not intuitive, for the same reasons that are discussed here:
Because comma-separated lists are equivalent, no matter how they are generated (i.e. written explicitly, or generated from cell array or struct expansion), and regardless of whether they are used as for input or output arguments, then your proposal would mean writing
max(3,2+1)
= 3
but instead expecting this to be equivalent to
max(4,3)
= 4
Ouch. Your proposal make any operation that occurs inside a comma-separated list apply to all of its values, which instantly makes lots of operations totally illogical. Of course + is just syntactical sugar for the binary function plus, so all other binary (or more?) functions would also have to follow this rule:
regexp('abc',strcat('a','b'))
would be equivalent to
regexp('abcb','ab')
Well, that would certainly make using MATLAB much more... adventurous.
Note that not only that, but this proposal would mean a very major change to how MATLAB works: functions (such as the plus in your example) are currently defined for inputs which are objects of some particular classes, but what you are proposing would mean that comma-separated lists themselves would have to become valid input objects. Currently they are not any kind of object at all (at least, not explicitly in the documented syntax). So this would be a major departure from how MATLAB is actually designed/documented because it would require creating a "comma-separated list" object class, and rewriting all functions to be able to handle this new class. I doubt that this would be worth the effort, for such small (and inconsistent) syntax changes that you request.
"That is to say, I encounter this problem fairly often..."
You probably should be using indexing more, rather than splitting up data into separate variables. In general keeping data together makes working with it easier (even trivial things like indices), and makes it easy to write code that automatically adjusts to different array sizes, etc.
"Because comma-separated lists are equivalent, no matter how they are generated (i.e. written explicitly, or generated from cell array or struct expansion),"
Not completely true:
>> [A,B] = 3,5
Too many output arguments.
>> C = {3,5}
C =
1×2 cell array
{[3]} {[5]}
>> [A,B] = C{:}
A =
3
B =
5
Greg
Greg el 30 de En. de 2018
Editada: Greg el 30 de En. de 2018
" This is not intuitive." I argue that it is intuitive. Intuition is devoid of experience (and many of us have difficulty remembering out MATLAB years before experience tempered our intuition). A large number of things that make no programming sense are still completely intuitive - our intuition is allowed to be mistaken.
I must spend more time taking in what you are teaching me about MATLAB mechanics, but as far as semantics go, I do again agree with Greg -- the question at hand is whether we want MATLAB to be an efficient, powerful tool, or easy for beginners to use. I think MathWorks has done a good job balancing these goals (not long ago I gave up on R -- no time to learn all the syntax and new commands, and excessive documentation, even documentation about documentation, unlike MathWorks' concise documentation database), and so I don't mind the strong rebuttal here that size() + [...] shouldn't work (i.e. that arrays and comma-separated lists remain distinct).

Iniciar sesión para comentar.

 Respuesta aceptada

Consider this:
planneddose = zeros(135, 130, 129, 2);
[EndX,EndY,EndZ] = size(planneddose) %works
EndX =
135
EndY =
130
EndZ =
258
>> size(planneddose)+[1 1 1]
Matrix dimensions must agree.
and consider
planneddose = zeros(135,130);
[EndX,EndY,EndZ] = size(planneddose)
EndX =
135
EndY =
130
EndZ =
1
>> size(planneddose)+[1 1 1]
Matrix dimensions must agree.
But in both cases assigning size(planneddose) to three variables was legal.
This is because size() looks at the number of output arguments to figure out the values it should output. In the case of three outputs, it outputs the first two dimensions into the first two variables and it outputs the product of all remaining dimensions in the third variable. This does not mean that the size "is" three dimensions: it is how size is defined. In the case of a single output, it outputs the individual dimensions as a vector, giving all of non-scalar leading dimensions explicitly, minimum two dimensions.
The case of size(planneddose)+[1 1 1] is the single output case, so it outputs a vector of values, of whatever length is appropriate. If you try to assign the resulting vector to three variables you have a problem because you do not have three sources.
There is no way in MATLAB to say that you want multiple outputs of a call or expression to be grouped together into individual elements of some data structure that you can then manipulate as if only a single variable had been returned. You cannot, for example, write
{size(planneddose)}
to get a cell array of the individual outputs from planneddose: this call will consider size() to have a single output so would create a cell array with a single element which is a vector of the dimensions. You cannot select a single output other than the first output either -- no way to do the equivalent of
function {local c; [~, c, ~] = size(planneddose); return c}
as an expression -- no way to write size(planneddose)#2 + 1 to get the second output and add 1 to it. You can have multiple assignments only in the case where the left hand side of an assignment has multiple outputs and the right hand size is a single call or single expansion.

Más respuestas (2)

This works:
planneddose = rand(135, 130, 129); % Create Matrix
Out = num2cell(size(planneddose) + [1 1 1]);
[EndX,EndY,EndZ] = Out{:}
It definitely takes the long way round to accomplish it!

14 comentarios

Daniel Bridges
Daniel Bridges el 31 de En. de 2018
Editada: Daniel Bridges el 31 de En. de 2018
Please pardon me for not accepting your answer - Walter answered the titular question, whereas you answered my discussion's closing question. I consider it bad form on my part to have asked two distinct questions in a single thread, but thank you for this demonstration of cell array indexing.
My pleasure.
Though it is not clear this is a "better" way of writing than three separate variables. A different way, yes. Every time I write num2cell just to be able to {:} it for comma list expansion, I feel grungy, that I have written ugly code.
I just considered it a fun problem, and to see if I could develop a solution for it.
Operating on each output separately is certainly more efficient, and what I would write.
I hope the 1x3 vector output and indexing is what you would write.
Same thing, essentially.
Is this code really better? There is a balancing act between working with non-MATLAB users and writing efficient MATLAB code; it seems to me three separate commands may be more clear to a non-MATLAB proofreader and not take any more time to write.
Star Strider
Star Strider el 1 de Feb. de 2018
Editada: Star Strider el 1 de Feb. de 2018
It could be applicable in certain situations. It would be a one-off, so it would likely be as efficient other more explicit methods. (I have not timed it.)
In most circumstances, I would simply do:
spd = size(planneddose);
NewSize = spd + [1 1 1];
then use the elements of ‘NewSize’ as necessary, remembering what the elements were, not even breaking them out into their separate components. If I wanted the row size, I would use ‘NewSize(1)’, and so for the other dimensions.
There is a certain satisfaction in the challenge of being able to do something like this in two lines of code.
" non-MATLAB proofreader" sounds kind of like asking an artist to check your science homework.
deal() applied to a cell assigns the same value to all of the outputs. You have to deal() a comma separated list (explicit or through expansion) to get different outputs. deal() is not magic -- you can look at the code for it.
I agree with you about the satisfaction of oneline-code, but on the other hand, I wonder if there isn't a "run-on sentence"-type style problem if one tries to put too many commands into a single line ...
One research mentor is accustomed to Fortran; another prefers Python. It seems the Tower of Babel has fallen on computers, too.
Noted. Corrected.
There is definitely a run-on sentence problem, which is why almost any style guide - regardless of language - encourages one executable command per line. Personally, I see no problem in putting a +1 on the same line as the size call, but I wouldn't go further than that.
APL was notorious as being a "write-only language" because of the difficulty of figuring out what someone else's APL code meant. It was quite powerful, and you could do amazing things in one line with it, but understanding them afterwards was a bit of a challenge.

Iniciar sesión para comentar.

[EndX,EndY,EndZ] = deal(size(planneddose)+[1 1 1])

2 comentarios

Greg
Greg el 30 de En. de 2018
Editada: Greg el 30 de En. de 2018
I thought the same thing at first. That copies the same 1x3 output to all three variables.
Greg is correct. KSSV, the goal was to add 1 to each element with only one element stored per variable. Your solution copies all three values to each element.

Iniciar sesión para comentar.

Categorías

Community Treasure Hunt

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

Start Hunting!

Translated by