Выступление Cython против Numba - PullRequest
0 голосов
/ 13 октября 2018

Привет, я сейчас работаю в модуле Python для термодинамических равновесий фаз жидкости.Для этого мне нужно запрограммировать модели коэффициентов активности, такие как NRTL, которые включают в себя несколько сумм.Чтобы повысить производительность модуля, я попытался выполнить функцию jit с помощью numba:

@jit(cache=True)
def NRTL(X,T,g, alpha, g1):
'''
NRTL activity coefficient model.

input
X: array like, vector of molar fractions
T: float, absolute temperature in K.
g: array like, matrix of energy interactions in K.
g1: array_like, matrix of energy interactions in K^2
alpha: float, aleatory factor.

tau = ((g + g1/T)/T)

output
lngama: array_like, natural logarithm of activify coefficient
'''

tau = g + g1*T
tau /= T

nc=len(X)
G=np.exp(-alpha*tau)
lngama=np.zeros_like(X)
for i in range(nc):
    SumC=SumD=SumE=0
    for j in range(nc):
        A=X[j]*G[i,j]
        SumA=SumB=0
        for k in range(nc):
            SumA +=X[k]*G[k,j]
            SumB +=X[k]*G[k,j]*tau[k,j]
        SumC +=A/SumA*(tau[i,j]-SumB/SumA)
        SumD+=X[j]*G[j,i]*tau[j,i]
        SumE+=X[j]*G[j,i]
    lngama[i]=SumD/SumE+SumC
return lngama

Я пробовал новые опции, как cython, но я не получаю такую ​​хорошую производительность, как с jit numbas.

import numpy as np
cimport numpy as np
cimport cython

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
cdef double[:] nrtlaux(double [:] X, double [:,::1] G, double [:,::1] tau, int nc):
cdef int i, j, k
cdef double A, SumA, SumB, SumC, SumD, SumE, aux1, aux2

cdef double [:] lngama = np.zeros(nc)

for i in range(nc):
    SumC = SumD = SumE = 0.
    for j in range(nc):
        A = X[j]*G[i,j]
        SumA = SumB = 0.
        for k in range(nc):
            aux1 = X[k]*G[k,j]
            SumA += aux1
            SumB += aux1*tau[k,j]
        SumC += A/SumA*(tau[i,j]-SumB/SumA)
        aux2 = X[j]*G[j,i]
        SumD += aux2*tau[j,i]
        SumE += aux2
    lngama[i] = SumD/SumE+SumC
return lngama

def NRTL(np.ndarray[double, ndim=1] X, double T, np.ndarray[double, ndim=2] g,
       np.ndarray[double, ndim=2] alpha, np.ndarray[double, ndim=2] g1):
cdef int nc = len(X)
cdef:
    double[:,::1] tau = (g/T + g1)
    double[:,::1] G  = np.exp( -alpha * tau )

lngama = nrtlaux(X, G, tau, nc)

return np.asarray(lngama)

Я использую следующие параметры для оценки функции:

X = np.array([0.5,0.4,0.1])
g = np.array([[0,35.00002657,463.719316],[341.00001923,0,96.02154497],[1194.42262, 534.77089478,0]])
alpha = np.array([[0,0.3456916919878884,0.242020522],[0.3456916919878884,0,0.54 ],[0.242020522,0.54 ,0]])
g1 = np.zeros_like(g)
T = 350. 

И я получил следующие результаты:

%timeit NRTL(X,T,g,alpha, g1) #cython
13.9 µs ± 489 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit nrtltp(X,T,g,alpha, g1) #numba
1.82 µs ± 35 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Я немного удивленхорошие результаты от функции joted, также я новичок в Cython, так что я надеялся на какие-либо предложения по улучшению производительности?

...