openlang

Implicit expansion turned my shape bug into a matrix

A row vector times a column vector with .* used to be an error. Since R2016b it isn't. With a = [1 2 3] and b = [1; 2; 3], a .* b is a 3 by 3 matrix of every pairwise product, and no warning.

I had a column where I thought I had a row. The old behaviour would have stopped me right there. The new behaviour fed a matrix into sum without a word, and sum added down the columns and returned a row of three numbers. Plausible numbers. Wrong ones.

Implicit expansion is fine when you mean it. Centering every column with X - mean(X) and no bsxfun is genuinely nicer. But the rule is symmetric, so any dimension of size one stretches, and a vector with the wrong orientation is the most common size-one dimension there is.

Now I check size at function entry with an arguments block and stop treating orientation as cosmetic.

后续讨论 3

顺着彼此的依据读下去
  1. 固定链接

    Julia went the other way on this, which is why I rarely hit it. [1 2 3] + [1, 2, 3] throws a DimensionMismatch there. Broadcasting happens only when you ask for it with a dot, [1 2 3] .+ [1, 2, 3], and then you get the same 3 by 3 result.

    So the shape bug still exists. It needs a dot to trigger it, which is a smaller target. The place people lose track is @., which puts a dot on every call and every arithmetic step in a long expression.

  2. 固定链接

    The dot only removes the silent version, though. Try changing just one thing in kvl's example and write sum(a .* b) in Julia. You get a single number back, not a row, because sum without dims adds every element. A different wrong answer from the same root cause, and now I'm curious which one people catch sooner.

  3. 固定链接

    My own advice above needs a correction. An arguments block with a (1,:) double does not reject a column vector. MATLAB reshapes it into a row to satisfy the size, and the validation docs list that conversion on purpose. So the check I added to catch wrong orientation repairs it instead, and says nothing.

    For the function, fine, it gets a row. For me it meant the caller kept building columns and nothing ever said so. The entry check is explicit now, and the arguments block only does the class.

    function s = total(a)
        arguments
            a double
        end
        if ~isrow(a)
            error("total:notRow", "expected a row vector")
        end
        s = sum(a);
    end

    Now a column gets total:notRow at the call instead of a quiet reshape.

同一个问题的其他角度

  1. Ported a short MATLAB script to R and one result came back as a matrix

    Trying to redo a short MATLAB script in R, and I've barely touched MATLAB before. Most of it came over fine, except for a sin…

    回复 7最近活动 rmatlab
  2. na.rm = TRUE on a group that is all NA

    Per-group totals with tapply(x, g, sum, na.rm = TRUE), and one group came back as 0. Every value in that group is NA. Not a s…

    回复 5最近活动 r
  3. A loop that allocated a column at a time

    Slicing in Julia copies, which I knew and then forgot inside a loop. Take a function that walks the columns of a matrix and d…

    回复 4最近活动 julia