使用Cython包装一个包装另一个库的库

时间:2011-05-24 14:53:54

标签: cython

我的目标是使用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_datavector_get的{​​{1}}类添加方法,这将返回一个包含python的vector_set,但这会产生自己的问题:如果用户重新分配来自gsl_vector的py-vector底层的C向量,我们如何保证pyv = pyd.get_vector()与其重新分配?

我尝试了几件事,我觉得每次都错过了这一点。关于如何针对这种情况最好地设计Cython类的任何建议?

1 个答案:

答案 0 :(得分:0)

C结构永远不应暴露给python端。 我快速浏览了一下图书​​馆,似乎没有任何异常。

您必须跟踪的唯一情况是库实际重新分配基础向量。这些函数通常需要指向指针的指针,并将指针值更新为新分配的结构。

为什么需要公开pyd.get_vector?