At the heart of an application (written in Python and using NumPy) I need to rotate a 4th order tensor. Actually, I need to rotate a lot of tensors many times and this is my
Not a new answer, as all the previous ones deal well with the question. More like a comment, but I post it as an answer to have some space for the code.
While all answers do reproduce the result of the original post, I am pretty sure that the code provided in the original post is wrong. Looking at the formula T'ijkl = Σ gia gjb gkc gld Tabcd, which I believe is correct, the indices for g that are varied in the calculation of each entry of T' are a, b, c & d. However, in the original provided code, the indices used to access the values of g in the calculation of gg are swapped with regard to the formula. Hence, I believe the following code actually provides the correct implementation of the formula:
def rotT(T, g):
Tprime = np.zeros((3, 3, 3, 3))
for i in range(3):
for j in range(3):
for k in range(3):
for l in range(3):
for a in range(3):
for b in range(3):
for c in range(3):
for d in range(3):
Tprime[i, j, k, l] += \
g[i, a] * g[j, b] * \
g[k, c] * g[l, d] * T[a, b, c, d]
The equivalent, but faster, calls to einsum and tensordot update to:
Tprime = np.tensordot(g, np.tensordot(g, np.tensordot(
g, np.tensordot(g, T, (1, 3)), (1, 3)), (1, 3)), (1, 3))
Tprime = np.einsum('ia, jb, kc, ld, abcd->ijkl', g, g, g, g, T)
Additionally, using @jit(nopython=True) from numba on the naive loops function is five times faster than using numpy.tensordot on my machine.