我的目标是使用Cython打包Apohenia库,一个用于科学计算的C库。使用Cython打包一个包装另一个库的库
这是为了不重新发明轮子,和Apophenia本身试图通过立足于那些由GNU科学图书馆的结构做同样的,:
typedef struct {
gsl_vector *vector;
gsl_matrix *matrix;
gsl_vector *weights;
apop_names *names;
...
} apop_data;
Apophenia提供了大量矢量/矩阵运算GSL或者不提供或者提供一点不明显的,但是如果GSL有一个功能,那么就没有必要重写它。您应该能够编写C代码,尽可能经常需要apop_data
集作为一个整体,其GSL部分之间跳跃,例如:
apop_data *dataset = apop_text_to_data("infile.csv"); //fill the matrix element
gsl_vector *minv = apop_matrix_inverse(dataset->matrix);
apop_data *dinv = apop_matrix_to_data(minv);
apop_data *identity_matrix = apop_dot(dataset, dinv); // I = D * D^-1
dataset->vector = gsl_vector_alloc(10);
gsl_vector_set_all(dataset->vector, 1);
我不知道如何用Cython这个包起来。典型的方法似乎是提供一个Python的侧结构,包括在C结构的内部副本被包裹:
"""I'm omitting the Cython declarations of the C structs and functions,
which are just translations of the C declarations. Let those be in c_apop."""
cdef class apop_data:
cdef c_apop.apop_data *d
def set(self, row, col, val):
c_apop.apop_data_set(self.d, row, col, val)
def get(self, row, col):
c_apop.apop_data_get(self.d, row, col)
[et cetera]
cdef class gsl_vector:
cdef c_apop.gsl_vector *v
def set(self, row, val):
c_apop.gsl_vector_set(self.v, row)
def get(self, row):
c_apop.gsl_vector_get(self.v, row)
[et cetera]
但现在我们就完蛋了,因为如果我们得到从向量元素数据集,
pyd = apop_data(10)
v = pyd.d.vector
v
是一个纯粹的C gsl_vector
,而不是一个蟒对象,所以下一行不能v.get(0)
或v.set(0, 1)
。
我们可以添加方法来命名vector_get
和vector_set
的apop_data
类,将返回一个python包裹gsl_vector
,但创建自己的问题:如果用户重新分配C载体的PY-矢量从pyv = pyd.get_vector()
底层,怎么办我们保证pyd.d.vector
与它重新分配?
我试过了几件事情,我觉得我每次都错过了这一点。有关如何为这种情况设计最佳Cython类的建议?