Как работает прямой доступ к данным с помощью NpyIter (новый API)? Как мне работать с типом char *? - PullRequest
1 голос
/ 18 октября 2011

Я вскидываю руки и надеюсь, что кто-то здесь будет достаточно знать о новом NpyIter API в C API Numpy, чтобы быстро сообщить мне, что я делаю неправильно.

У меня есть массивформы (действительно большой, несколько большой).Элементы являются doubles> = 0. Для каждой строки мне нужно найти сумму непрерывных ненулевых значений, которые суммируются с наибольшим значением.Я не знаю ни одного способа сделать это быстро в одном только Python (действительно большой размер ~ 1e5), поэтому я вместо этого использовал Weave.

В моем старом коде у меня было следующее:

            double *p1,*res;
            double g,d,q;
            PyArrayIterObject *itr;
            int axis = 1;
            g = 0;
            d = 0;
            itr = (PyArrayIterObject *) PyArray_IterAllButAxis(py_x,&axis);
            while(PyArray_ITER_NOTDONE(itr)) {
                const int go = x_array->strides[axis]/sizeof(double);
                p1 = (double *) PyArray_ITER_DATA(itr);
                res = (double *) PyArray_GETPTR1(py_r,itr->index);
                g = 0;
                d = 0;
                for (int i = 0; i < x_array->dimensions[axis]; i++) {
                    d+=*p1;
                    if (d>g) g=d;
                    if ((*p1)==0) d=0;
                    p1+=go;
                }
                *res = g;
                PyArray_ITER_NEXT(itr);
            }
            PyArray_free(itr);

Это работает, но ужасно теряет память.Я не уверен, как остановить утечку, и документации по старому PyArrayIter с точки зрения управления памятью довольно не хватает.

Я пытался написать новый код с помощью API NpyIter, но документациядля этого в другом , кроме управления памятью, не хватает.В частности, я совсем не уверен, как мне получить доступ к фактическим значениям массива.Я пробовал следующее:

            char *p1; 
            double *res;
            char **p1p;
            double g,d,q;
            int go;
            NpyIter* iter;
            NpyIter_IterNextFunc *iternext;
            g = 0;
            d = 0;
            iter = NpyIter_New(x_array, NPY_ITER_READONLY|NPY_ITER_EXTERNAL_LOOP, NPY_KEEPORDER, NPY_NO_CASTING, NULL);
            iternext = NpyIter_GetIterNext(iter, NULL);
            p1p = NpyIter_GetDataPtrArray(iter);

            do {
                p1 = *p1p;
                const int go = x_array->strides[1]/sizeof(double);
                res = (double *) PyArray_GETPTR1(py_r,NpyIter_GetIterIndex(iter));
                g = 0;
                d = 0;
                for (int i = 0; i < x_array->dimensions[1]; i++) {
                    d+= p1;
                    if (d>g) g=d;
                    if ((*p1)==0) d=0;
                    p1+=go;
                }
                *res = g;
            } while(iternext(iter));

            NpyIter_Deallocate(iter);   

Однако, это, очевидно, не работает из-за char * против double *.Однако я не уверен, как взять (char **), возвращенный из NpyIter_GetDataPtrArray, и превратить его в фактические значения массива: в документации крайне бесполезно вместо этого используется функция, которая не указана, и принимает символ *.

Как я могу сделать это так, чтобы это работало и не давало утечки памяти?

1 Ответ

2 голосов
/ 18 октября 2011

В первом случае вам необходимо следовать обычным правилам управления памятью PyObject: Py_DECREF ваш PyArrayIterObject после использования, чтобы избежать утечки памяти.(PyArray_free делает что-то совсем другое.)

Для NpyIter:

Чтобы получить доступ к данным, захватите (double*)(*dataptr).

Если вы неточно знаю, что вы делаете, не используйте NPY_ITER_EXTERNAL_LOOP.Чтобы повторить поведение IterAllButAxis, вам нужно вызвать NpyIter_RemoveAxis, чтобы удалить ось, которую вы не хотите повторять из итерации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...