3

I've been trying to figure out the algorithm behind NumPy's matrix multiplication for complex numbers:

import numpy as np

A = np.array([[17.+0.j, -3.+0.j],
              [-7.+0.j,  1.+0.j]])

B = np.array([[ 60.+0.j,  -4.+0.j],
              [-12.+0.j,   0.+0.j]])

print(A * B)

It outputs:

[[1020.+0.j   12.-0.j]
 [  84.-0.j    0.+0.j]]

The result from a standard matrix multiplication is very different, as you can see by the numbers below, so I'm left wondering what it is exactly that NumPy does:

[[1056.+0.j  -68.+0.j]
 [-432.+0.j   28.+0.j]]

I've been trying to reproduce their multiplication algorithm using just for loops but I still haven't found the answer. Any tips?

karlphillip
  • 92,053
  • 36
  • 243
  • 426
  • `*` is element-wise multiplication, you're probably looking for [`numpy.matmul()`](https://numpy.org/doc/stable/reference/generated/numpy.matmul.html?#numpy-matmul). – AMC May 11 '20 at 18:51
  • @AMC Nope. In this case, it uses `np.multiply()` behind our backs. – karlphillip May 11 '20 at 19:01
  • I'm confused, what are you referring to? – AMC May 11 '20 at 19:02
  • The question asked what type of multiplication NumPy does between two matrices of complex numbers. The answer is `np.multipy()`. Also, please don't remove the tags again. – karlphillip May 11 '20 at 19:06
  • _The question asked what type of multiplication NumPy does between two matrices of complex numbers. The answer is `np.multiply()`._ That’s true, although I believe it’s always the case when it comes to ndarrays. That lead to some confusion with the old `nump.matrix` class, see https://stackoverflow.com/questions/3890621/how-does-multiplication-differ-for-numpy-matrix-vs-array-classes for example. – AMC May 11 '20 at 19:14

2 Answers2

4

When you compute A*B it's actually multiplying the matrices elementwise, giving you what is called the hadamard product. It isn't matmul. For example (17.+0.j) * (60.+0.j) = 1020.+0.j, which is the first element in the output. For matrix multiplication use np.dot or simply the @ operator, ie, A@B.

Mercury
  • 3,417
  • 1
  • 10
  • 35
  • There's also `numpy.matmul`, which can be used instead of the `@` operator, and they're the recommended solution when both the arrays are 2-D. – AMC May 11 '20 at 18:55
  • Correct, **element-wise multiplication** is the answer for this question. This can be achieved with `np.multiply()`. – karlphillip May 11 '20 at 19:07
1

Found it! It seems NumPy uses np.multiply() (element-wise multiplication), hence the different results.

Here is a naive implementation of this function using for loops:

def np_multiply(X, Y):
    height = X.shape[0]
    width = X.shape[1]
    output = np.empty((height, width), dtype=np.complex128)

    for i in range(height):
        for j in range(width):
            output[i,j] = X[i, j] * Y[i, j]

    return output

This post has an interesting discussion on its performance.

karlphillip
  • 92,053
  • 36
  • 243
  • 426
  • No, Not under this specific scenario, numpy always uses elementwise multiplication with `*`. The o ly exceptio is the now deprecated np.matrix class. – MaxNoe May 11 '20 at 19:07