ускорение понимания списка numpy.dot внутри

У меня есть пустой скрипт, который в настоящее время работает довольно медленно. тратит подавляющее большинство своего времени на выполнение следующей операции внутри цикла:

terms=zip(Coeff_3,Coeff_2,Curl_x,Curl_y,Curl_z,Ex,Ey,Ez_av)
res=[np.dot(C2,array([C_x,C_y,C_z]))+np.dot(C3,array([ex,ey,ez])) for (C3,C2,C_x,C_y,C_z,ex,ey,ez) in terms]
res=array(res) 

Ex[1:Nx-1]=res[1:Nx-1,0]
Ey[1:Nx-1]=res[1:Nx-1,1]

Именно понимание списка действительно замедляет этот код. В этом случае Coeff_3 и Coeff_2 представляют собой списки длиной 1000, элементы которых представляют собой матрицы 3x3 numpy, а Ex, Ey, Ez, Curl_x и т. д. — все массивы numpy длиной 1000. Я понимаю, что было бы быстрее, если бы я сделал такие вещи, как установка одного вектора E 3x1000, но мне нужно выполнить значительный объем усреднения различных векторов E между шагами, что сделало бы все очень громоздким.

Любопытно, однако, что я выполняю эту операцию дважды за цикл (один раз для Ex, Ey, один раз для Ez), и выполнение той же операции для Ez занимает почти вдвое больше времени:

terms2=zip(Coeff_3,Coeff_2,Curl_x,Curl_y,Curl_z,Ex_av,Ey_av,Ez)
res2=array([np.dot(C2,array([C_x,C_y,C_z]))+np.dot(C3,array([ex,ey,ez])) for (C3,C2,C_x,C_y,C_z,ex,ey,ez) in terms2])

Кто-нибудь знает, что происходит? Простите меня, если это что-то очевидное, я очень новичок в python.


person Mdupont    schedule 03.02.2014    source источник
comment
Вы должны написать понимание списка как операцию массива   -  person gypaetus    schedule 04.02.2014
comment
Как так? Я не совсем уверен, как это сделать/   -  person Mdupont    schedule 04.02.2014
comment
Если вы можете переписать эту операцию, используя n-мерные тензоры и нотацию суммирования Эйнштейна, будет тривиально векторизовать операцию в numpy. По крайней мере, пожалуйста, напишите размер каждого объекта. Например, Coeff_3 имеет форму (1000,3,3).   -  person Daniel    schedule 04.02.2014


Ответы (1)


Как указывалось в предыдущих комментариях, используйте операции с массивами. Здесь полезны np.hstack(), np.vstack(), np.outer() и np.inner(). Ваш код может стать чем-то вроде этого (не уверен в ваших размерах):

 Cxyz = np.vstack((Curl_x,Curl_y,Curl_z))
 C2xyz = np.dot(C2, Cxyz)
 ...

Проверьте форму полученных размеров, чтобы убедиться, что вы правильно перевели свою задачу. Иногда numexpr также может значительно ускорить такие задачи с небольшими дополнительными усилиями,

person Dietrich    schedule 04.02.2014
comment
Кажется, это работает. Я сложил все свои векторы и использовал суммирование Эйнштейна, как было предложено Option, и оно увеличилось с 15 циклов в секунду до 77 циклов в секунду. Спасибо! - person Mdupont; 04.02.2014