Au cœur d'une application (écrite en Python et utilisant NumPy ) J'ai besoin de faire tourner un tenseur d'ordre 4. En fait, j'ai besoin de faire tourner un grand nombre de tenseurs plusieurs fois et c'est là mon goulot d'étranglement. Mon implémentation naïve (ci-dessous) impliquant huit boucles imbriquées semble être assez lente, mais je ne vois pas de moyen de tirer parti des opérations matricielles de NumPy et, espérons-le, d'accélérer les choses. J'ai l'impression que je devrais utiliser np.tensordot
mais je ne vois pas comment.
Mathématiquement, les éléments du tenseur tourné, T', sont donnés par : T' ijkl \= Σ g ia g jb g kc g ld T abcd avec la somme sur les indices répétés sur le côté droit. T et Tprime sont des tableaux NumPy 3*3*3*3 et la matrice de rotation g est un tableau NumPy 3*3. Mon implémentation lente (prenant ~0.04 secondes par appel) est ci-dessous.
#!/usr/bin/env python
import numpy as np
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 ii in range(3):
for jj in range(3):
for kk in range(3):
for ll in range(3):
gg = g[ii,i]*g[jj,j]*g[kk,k]*g[ll,l]
Tprime[i,j,k,l] = Tprime[i,j,k,l] + \
gg*T[ii,jj,kk,ll]
return Tprime
if __name__ == "__main__":
T = np.array([[[[ 4.66533067e+01, 5.84985000e-02, -5.37671310e-01],
[ 5.84985000e-02, 1.56722231e+01, 2.32831900e-02],
[ -5.37671310e-01, 2.32831900e-02, 1.33399259e+01]],
[[ 4.60051700e-02, 1.54658176e+01, 2.19568200e-02],
[ 1.54658176e+01, -5.18223500e-02, -1.52814920e-01],
[ 2.19568200e-02, -1.52814920e-01, -2.43874100e-02]],
[[ -5.35577630e-01, 1.95558600e-02, 1.31108757e+01],
[ 1.95558600e-02, -1.51342210e-01, -6.67615000e-03],
[ 1.31108757e+01, -6.67615000e-03, 6.90486240e-01]]],
[[[ 4.60051700e-02, 1.54658176e+01, 2.19568200e-02],
[ 1.54658176e+01, -5.18223500e-02, -1.52814920e-01],
[ 2.19568200e-02, -1.52814920e-01, -2.43874100e-02]],
[[ 1.57414726e+01, -3.86167500e-02, -1.55971950e-01],
[ -3.86167500e-02, 4.65601977e+01, -3.57741000e-02],
[ -1.55971950e-01, -3.57741000e-02, 1.34215636e+01]],
[[ 2.58256300e-02, -1.49072770e-01, -7.38843000e-03],
[ -1.49072770e-01, -3.63410500e-02, 1.32039847e+01],
[ -7.38843000e-03, 1.32039847e+01, 1.38172700e-02]]],
[[[ -5.35577630e-01, 1.95558600e-02, 1.31108757e+01],
[ 1.95558600e-02, -1.51342210e-01, -6.67615000e-03],
[ 1.31108757e+01, -6.67615000e-03, 6.90486240e-01]],
[[ 2.58256300e-02, -1.49072770e-01, -7.38843000e-03],
[ -1.49072770e-01, -3.63410500e-02, 1.32039847e+01],
[ -7.38843000e-03, 1.32039847e+01, 1.38172700e-02]],
[[ 1.33639532e+01, -1.26331100e-02, 6.84650400e-01],
[ -1.26331100e-02, 1.34222177e+01, 1.67851800e-02],
[ 6.84650400e-01, 1.67851800e-02, 4.89151396e+01]]]])
g = np.array([[ 0.79389393, 0.54184237, 0.27593346],
[-0.59925749, 0.62028664, 0.50609776],
[ 0.10306737, -0.56714313, 0.8171449 ]])
for i in range(100):
Tprime = rotT(T,g)
Y a-t-il un moyen d'accélérer le processus ? Généraliser le code à d'autres rangs de tenseurs serait utile, mais c'est moins important.
0 votes
Et, s'il devient clair que faire cela plus rapidement dans numpy ou scipy n'est pas facile, j'élaborerai un module d'extension Fortran et verrai comment cela se passe.
1 votes
Si tout le reste échoue, vous pouvez utiliser Cython. Il est censé joue bien avec numpy .
0 votes
Alors que je suis modérément sûr qu'il y a un moyen de faire cela avec moins de boucles imbriquées dans numpy (je ne le vois pas immédiatement, cependant), comme @delnan l'a dit, votre code actuel est un candidat de choix pour Cython.....