I recently asked about trying to optimise a Python loop for a scientific application, et reçu an excellent, smart way of recoding it within NumPy which reduced execution time by a factor of around 100 pour moi!Réécriture d'une boucle for en NumPy pur pour réduire le temps d'exécution
Toutefois, le calcul de la valeur B
est en fait imbriqué dans quelques autres boucles, car il est évalué sur une grille de positions régulière. Existe-t-il une réécriture NumPy intelligente pour raser cette procédure? Je soupçonne que le gain de performance pour cette partie serait moins marqué, et les inconvénients seraient probablement qu'il ne serait pas possible de rapporter à l'utilisateur sur la progression du calcul, que les résultats n'ont pas pu être écrits à le fichier de sortie jusqu'à la fin du calcul, et éventuellement que cela en une étape énorme aurait des implications de mémoire? Est-il possible de contourner l'un de ceux-ci?
import numpy as np
import time
def reshape_vector(v):
b = np.empty((3,1))
for i in range(3):
b[i][0] = v[i]
return b
def unit_vectors(r):
return r/np.sqrt((r*r).sum(0))
def calculate_dipole(mu, r_i, mom_i):
relative = mu - r_i
r_unit = unit_vectors(relative)
A = 1e-7
num = A*(3*np.sum(mom_i*r_unit, 0)*r_unit - mom_i)
den = np.sqrt(np.sum(relative*relative, 0))**3
B = np.sum(num/den, 1)
return B
N = 20000 # number of dipoles
r_i = np.random.random((3,N)) # positions of dipoles
mom_i = np.random.random((3,N)) # moments of dipoles
a = np.random.random((3,3)) # three basis vectors for this crystal
n = [10,10,10] # points at which to evaluate sum
gamma_mu = 135.5 # a constant
t_start = time.clock()
for i in range(n[0]):
r_frac_x = np.float(i)/np.float(n[0])
r_test_x = r_frac_x * a[0]
for j in range(n[1]):
r_frac_y = np.float(j)/np.float(n[1])
r_test_y = r_frac_y * a[1]
for k in range(n[2]):
r_frac_z = np.float(k)/np.float(n[2])
r_test = r_test_x +r_test_y + r_frac_z * a[2]
r_test_fast = reshape_vector(r_test)
B = calculate_dipole(r_test_fast, r_i, mom_i)
omega = gamma_mu*np.sqrt(np.dot(B,B))
# write r_test, B and omega to a file
frac_done = np.float(i+1)/(n[0]+1)
t_elapsed = (time.clock()-t_start)
t_remain = (1-frac_done)*t_elapsed/frac_done
print frac_done*100,'% done in',t_elapsed/60.,'minutes...approximately',t_remain/60.,'minutes remaining'
Je pense que la suggestion de Justin de profiler était probablement sage, mais merci beaucoup pour cela ... bien que je ne sois pas sûr de l'utiliser, je pense qu'essayer de comprendre cet exemple est probablement une très bonne façon d'apprendre. :) – Statto