X = np.einsum('ik,jk->ij', np.conj(x), x)
は
X = np.empty((x.shape[0], x.shape[0]), dtype='complex128')
for i in range(x.shape[0]):
for j in range(x.shape[0]):
X[i, j] = np.vdot(x[i], x[j])
np.einsum
と同等である積の和をとります。第2引数は、 np.conj(x)
は添字ik
と三番目の引数を持つ配列であるnp.einsum
に指示'ik,jk->ij'
添字、x
は jk
添え字を有します。したがって、全ての製品についてnp.conj(x)[i,k]*x[j,k]
が計算される。 i
,j
,k
。合計は、反復された添え字k
を引き継いでおり、 が残っているので、i
とj
が残っているので、結果の配列の添字になります。
例えば、
import numpy as np
N, M = 10, 20
a = np.random.random((N,M))
b = np.random.random((N,M))
x = a + b*1j
def orig(x):
X = np.empty((x.shape[0], x.shape[0]), dtype='complex128')
for i in range(x.shape[0]):
for j in range(x.shape[0]):
X[i, j] = np.vdot(x[i], x[j])
return X
def alt(x):
return np.einsum('ik,jk->ij', np.conj(x), x)
assert np.allclose(orig(x), alt(x))
In [307]: %timeit orig(x)
10000 loops, best of 3: 143 µs per loop
In [308]: %timeit alt(x)
100000 loops, best of 3: 8.63 µs per loop