Search code examples
matlabmatrix-multiplicationelementwise-operations

Element-wise mutiplication .* of vectors gives matrix in Matlab


Given two vectors

a = 1:3;
b = 2:4;

it's well known that the element-wise mutiplication a.*b produces

[ 2  6  12 ]

Calling that result c, we have c(i) = a(i)*b(i)

But I don't understand how a.*b', b'.*a and b'*a all produce

[ 2     4     6
  3     6     9
  4     8    12 ]

For the matrix multiplication b'*a, we know c(i,j) = b(i)*a(j).
But why do the other two also produce the same result?


Solution

  • Due to implicit expansion (introduced in 2016b) it's essentially the same as using bsxfun.
    But what does that mean?

    Setup:

    a = 1:3;
    b = 2:4;
    
    • All MATLAB versions:

      c = a.*b; 
      % c = [2 6 12], element-wise multiplication c(j) = a(j)*b(j)
      
      c = b'*a;  
      % c = [2 4 5; 3 6 9; 4 8 12]
      % standard matrix multiplication of vectors
      % c(i,j) = a(i) + b(j)
      
      c = bsxfun(@times, b', a)
      % c = [2 4 5; 3 6 9; 4 8 12]
      % bsxfun applies the function (in this case @times) to b' and a
      

      By definition, bsxfun "applies the element-by-element binary operation specified by the function handle fun to arrays A and B, with singleton expansion enabled". This means that singleton dimensions (dimensions whose size is 1) are expanded row-wise/column-wise to match the size of the other argument supplied to bsxfun.

      So, bsxfun(@times, b', a) is equivalent to

       % b' in singleton in the 2nd dimension, a is singleton in the 1st dimension
       % Use repmat to perform the expansion to the correct size
       repmat(b', 1, size(a,2)) .* repmat(a, size(b',1), 1)
       % Equivalent to...
       repmat(b', 1, 3) .* repmat(a, 3, 1)
       % Equivalent to...
       [2 2 2; 3 3 3; 4 4 4] .* [1 2 3; 1 2 3; 1 2 3]   
       % = [2 4 5; 3 6 9; 4 8 12] the same as b'*a
      
    • Before R2016b

      c = a.*b'; % Error: Matrix dimensions must agree.
      c = b'.*a; % Error: Matrix dimensions must agree.
      
    • Since R2016b

      Newer MATLAB versions use implicit expansion, which basically means that a bsxfun equivalent is called 'under the hood' if necessary for a valid operation.

      c = a.*b'; % [2 4 5; 3 6 9; 4 8 12] the same as bsxfun(@times, a, b')
      c = b'.*a; % [2 4 5; 3 6 9; 4 8 12] the same as bsxfun(@times, b', a)
      % These two are equivalent also because order of operations is irrelevant
      % We can see this by thinking about the expansion discussed above
      

    As you've noticed, this can be confusing if you don't keep track of your vector orientations! If you ever want to get a 1D output (without expansion), then you can ensure your inputs are 1D column vectors by using the colon operator like so

    c = a(:).*b(:); % c = [2; 6; 12] always a column vector