Swig, возвращая массив двойников - PullRequest
9 голосов
/ 28 апреля 2011

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

У меня есть C-функция, которая возвращает мне массив двойных значений:

double *my(int x)
{
   double a,b,*buf;
   buf = malloc (x * sizeof(double));
   a=3.14;
   b=2.7;
   buf[0]=a;
   buf[1]=b;
   return buf;
}

Здесь я определенно хочу иметь массив в качестве возвращаемого значения. Нет, как во многих примерах функция 'void', которая записывает во входной массив. Теперь я хотел бы получить оболочку SWIG-python, которую можно использовать как:

>>> import example
>>> print example.my(7)
[3.14,2.7]

Что бы я ни делал, у меня здесь есть некоторые концептуальные проблемы - я всегда получаю ст.ст. как <Swig Object of type 'double *' at 0xFABCABA12>

Я попытался определить некоторые карты типов в моем SWG-файле:

%typemap(out) double [ANY] {
  int i;
  $result = PyList_New($1_dim0);
  for (i = 0; i < $1_dim0; i++) {
    PyObject *o = PyFloat_FromDouble((double) $1[i]);
    PyList_SetItem($result,i,o);
  }
}

Но я все еще не могу получить свои результаты по мере необходимости. У кого-нибудь есть простой пример кода для решения этой задачи?

Ответы [ 5 ]

4 голосов
/ 30 мая 2011

Первая проблема заключается в том, что ваша карта типов не соответствует, вам понадобится %typemap(out) double * { ... }, так как ваша функция возвращает указатель на двойной, а не двойной массив.

Если ваш список имеет фиксированный размер (т. Е. Целочисленный литерал), как в приведенном вами примере (который, я полагаю, не то, что вам нужно), вы можете просто изменить карту типов, как я дал выше, и обменять $1_dim0 на фиксированные размер.

В противном случае ваша проблема заключается в том, что ваш %typemap(out) double * не может знать значение вашего параметра int x. Вы можете вернуть структуру, которая содержит как указатель, так и размер. Затем вы можете легко определить карту типов, чтобы превратить ее в список (или массив NumPy, см. Также мой ответ на Обертывание структуры C с элементом массива для доступа в python: SWIG? Cython? Ctypes? ).

Между прочим, невозможно вернуть массив фиксированного размера в C (см. Также этот ответ: Объявление функции C для возврата массива ), поэтому %typemap(out) double [ANY] { ... } никогда не может совпадать.

3 голосов
/ 19 декабря 2011

Я столкнулся с подобной проблемой и решил ее следующим образом.

// example.i

%module example

%include "carrays.i"
%array_class(float, floatArray);

float * FloatArray(int N);

float SumFloats(float * f);

# ipython

> a = example.floatArray(23) # array generated by swig's class constructor

> a

<example.floatArray; proxy of <Swig Object of type 'floatArray *' at 0x2e74180> >

> a[0]

-2.6762280573445764e-37 # unfortunately it is created uninitialized..

> b = example.FloatArray(23) # array generated by function

> b

<Swig Object of type 'float *' at 0x2e6ad80>

> b[0]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
# .....
TypeError: 'SwigPyObject' object is not subscriptable

> #But there is a way to access b!!

> p = example.floatArray_frompointer(b) # i found this function by example. and twice tab

> p

<example.floatArray; proxy of <Swig Object of type 'floatArray *' at 0x2e66750> >

> p[0]

0.0

> p[0] = 42

> p[0]

42.0

К счастью, все эти типы (float *, floatArray * и прокси floatArray *) может быть успешно передано в функцию C ++ (например, SumFloats).

1 голос
/ 23 мая 2015

Если вы не возражаете против добавления модуля numpy python в свой код python, вы можете сделать следующее:

В файле интерфейса SWIG:

%{
#define SWIG_FILE_WITH_INIT
%}
%include "numpy.i"
%init %{
import_array();
%}

%apply(float ARGOUT_ARRAY1[ANY]) {(float outarray1d[9])};
void rf(float outarray1d[9]);

Только последние две строки относятся к этому примеру, первый материал по умолчанию для numpy.i (см. Документацию numpy.i в другом месте: http://docs.scipy.org/doc/numpy/reference/swig.interface-file.html).

В файле C (также может быть встроен в файл .i):

void rf(float outarray1d[9]) {
    float _internal_rf[9];
    /* ... */
    memcpy(outarray1d, _internal_rf, 9*sizeof(float));
}

Тогда у вас есть функция, которую вы можете вызвать из python как

import mymodule
a = mymodule.rf()
# a is a numpy array of float32's, with len 9

Теперь, если вы не хотите, чтобы вас заставляли вставлять модуль numpy в ваш проект python, тогда я предлагаю вам проверить numpy.i, чтобы увидеть, как они делают трюк% typemap - насколько я понимаю, выполненный с SWIG-типами и не привязанный к numpy по своей сути - должен быть возможен тот же трюк с кортежами или списками, что и возвращаемое значение.

1 голос
/ 26 мая 2011

Возможно, вы захотите взглянуть на документацию вокруг carray.i:

% include "carrays.i"% array_class (int, intArray);

http://www.swig.org/Doc2.0/Python.html#Python_nn48

0 голосов
/ 16 мая 2011

Я не знаю, сколько C вы знаете - поэтому извиняюсь, если я учу вас сосать яйца здесь ...

В обычном оле C. нет класса Array. Массив всегдауказатель на кусок памяти, а не «вещь» сам по себе, и поэтому не может быть просто распечатан сам по себе.

В этом случае - ваш «buf» имеет тип «double *».AFAICRem, если вы хотите распечатать фактические значения, хранящиеся в «памяти, на которую указывает buf», вы должны освободить каждое из них, например (в псевдокоде): от i = 0 до длины печати print buf [i]

...