The similarities and differences between NumPy's tensordot and einsum functions are well documented and have been extensively discussed in this forum (e.g. [1], [2], [3], [4], [5]). However, I've run into an instance of matrix multiplication using einsum that I'm finding very difficult, if not impossible, to replicate using tensordot: If our two arrays are,
>>> A = np.array([[0, 1], [1, 0]])
>>> B = np.arange(2 ** 4).reshape((2, 2, 2, 2))
does there exist a one line tensordot equivalent to the following?
>>> np.einsum("ab,ibjk->iajk", A, B)
array([[[[ 4, 5],
[ 6, 7]],
[[ 0, 1],
[ 2, 3]]],
[[[12, 13],
[14, 15]],
[[ 8, 9],
[10, 11]]]])
From what I've found, the answer seems to be "no". The trouble arises in the indexing of the output dimension, iajk. Here, dimension a of array A appears in-between dimensions i and j of array B. Had the indexing of the output dimension instead been aijk, np.tensordot(A, B, (1, 1)) would have worked fine. I ran a test using all possible axes to be sure,
>>> output_einsum = np.einsum("ab,ibjk->iajk", A, B)
>>> axes_A = [-2, -1, 0, 1]
>>> axes_B = [-4, -3, -2, -1, 0, 1, 2, 3]
>>> for i in axes_A:
... for j in axes_B:
... output_tensordot = np.tensordot(A, B, axes=(i, j))
... if np.allclose(ouput_einsum, output_tensordot):
... print(i,j)
...
and found that no combination of the allowed axes produced the desired result. Note that the dimension of B limits each element of the axes parameter to length one. Is it correct that einsum functions with interleaving output dimensions cannot be reproduced in one line using tensordot? And if is so, does there exist a multi-line work-around?
As I stress in my earlier answers,
tensordotis an extension ofnp.dot, allowing us to specify which dimensions are used in the sum-of-products. Thedotdefault is last of A, 2nd to the last of B.This illustrates how
dothandles dimensions greater than 2:The way
tensordotputs it, the noncontracted dimensions ofBfollow those ofA. So taking the same arrays, but shifting the axes, produces the same thing.In these examples I chose distinct dimensions so the order is more obvious.
tensordotdoes not provide a way of reordering the noncontracted dimensions. But you can easily do that yourself after.Your example has size 2 dimensions all around. This allows you to specify any combination of axes, but requires the use of
allcloseto test results.Performing the sum-of-products on the 2nd axis of both arrays:
And the
einsumwith its default result ordering ('aijk')The
tensordotis the equivalent of thisdot: