我的目标是使用Cython包装Apohenia库,这是一个用于科学计算的C库。
这是一种不重建轮子的努力,Apophenia本身也试图通过将其结构基于GNU科学图书馆的结构来实现同样的目标:
typedef struct {
gsl_vector *vector;
gsl_matrix *matrix;
gsl_vector *weights;
apop_names *names;
...
} apop_data;
Apophenia提供了许多向量/矩阵运算,GSL要么不提供这些运算,要么提供一点笨拙,但如果GSL有一个函数,则没有必要重写它。您应该能够根据需要编写在整个apop_data
集合和GSL部分之间跳转的C代码,例如:
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]
但是现在我们被卡住了,因为如果我们要从数据集中获取vector元素,
pyd = apop_data(10)
v = pyd.d.vector
v
是原始C gsl_vector
,而不是python对象,因此下一行不能是v.get(0)
或v.set(0, 1)
。
我们可以向名为apop_data
和vector_get
的{{1}}类添加方法,这将返回一个包含python的vector_set
,但这会产生自己的问题:如果用户重新分配来自gsl_vector
的py-vector底层的C向量,我们如何保证pyv = pyd.get_vector()
与其重新分配?
我尝试了几件事,我觉得每次都错过了这一点。关于如何针对这种情况最好地设计Cython类的任何建议?
答案 0 :(得分:0)
C结构永远不应暴露给python端。 我快速浏览了一下图书馆,似乎没有任何异常。
您必须跟踪的唯一情况是库实际重新分配基础向量。这些函数通常需要指向指针的指针,并将指针值更新为新分配的结构。
为什么需要公开pyd.get_vector?