Использование 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 есть функция, нет смысла ее переписывать. Вы должны быть в состоянии написать код 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, а не объект Python, поэтому следующая строка не может быть v.get(0) или v.set(0, 1).

Мы могли бы добавить в класс apop_data методы с именами vector_get и vector_set, которые будут возвращать gsl_vector в оболочке Python, но это создает свои собственные проблемы: если пользователь перераспределяет вектор C, лежащий в основе py-вектора из pyv = pyd.get_vector(), как мы можем гарантировать, что pyd.d.vector перераспределяется с ним?

Я пробовал пару вещей, и я чувствую, что каждый раз упускаю суть. Любые предложения о том, как лучше всего разработать классы Cython для этой ситуации?


person bk.    schedule 24.05.2011    source источник


Ответы (1)


Структура C никогда не должна подвергаться воздействию стороны Python. Я бегло просмотрел библиотеку и не нашел ничего необычного.

Единственная ситуация, которую вы должны отслеживать, — это когда библиотека фактически перераспределяет базовый вектор. Эти функции обычно требуют указатель на указатель и обновляют значение указателя до новой выделенной структуры.

Зачем вам нужно выставлять pyd.get_vector?

person fabrizioM    schedule 24.05.2011