У меня есть небольшой проект, который прекрасно работает с SWIG. В частности, некоторые из моих функций возвращают std::vector
s, которые переводятся на кортежи в Python. Теперь я делаю много цифр, поэтому у меня просто SWIG конвертирует их в массивы numpy после того, как они возвращаются из кода C++. Для этого я использую что-то вроде SWIG.Есть ли способ использовать pythonappend с новой встроенной функцией SWIG?
%feature("pythonappend") My::Cool::Namespace::Data() const %{ if isinstance(val, tuple) : val = numpy.array(val) %}
(На самом деле, есть несколько функций, названных данных, некоторые из которых возвращаются поплавки, поэтому я проверить, что на самом деле val
кортеж.) Это работает только красиво.
Но, я также хотел бы использовать флаг -builtin
, который теперь доступен. Звонки на эти функции данных редки и в основном интерактивны, поэтому их медленность не проблема, но есть и другие медленные циклы, которые значительно ускоряются с встроенной опцией.
Проблема в том, что когда я использую этот флаг, функция pythonappend молча игнорируется. Теперь данные снова вернут кортеж. Есть ли способ вернуть массив numpy? Я пробовал использовать typemaps, но он превратился в гигантский беспорядок.
Edit:
Borealid ответил на вопрос очень красиво. Для полноты я включаю пару связанных, но очень тонких типов, которые мне нужны, потому что я возвращаюсь по ссылке const, и я использую векторы векторов (не начинайте!). Они достаточно разные, и я бы не хотел, чтобы кто-то еще спотыкался о том, чтобы выяснить незначительные различия.
%typemap(out) std::vector<int>& {
npy_intp result_size = $1->size();
npy_intp dims[1] = { result_size };
PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_INT);
int* dat = (int*) PyArray_DATA(npy_arr);
for (size_t i = 0; i < result_size; ++i) { dat[i] = (*$1)[i]; }
$result = PyArray_Return(npy_arr);
}
%typemap(out) std::vector<std::vector<int> >& {
npy_intp result_size = $1->size();
npy_intp result_size2 = (result_size>0 ? (*$1)[0].size() : 0);
npy_intp dims[2] = { result_size, result_size2 };
PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(2, dims, NPY_INT);
int* dat = (int*) PyArray_DATA(npy_arr);
for (size_t i = 0; i < result_size; ++i) { for (size_t j = 0; j < result_size2; ++j) { dat[i*result_size2+j] = (*$1)[i][j]; } }
$result = PyArray_Return(npy_arr);
}
Edit 2:
Хотя не совсем то, что я искал, подобные проблемы могут быть решены с помощью @ подхода Монаха (explained here).
Я не думаю, что вы можете сделать это, не написав типовую карту и не сделав ее на стороне С, именно потому, что -builtin удаляет код, в котором обычно размещается pythonappend. Вы уверены, что -builtin намного быстрее (т. Е. Профилирование привело вас к его использованию?) У меня возникло бы желание использовать два модуля: один с одним без -builtin. – Flexo
Я удивлен, что нет предупреждения, что '-builtin' игнорирует pythonappend. Я не подхожу к вызову typemapping 'std :: vector' в массивы numpy. Я сделал профиль, и это значительно ускорило самый раздражающий цикл в моем интерфейсе (недостаточно долго, чтобы сделать паузу, слишком долго ждать часто). Но я также понял, что могу переместить этот цикл в свой код на C++, хотя и несколько неловко. Так вот как я пойду. Тем не менее, предложение «двух модулей» является интересным и может быть полезным в других случаях. – Mike
Вы звонили в SWIG -Wall? Я предположил, что в этом случае будет предупреждать. – Flexo