import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
A = np.array([
[1, 2],
[3, 4],
])
B = np.array([
[5, 6],
[7, 8],
])
Matrix multiplication
print(a @ b)
print(A @ B)
32
[[19 22]
[43 50]]
print(np.einsum("i,i", a, b))
print(np.einsum("ij,jk->ik", A, B))
32
[[19 22]
[43 50]]
Trace (Sum of product of diagnal values)
print(np.trace(A))
print(np.einsum("ii->", A))
5
5
Get diagnal
print(np.diag(A))
print(np.einsum("ii->i", A))
[1 4]
[1 4]
Sum over an axis
A
array([[1, 2],
[3, 4]])
print(np.sum(A, axis=0))
print(np.einsum("ij->j", A))
## Under the hood
result = np.zeros((A.shape[1]), dtype=A.dtype)
for j in range(A.shape[1]):
for i in range(A.shape[0]):
result[j] = result[j] + A[i, j]
print(result)
[4 6]
[4 6]
[4 6]
View as result
np.einsum
returns view of the array which is writable.
np.einsum("ii->i", A)[...] = 1
A
array([[1, 2],
[3, 1]])
print(np.einsum("cd,da", A, B))
print(np.einsum("ij,jk", A, B))
[[19 43]
[22 50]]
[[19 22]
[43 50]]
Tensor contraction
a = np.arange(60.).reshape(3,4,5)
b = np.arange(24.).reshape(4,3,2)
print(np.einsum('ijk,jil', a, b))
## Using loops
result = np.zeros((5, 2))
for k in range(a.shape[-1]):
for l in range(b.shape[-1]):
for i in range(a.shape[0]):
for j in range(a.shape[1]):
result[k, l] += a[i,j,k] * b[j, i, l]
print(result)
[[4400. 4730.]
[4532. 4874.]
[4664. 5018.]
[4796. 5162.]
[4928. 5306.]]
[[4400. 4730.]
[4532. 4874.]
[4664. 5018.]
[4796. 5162.]
[4928. 5306.]]
Optimizations
a = np.ones(64).reshape(2,4,8)
path = np.einsum_path('ijk,ilm,njm,nlk,abc->',a,a,a,a,a, optimize="optimal")[0]
for iteration in range(10000):
_ = np.einsum('ijk,ilm,njm,nlk,abc->',a,a,a,a,a, optimize=path)