我想在python中对代码进行cython化以加速代码。在下面你可以看到我试图使我的python类可以理解为cython:
import numpy as np
cimport numpy as np
ctypedef np.double_t DTYPE_T
cpdef double std_G,v_c
std_G=4.3e-9 # Newton's const in Mpc (km/s)^2 M_sol^{-1}
v_c = 299792.458 #km/s
cdef extern from "math.h":
double log(double) nogil
double sqrt(double) nogil
cdef extern from "gsl/gsl_math.h":
ctypedef struct gsl_function:
double (* function) (double x, void * params)
void * params
cdef extern from "gsl/gsl_integration.h":
ctypedef struct gsl_integration_workspace
gsl_integration_workspace * gsl_integration_workspace_alloc(size_t n)
void gsl_integration_workspace_free(gsl_integration_workspace * w)
int gsl_integration_qags(const gsl_function * f, double a, double b, double epsabs, double epsrel, size_t limit, gsl_integration_workspace * workspace, double *result, double *abserr)
cdef double do_callback(double x, void* params):
return (<ComovingDistMemoization>params).eval(x)
cdef class ComovingDistMemoization(object):
cdef list _memotable
cdef cosmolgy
def __cinit__(self, cosmology, memotable = None):
if memotable is None:
self._memotable = []
self._memotable = memotable
self.cosmology = cosmology
def __call__(self, double z):
if z in self._memotable:
return self._memotable[z]
def eval(z):
return 1./sqrt(self.cosmology.hubble2(z))
cdef gsl_integration_workspace* w =gsl_integration_workspace_alloc(1000)
cdef gsl_function F
F.function = &do_callback
F.params = <void*>self
cdef double result = 3, error = 5
cdef double y, err, dist
gsl_integration_qags (&F, 0, z, 0, 1e-7, 1000, w, &result, &error)
y, err = result, error
gsl_integration_workspace_free(w)
dist = self.cosmology.v_c * y #to get proper units, ie to put in the hubble length
self._memotable[z] = dist
return dist
cdef class cosmology(object):
cdef comovingdist
cdef public double omega_m, omega_l, h, w, omega_r, G, v_c
cdef double H0, hubble_length
def __init__(self, omega_m = 0.3, omega_l = 0.7, h = 0.7, w = -1, omega_r = 0., G = std_G):
self.omega_m = omega_m
self.omega_l = omega_l
self.omega_r = omega_r
self.h = h
self.w = w
self.G = G
self.v_c = v_c
self.comovingdist = ComovingDistMemoization(self)
def __copy__(self):
return cosmology(omega_m = self.omega_m, omega_l = self.omega_l, h = self.h, w = self.w, omega_r = self.omega_r, G = self.G)
property H0:
def __get__(self):
return 100*self.h #km/s/MPC
def hubble2(self, double z):
cdef double inv_a
inv_a = 1.+z
return (self.omega_r*inv_a**4 + self.omega_m*inv_a**3 + \
self.omega_l*(inv_a**(3*(1+self.w))) + (1 - self.omega_m - self.omega_l - self.omega_r)*inv_a**2)*self.H0**2
property hubble_length:
def __get__(self):
return self.v_c / self.H0
def rho_crit(self, double z):
return 3.*self.hubble2(z)/(8*np.pi*self.G)
def angulardist(self, double z, double z2 = None):
if z2 is None:
return self.comovingdist(z) / (1+z)
return (self.comovingdist(z2) - self.comovingdist(z)) / (1+z2)
然而,其中一个引发错误的地方,到目前为止我找不到任何替换,我的调查刚刚达到这一点,cython不支持__copy__(self)
功能。
第一个问题:如何在class
中复制cython
的一种方法?
我用pickle.Pickler
读到了它,可以为类的实例提供替换,但我不知道它应该如何在类中产生copy
类?
更新:
这是用以下代码替换__copy__
的正确方法:
def __reduce__(self):
return (self.__class__, (), self.__getstate__())
def __getstate__(self):
return (self.omega_m, self.omega_l, self.omega_r, self.h, self.w, self.G, self.v_c)
def __setstate__(self, data):
(self.omega_m, self.omega_l, self.omega_r, self.h, self.w, self.G, self.v_c) = data
我的第二个问题是property
,我是否在cython中定义了属性,或者我还需要__set__
函数?
我的上一个问题:当我使用cosmology
调用ComovingDistMemoization
类的所有实例时,它们返回零。我想知道我在cosmology
类中调用实例ComovingDistMemoization
类的方式是否会引起问题并且无法在它们之间传递信息?
答案 0 :(得分:1)
回答第二个问题,在您的情况下,您不需要__set__
功能,并且您使用__get__
概念的方式似乎有误。要获取的属性名称必须设置为:
def get_H0(self):
return 100*self.h #km/s/MPC
H0 = property(fget=get_H0)
def get_hubble_length(self):
return self.v_c / self.H0
hubble_length = property(fget=get_hubble_length)
编辑:我不知道@property
不能与Cython一起使用
答案 1 :(得分:1)
最好的方法是将cosmology
类与ComovingDistMemoization
类组合,并将第二个类写为第一个类的方法。我将此类重命名为comovingdist
类的cosmology
函数。
cdef extern from "gsl/gsl_math.h":
ctypedef struct gsl_function:
double (* function) (double x, void * params)
void * params
cdef extern from "gsl/gsl_integration.h":
ctypedef struct gsl_integration_workspace
gsl_integration_workspace * gsl_integration_workspace_alloc(size_t n)
void gsl_integration_workspace_free(gsl_integration_workspace * w)
int gsl_integration_qags(const gsl_function * f, double a, double b, double epsabs, double epsrel, size_t limit, gsl_integration_workspace * workspace, double *result, double *abserr)
cdef double do_callback(double x, void* params):
return (<cosmology>params).eval(x)
cdef class cosmology(object):
cdef public double omega_m, omega_l, h, w, omega_r, G, v_c
def __init__(self,double omega_m = 0.3, double omega_l = 0.7, double h = 0.7, double w = -1, double omega_r = 0., double G = std_G):
self.omega_m = omega_m
self.omega_l = omega_l
self.omega_r = omega_r
self.h = h
self.w = w
self.G = G
self.v_c = v_c
def __copy__(self):
return cosmology(omega_m = self.omega_m, omega_l = self.omega_l, h = self.h, w = self.w, omega_r = self.omega_r, G = self.G)
property H0:
def __get__(self):
return 100*self.h #km/s/MPC
def hubble2(self, double z):
cdef double inv_a
inv_a = 1.+z
return (self.omega_r*inv_a**4 + self.omega_m*inv_a**3 + \
self.omega_l*(inv_a**(3*(1+self.w))) + (1 - self.omega_m - self.omega_l - self.omega_r)*inv_a**2)*self.H0**2
property hubble_length:
def __get__(self):
return self.v_c / self.H0
cpdef double eval(self, double z):
return 1./sqrt(self.hubble2(z))
def comovingdist(self, double z):
cdef gsl_integration_workspace* w =gsl_integration_workspace_alloc(1000)
cdef gsl_function F
F.function = &do_callback
F.params = <void*>self
cdef double result = 3, error = 5
cdef double y, err, dist
gsl_integration_qags(&F, 0, z, 0, 1e-7, 1000, w, &result, &error)
y, err = result, error
gsl_integration_workspace_free(w)
dist = self.v_c * y #to get proper units, ie to put in the hubble length
return dist
def rho_crit(self, double z):
return 3.*self.hubble2(z)/(8*np.pi*self.G)
def angulardist(self, z, z2=None):
if z2 is None:
return self.comovingdist(z) / (1+z)
return (self.comovingdist(z2) - self.comovingdist(z)) / (1+z2)
def beta(self, z, zcluster):
Ds = np.array([self.angulardist(zi) for zi in z])
Dls = np.array([self.angulardist(zcluster, zi) for zi in z])
Dls_over_Ds = np.zeros_like(Dls)
Dls_over_Ds[Ds > 0] = Dls[Ds > 0] / Ds[Ds > 0]
Dls_over_Ds[Dls <= 0] = 0
return Dls_over_Ds
def beta_s(self, z, zcluster):
betainf = self.beta([1e6], zcluster)
beta_s = self.beta(z, zcluster) / betainf
return beta_s
def RhoCrit_over_SigmaC(self,z, zcluster):
Dl = self.angulardist(zcluster)
r= (4*np.pi*self.G)*self.rho_crit(zcluster)*self.beta( z, zcluster )*Dl/self.v_c**2
return r