#cython
#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
and vector_set
, которые вернут обертку в python gsl_vector
, но это создает свои собственные проблемы: если пользователь перераспределяет вектор C, лежащий в основе py-vector из pyv = pyd.get_vector()
, как мы гарантируем, что pyd.d.vector
он будет перераспределен вместе с ним?
Я попробовал пару вещей, и мне кажется, что я каждый раз упускаю суть. Есть предложения о том, как наилучшим образом спроектировать классы Cython для этой ситуации?
Ответ №1:
Структура C никогда не должна быть доступна стороне python. Я быстро взглянул на библиотеку, и, похоже, в ней нет ничего необычного.
Единственная ситуация, которую вам нужно отслеживать, — это когда библиотека фактически перераспределяет базовый вектор. Для этих функций обычно требуется указатель на указатель и они обновляют значение указателя до новой выделенной структуры.
Зачем вам нужно предоставлять pyd.get_vector ?