Как создать оболочку для класса Matrix для Numpy с помощью SWIG?

У меня есть старая и выросшая библиотека C ++, содержащая класс Matrix и множество кода, использующего его. Это в основном

class Matrix {
double* p;      // the actual data
int nd;         // number of dimensions
int d0, d1, d2; // the actual dimensionality

// ... (a whole lot of functions computing various things, like SVDs, dotproduct etc.
}

Теперь мы пишем оболочку Python, используя SWIG. Мы хотим использовать массивы NumPy на стороне Python для обеспечения совместимости с остальным миром. Таким образом, нам на самом деле не нужна функциональность нашего класса C ++ Matrix, но мы хотим использовать некоторые другие части нашей библиотеки, которые ожидают эту C ++ Matrix. Таким образом, идеальная ситуация была бы, если бы мы могли записать карту типов из массива NumPy в наш класс Matrix, который прозрачно преобразует массив NumPy при каждом вызове и поддерживает синхронизацию памяти. Допустим, у нас есть какая-то функция в нашей библиотеке, которая работает:

int some_function(Matrix& in) { /* do some stuff */ }

Теперь было бы здорово, если бы в Python мы могли сделать что-то вроде:

a = numpy.array[1,2,3,4]
b = some_function(a)

Я понимаю, что есть numpy.i, но, похоже, это больше относится к отображению функций и простым старым массивам Си. Я также понимаю, что карта типов должна соответствовать тому, что я хочу, но я не совсем понимаю, как я могу на самом деле получить доступ к пустым данным. Есть ли (относительно) простой способ сделать это?

Я также был бы признателен за указатель на какой-то учебник.

2

Решение

На основании предоставленной вами информации, будут работать карты типов. Но мой опыт временного пользователя SWIG (обычно пару недель, когда я его часто использую, а затем перерыва до следующего проекта / фазы), заключается в том, что у немногих людей есть время, чтобы воспользоваться этой возможностью.

В вашем случае я считаю, что типографские карты SWIG более удобны, чем требование, поэтому я бы использовал один из двух подходов:

  1. создать функцию Python, которая выполняет преобразование из numpy.array в Matrix (Matrix — это та, которая экспортируется из C ++ в Python с помощью SWIG)
  2. используйте встроенную карту типов numpy.i для вызова функции C ++, которая принимает тип C ++ в этой карте типов, и определите эту функцию для вызова int some_function(Matrix& in)

Преимущество варианта 1 заключается в том, что вы можете автоматизировать преобразование, связав функцию Python:

old_some_func = some_function
def some_function(numpy_array):
tempMat = Matrix()
# convert numpy_array to SWIG'd Matrix class
old_some_func(tempMat)

Повышение производительности при выполнении этого, вероятно, будет незначительным, но вы должны проверить. Без SWIG (то есть, если вы использовали C API) этот метод имел бы дополнительное преимущество, заключающееся в том, что вам не нужно менять библиотеку C ++ (см. Директиву расширения SWIG).

Преимущество варианта 2 заключается в том, что преобразование происходит на уровне C / C ++, поэтому в зависимости от того, что задействовано, вы можете получить улучшенную производительность. Скажем, одно из типографских карт numpy.i отображает numpy.array в массив float [numValues], а ваша матрица C ++ содержит значения с плавающей запятой одинарной точности. В этом случае вы определяете C ++ some_function (float *, numValues) в файле .i для вашего проекта, и эта функция вызывает some_function (Matrix). Проверьте, может ли ваш класс C ++ Matrix хранить указатель на данные массива, таким образом вы избежите копирования данных через один и, возможно, даже два слоя (Python -> SWIG some_function (array) -> some_function (Matrix)).

Но имейте в виду: ваши вычисления внутри вашей C ++ функции some_function могут сделать любую разницу в производительности между этими двумя параметрами несущественной. Вы должны проверить. Затем выберите тот, который проще и удобнее обслуживать (вероятно, вариант 1).

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]