Numpy 如何在cython中键入变量,以便它们更快地传递到memoryview数组?

Numpy 如何在cython中键入变量,以便它们更快地传递到memoryview数组?,numpy,types,cython,memoryview,Numpy,Types,Cython,Memoryview,我正在尝试为N体积分器优化一个双循环,我发现我的代码的问题是,当我将存储的变量写入内存视图位置时,会产生巨大的开销 我最初用numpy对这段代码进行了矢量化,但在另一个for循环中调用了它来更新粒子位置,开销非常大。我有一个np.ndarray Nx2位置向量(X),我想返回一个Nx2动量向量(XOut)——下面列出的当前代码返回一个内存视图,但这没关系,因为我想在调试完这个瓶颈后,最终将这个函数嵌入到其他Cython函数中 我尝试了cython-a“name.pyx”命令,发现我或多或少都是C

我正在尝试为N体积分器优化一个双循环,我发现我的代码的问题是,当我将存储的变量写入内存视图位置时,会产生巨大的开销

我最初用numpy对这段代码进行了矢量化,但在另一个for循环中调用了它来更新粒子位置,开销非常大。我有一个np.ndarray Nx2位置向量(X),我想返回一个Nx2动量向量(XOut)——下面列出的当前代码返回一个内存视图,但这没关系,因为我想在调试完这个瓶颈后,最终将这个函数嵌入到其他Cython函数中

我尝试了cython-a“name.pyx”命令,发现我或多或少都是C-type。然而,我发现在循环的底部,写入XOut[ii,0]-=valuex的memoryview会占用大部分运行时间。如果我把它变成一个常数,使XOut[ii,0]-=5,代码会快40倍。我想这意味着我在那条线上做了某种复制操作,这会让我慢下来。我的Cython/C++背景还很初级,但我认为我需要更改语法,以便从指针写入memoryview。任何建议都将不胜感激;谢谢

import numpy as np
cimport numpy as np
from cython.view cimport array as cvarray
cimport cython
from libc.math cimport sinh, cosh, sin, cos, acos, exp, sqrt, fabs, M_PI


DTYPE = np.float64  

ctypedef np.float64_t DTYPE_t  
cdef DTYPE_t pi = 3.141592653589793  

@cython.cdivision(True)  
@cython.boundscheck(False) # turn off bounds-checking for entire function  
@cython.wraparound(False)  # turn off negative index wrapping for entire function

def intTerms(const DTYPE_t[:,:] X, DTYPE_t epsilon, DTYPE_t[:,:] XOut):  
    cdef Py_ssize_t ii,jj,N  
    N = X.shape[0]  
    cdef DTYPE_t valuex,valuey,r2,xvec,yvec  
    for ii in range(0,N):  
        for jj in range(ii+1,N):  
            xvec = X[ii,0]-X[jj,0]  
            yvec = X[ii,1]-X[jj,1]  
            r2 = max(xvec**2+yvec**2,epsilon)  
            valuex = xvec/r2**2  
            valuey = yvec/r2**2  
            XOut[ii,0] -= valuex  
            XOut[ii,1] -= 5 #valuey  
            XOut[jj,0] += 5 #valuex  
            XOut[jj,1] += 5 #valuey  
        XOut[ii,0] /= 2*pi  
        XOut[ii,1] /= 2*pi   
    return XOut  

好的,问题是数学运算。Cython没有优化**操作符,所以我修改了代码:

import numpy as np
cimport numpy as np
from cython.view cimport array as cvarray
cimport cython
from libc.math cimport sinh, cosh, sin, cos, acos, exp, sqrt, fabs, M_PI

DTYPE = np.float64

ctypedef np.float64_t DTYPE_t
cdef DTYPE_t pi = 3.141592653589793

@cython.cdivision(True)
@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False)  # turn off negative index wrapping for entire function
def intTerms(const DTYPE_t[:,:] X, DTYPE_t epsilon, DTYPE_t[:,:] XOut):
    cdef Py_ssize_t ii,jj,N
    N = X.shape[0]
    cdef DTYPE_t valuex,valuey,r2,xvec,yvec
    for ii in range(0,N-1):
        for jj in range(ii+1,N):
            xvec = X[ii,0]-X[jj,0]
            yvec = X[ii,1]-X[jj,1]
            r2 = max(xvec*xvec+yvec*yvec,epsilon)
            valuex = xvec/r2/r2
            valuey = yvec/r2/r2
            XOut[ii,0] -= valuex
            XOut[ii,1] -= valuey
            XOut[jj,0] += valuex
            XOut[jj,1] += valuey
        XOut[ii,0] /= 2*pi
        XOut[ii,1] /= 2*pi 
    return XOut

将valuex从xvec/r2**2更改为xvec/r2/r2,并删除**运算符的所有实例,将1800x2阵列的循环速度从200ms提高到9ms。我仍然希望4ms的速度是可能的,但我现在只能满足于9ms。

如果将xvalue替换为5,编译器可能能够优化所有以前的计算,因为它们没有被使用。我明白你的意思,让我再添加一点背景。所以我有另一个函数,它是一个内存视图的单for循环,添加了另外两个带有sinh和cosh表达式的内存视图。在1800个元素的向量上,这个函数需要18微秒。在double for循环中,它应该是4毫秒,因为它是一个双循环,但是当我添加值时,我得到了200毫秒,所以我认为存在类型问题。好的,我得到了。这是(*2)操作。他是对的。我将(**2)操作更改为xvecxvec和/r2/r2,并将执行时间设置为8毫秒。您能否显示您用于配置文件的数据采样?我想尝试一个逐行分析器来优化它。你只需要传入一个随机数组:X=np.random.rand(1800,4),XOut=0*X,然后XOut=IntTerms(X,0.01,XOut)作为另一个优化,你可能想
/r2/r2
整个numpys,而不是重复很多次这个除法。当您将此操作应用于整个数组时,Numpy会优化此操作。无法执行此操作,因为为了将其矢量化,r2必须由对称矩阵紧凑地表示。内存将缩放为N^2