Как мне ввести переменные в Cython, чтобы они быстрее передавались в массив memoryview? - PullRequest
0 голосов
/ 02 февраля 2019

Я пытаюсь оптимизировать двойной цикл для интегратора N-тела, и я обнаружил, что проблема с моим кодом заключается в том, что у меня возникают огромные накладные расходы, когда я записываю сохраненные переменные в области просмотра памяти.

Первоначально этот код был векторизован в виде numpy, но он вызывался внутри другого цикла for для обновления позиций частиц, и накладные расходы были жестокими.У меня есть вектор позиций NX2 np.ndarray (X), и я хочу вернуть вектор импульсов Nx2 (XOut) - текущий код, указанный ниже, возвращает представление памяти, но это нормально, потому что я хотел бы в конечном итоге встроить этофункция в другой функции Cython, как только я отладил это узкое место.

Я попробовал команду cython -a "name.pyx" и обнаружил, что у меня более или менее все есть как C-тип.Однако я обнаружил, что в нижней части цикла запись в представление памяти XOut [ii, 0] - = valuex влечет за собой большую часть времени выполнения.Если я изменю это на константу, так что XOut [ii, 0] - = 5, код будет примерно в 40 раз быстрее.Я думаю, это означает, что я делаю какую-то операцию копирования в этой строке, которая замедляет меня.Мои фоны Cython / C ++ являются элементарными, но я думаю, что мне нужно изменить синтаксис так, чтобы я записывал в память представление из указателя.Любой совет будет очень признателен;Спасибо!

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  

1 Ответ

0 голосов
/ 02 февраля 2019

ОК, поэтому проблема заключалась в математических операциях.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

Изменение значения x с xvec / r2 ** 2 на xvec / r2 / r2 и удаление всех экземпляров оператора ** ускорилосьцикл до 9 мс с 200 мс для массива 1800x2.Я все еще надеюсь, что скорость 4 мс возможна, но сейчас я остановлюсь на 9 мс.

...