Search code examples
octave

matrix operation not returning correctly


R = [cos(pi/3) sin(pi/3); -sin(pi/3) cos(pi/3)]
[i,j]=round([1 1] * R)

returns

i =

  -0   1

error: element number 2 undefined in return list

While I want i=0 and j=1

Is there a way to work around that? Or just Octave being stupid?


Solution

  • Octave is not being stupid; it's just that you expect the syntax [a,b] = [c,d] to result in 'destructuring', but that's not how octave/matlab works. Instead, you are assigning a 'single' output (a matrix) to two variables. Since you are not generating multiple outputs, there is no output to assign to the second variable you specify (i.e. j) so this is ignored.

    Long story short, if you're after a 'destructuring' effect, you can convert your matrix to a cell, and then perform cell expansion to generate two outputs:

    [i,j] = num2cell( round( [1 1] * R ) ){:}
    

    Or, obviously, you can collect the output into a single object, and then assign to i, and j separately via that object:

    [IJ] = round( [1 1] * R ) )
    i = IJ(1)
    j = IJ(2)
    

    but presumably that's what you're trying to avoid.


    Explanation:

    The reason [a,b] = bla bla doesn't work, is because syntactically speaking, the [a,b] here isn't a normal matrix; it represents a list of variables you expect to assign return values to. If you have a function or operation that returns multiple outputs, then each output will be assigned to each of those variables in turn.

    However, if you only pass a single output, and you specified multiple return variables, Octave will assign that single output to the first return variable, and ignore the rest. And since a matrix is a single object, it assigns this to i, and ignores j.

    Converting the whole thing to a cell allows you to then index it via {:}, which returns all cells as a comma separated list (this can be used to pass multiple arguments into functions, for instance). You can see this if you just index without capturing - this results in 'two' answers, printed one after another:

    num2cell( round( [1 1] * R ) ){:}
    % ans = 0
    % ans = 1
    

    Note that many functions in matlab/octave behave differently, based on whether you call them with 1 or 2 output arguments. In other words, think of the number of output arguments with which you call a function to be part of its signature! E.g., have a look at the ind2sub function:

    [r] = ind2sub([3, 3], [2,8])     % returns 1D indices
    % r = 2   8
    
    [r, ~] = ind2sub([3, 3], [2,8])  % returns 2D indices
    % r = 2   2
    

    If destructuring worked the way you assumed on normal matrices, it would be impossible to know if one is attempting to call a function in "two-outputs" mode, or simply trying to call it in "one-output" mode and then destructure the output.