передача 2d массива из numpy в c ++ через swig не может использовать float ** - PullRequest
2 голосов
/ 11 января 2011

Я изучаю упаковку классов C ++ с помощью SWIG и передачу данных из numpy

Я могу успешно передать 1d массив, используя следующую карту типов

(float*, IN_ARRAY1, int DIM1)

Размер массива неизвестен во время компиляции, поэтому я не могу использовать карту типов

(float, IN_ARRAY2[DIM1][DIM2])

справка numpy.i предлагает использовать

(float*, IN_ARRAY2, int DIM1, int DIM2)

однако мой класс c ++ ожидает - указатель на указатель с плавающей точкой

void Initialise(float** buffer, long dim1, long dim2)

чтобы использовать карту типа float * IN_ARRAY2, мне нужно чередовать два измерения? Ург, я надеюсь, что нет, кому-нибудь удалось сделать это успешно, что вы делаете.

Ответы [ 2 ]

2 голосов
/ 14 января 2011

Казалось бы, вы не можете передать float ** в numpy C API, потому что они не совместимы с представлениями памяти априори.

В numpy данные в массиве должны находиться в одной непрерывной области памяти (могут быть дыры, но они должны располагаться в одном блоке, как выделено, например, malloc):

data -> | - | - | - | ..... | - | # this is allocated in one block
         a0  a1  a2          an

При использовании float **, вероятно, ваша модель памяти:

float** a;
int n = 10, m = 20; // n,m matrix

a = malloc(sizeof(*a) * n) // ten rows
for (int i=0; i < n; ++i) {
    a[i] = malloc(sizeof(*a[i]) * m); // one row of 29 items
}

То есть память:

a -> | a[0] | -> | a[0][0] | a[0][1] | a[0][2] | 
     | a[1] | -> | a[1][0] | ....

На самом деле это почти всегда плохой формат для числовых вычислений, потому что вы не можете передавать данные в одном блоке (плохо для локальности памяти и т. Д.), И почти каждая числовая библиотека стоит того, чтобы использовать ее в этом формате. Смотрите, например это для объяснения.

Тем не менее, предполагая, что вы не можете изменить свой код, вы можете легко преобразовать формат одного блока в формат с плавающей запятой ** без копирования (обратное невозможно):

void convert(float *in, int n, int m, float ***out)
{
    float **data;
    int i;

    data = malloc(sizeof(*data) * n);
    for(i = 0; i < n; ++i) {
            data[i] = in + i * m:
    }       

    *out = data;
}

И вы вызываете эту функцию как таковую

float **a;
convert((float*)numpy_data, n, m, &a);

Initialise(a, n, m);

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

0 голосов
/ 11 января 2011

В любом случае, если вы передаете массив в качестве параметра, вы передаете указатель на первый элемент массива. И вы должны знать размер массива, чтобы работать с ним.

...