我已经编写了以下代码,它可以满足我的需要,但我希望对其进行优化.

import numpy as np
N_rs = 100
N_thetas = 30

Nlm_container = np.ones( (N_thetas, 2*N_thetas-1), dtype=np.complex128 )
lpmv_container = np.ones ( (N_thetas, 2*N_thetas-1, N_thetas), dtype=np.complex128 )
Psi_m_res1 = np.zeros( (2*N_thetas - 1,    N_rs - 1,    N_thetas) , dtype=np.complex128 )
Psi_m_res2 = np.zeros( (2*N_thetas - 1,    N_rs - 1,    N_thetas) , dtype=np.complex128 )
Psi_m_res3 = np.zeros( (2*N_thetas - 1,    N_rs - 1,    N_thetas) , dtype=np.complex128 )
Psi_lm = np.ones ( ( N_rs - 1, 2*N_thetas-1, N_thetas), dtype=np.complex128 )

for m in range(-N_thetas+1,  N_thetas,  1):
    for j in range(N_rs - 1):
        for k in range(N_thetas):
            Psi_m_res1[m + (N_thetas-1),  j,  k] = np.sum(  Psi_lm[j, m+(N_thetas-1), np.abs(m):] * Nlm_container[np.abs(m):, m+(N_thetas-1)]  *  lpmv_container[abs(m):, m+(N_thetas-1), k]  )

我希望避免嵌套的三元组for循环. 我认为使用:会更好,而不是使用j之上的循环和k之上的循环.我这样写(作为第一步):

for m in range(-N_thetas+1,  N_thetas,  1):
    for k in range(N_thetas):
        Psi_m_res2[m + (N_thetas-1),  :,  k] = np.sum(  Psi_lm[:, m+(N_thetas-1), np.abs(m):] * Nlm_container[np.abs(m):, m+(N_thetas-1)]  *  lpmv_container[abs(m):, m+(N_thetas-1), k]  )

尽管如此,这并没有产生我想要的:

print(np.testing.assert_allclose(Psi_m_res1, Psi_m_res2))
Mismatched elements: 175230 / 175230 (100%)
Max absolute difference: 2940.
Max relative difference: 0.98989899

更重要的是,当同时消除k索引for循环时,程序根本不会计算任何形状不匹配.

for m in range(-N_thetas+1,  N_thetas,  1):
    Psi_m_res3[m + (N_thetas-1),  :,  :] = np.sum(  Psi_lm[:, m+(N_thetas-1), np.abs(m):] * Nlm_container[np.abs(m):, m+(N_thetas-1)]  *  lpmv_container[abs(m):, m+(N_thetas-1), :]  )

ValueError: operands could not be broadcast together with shapes (99,2) (2,30)

我可以创建线程,将Psi_lmNlm_containerlpmv_container的片段发送给它们,然后请求执行工作,然后重新组合结果,但我认为麻木魔法可能会做得更好.

在实践中,N_rsN_thetas应该更高--它们可以上升到N_rs = 1600N_thetas=100,这是在代码开始运行之前设置的,并在代码运行时期间进行修复.

有没有办法用麻木魔法来解决这个问题?

谢谢!

推荐答案

您可以使用np.einsum向量化两个内部循环,从而获得更快(也更简单)的代码.以下是代码:

for m in range(-N_thetas+1,  N_thetas,  1):
    m_abs = np.abs(m)
    idx = m + (N_thetas - 1)
    Psi_m_res1[idx] = np.einsum('ji,i,ik->jk', Psi_lm[:, idx, m_abs:], Nlm_container[m_abs:, idx], lpmv_container[m_abs:, idx, :], optimize='optimal')

在我的机器上,这需要4.7毫秒,而不是956毫秒.这意味着上面的代码大约是200 times faster!有效地向量化外部循环是非常困难的,如果甚至不可能的话,因为数组的大小不同.注np.einsum足够智能,因此在本例中可以在内部使用矩阵乘法.如果你想要更快的代码,那么我建议你使用多线程的Numba代码.

Python相关问答推荐

Pandas—合并数据帧,在公共列上保留非空值,在另一列上保留平均值

如何将多进程池声明为变量并将其导入到另一个Python文件

Python中的变量每次增加超过1

无论输入分辨率如何,稳定扩散管道始终输出512 * 512张图像

判断solve_ivp中的事件

网格基于1.Y轴与2.x轴显示在matplotlib中

幂集,其中每个元素可以是正或负""""

使用字典或列表的值组合

当单元测试失败时,是否有一个惯例会抛出许多类似的错误消息?

不允许 Select 北极滚动?

Python 3试图访问在线程调用中实例化的类的对象

判断Python操作:如何从字面上得到所有decorator ?

解决Geopandas和Altair中的正图和投影问题

启动线程时,Python键盘模块冻结/不工作

Django更新视图未更新

我怎样才能让深度测试在OpenGL中使用Python和PyGame呢?

是否将列表分割为2?

为什么任何一个HTML页面在保存到文件后都会变大6个字节?

S最大值除以最小值,然后减1的结果是什么?

在多索引的Pandas数据帧中,有可能有一个值引用更高级别索引的列吗?