SegFault при попытке записи в массив Numpy, созданный в расширении C - PullRequest
0 голосов
/ 15 октября 2011

У меня есть предложение if внутри цикла for, в котором я предварительно определил state_out с помощью:

state_out = (PyArrayObject *) PyArray_FromDims(1,dims_new,NPY_BOOL);

И если условия такие:

        if (conn_ctr<sum*2){
            *(state_out->data + i*state_out->strides[0]) =  true;
        }
        else {
            *(state_out->data + i*state_out->strides[0]) =  false;
        }

При комментировании их, state_out возвращается как массив всех ложных значений Numpy. Существует проблема с этим заданием, которую я не вижу. Насколько я знаю, все в структуре PyArrayObject, которые вызываются здесь в этом коде, являются указателями, поэтому после арифметики указателей он должен указывать на адрес, который я намереваюсь написать. (Все, если условия в коде создаются путем достижения значений таким образом, и я знаю, что это работает, поскольку мне удалось напечатать значения входных массивов f.) Затем, если я хочу назначить bool одной из этих частей в памяти, Я должен назначить его через *(pointer_intended) = true Что мне не хватает?

РЕДАКТИРОВАТЬ: я заметил, что даже если я не достигну этих значений, даже если я поместил некоторые функции printf в:

if (conn_ctr<sum*2){
    printf("True!\n");
}
else {
    printf("False!\n");
}

Я снова получаю SegFault.

Большое спасибо, остальная часть кода здесь.

#include <Python.h>
#include "numpy/arrayobject.h"
#include <stdio.h>
#include <stdbool.h>

static PyObject* trace(PyObject *self, PyObject *args);

static char doc[] =
"This is the C extension for xor_masking routine. It interfaces with Python via C-Api, and calculates the"
"next state with C pointer arithmetic";

static PyMethodDef TraceMethods[] = {
    {"trace", trace, METH_VARARGS, doc},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
inittrace(void)
{
    (void) Py_InitModule("trace", TraceMethods);
    import_array();
}

static PyObject* trace(PyObject *self, PyObject *args){
    PyObject *adjacency ,*mask, *state;
    PyArrayObject *adjacency_arr, *mask_arr, *state_arr, *state_out;

    if (!PyArg_ParseTuple(args,"OOO:trace", &adjacency, &mask, &state)) return NULL;

    adjacency_arr = (PyArrayObject *)
        PyArray_ContiguousFromObject(adjacency, NPY_BOOL,2,2);

    if (adjacency_arr == NULL) return NULL;
    mask_arr = (PyArrayObject *)
        PyArray_ContiguousFromObject(mask, NPY_BOOL,2,2);

    if (mask_arr == NULL) return NULL;
    state_arr = (PyArrayObject *)
        PyArray_ContiguousFromObject(state, NPY_BOOL,1,1);

    if (state_arr == NULL) return NULL;

    int dims[2], dims_new[1];
    dims[0] = adjacency_arr -> dimensions[0];
    dims[1] = adjacency_arr -> dimensions[1];
    dims_new[0] =  adjacency_arr -> dimensions[0];
    if (!(dims[0]==dims[1] && mask_arr -> dimensions[0] == dims[0]
                         && mask_arr -> dimensions[1] == dims[0]
                         && state_arr -> dimensions[0] == dims[0]))
                         return NULL;


    state_out = (PyArrayObject *) PyArray_FromDims(1,dims_new,NPY_BOOL);

    int i,j;

    for(i=0;i<dims[0];i++){
        int sum = 0;
        int conn_ctr = 0;

            for(j=0;j<dims[1];j++){

                bool adj_value = (adjacency_arr->data + i*adjacency_arr->strides[0]
                         +j*adjacency_arr->strides[1]);

                if (*(bool *) adj_value == true){

                    bool mask_value = (mask_arr->data + i*mask_arr->strides[0]
                    +j*mask_arr->strides[1]);
                    bool state_value = (state_arr->data + j*state_arr->strides[0]);

                    if ( (*(bool *) mask_value ^ *(bool *)state_value) ==  true){
                        sum++;
                    }
                    conn_ctr++;
                }
            }

            if (conn_ctr<sum*2){

            }
            else {

            }
    }

    Py_DECREF(adjacency_arr);
    Py_DECREF(mask_arr);
    Py_DECREF(state_arr);
    return PyArray_Return(state_out);
}

1 Ответ

0 голосов
/ 16 октября 2011
    if (conn_ctr<sum*2){
        *(state_out->data + i*state_out->strides[0]) =  true;
    }
    else {
        *(state_out->data + i*state_out->strides[0]) =  false;
    }

Здесь я наивно делаю арифметику указателей, state_out-> data - указатель на начало данных, он определен как указатель char: SciPy Doc - Python Types и C-Structures

typedef struct PyArrayObject {
    PyObject_HEAD
    char *data;
    int nd;
    npy_intp *dimensions;
    npy_intp *strides;
    ...
} PyArrayObject;

Какую часть я скопировал здесь.state_out-> strides - указатель на массив длины измерения массива, который у нас есть.Это 1d массив в этом случае.Поэтому, когда я делаю арифметику указателя (state_out->data + i*state_out->strides[0]), я определенно стремлюсь вычислить указатель, который указывает i-е значение массива, но мне не удалось указать тип указателя, поэтому

я пытался:

NPY_BOOL *adj_value_ptr, *mask_value_ptr, *state_value_ptr, *state_out_ptr;

, которые переменные указывают на значения, которые меня интересуют, в мой цикл for, а state_out_ptr - это то, в которое я пишу.Я думал, что, поскольку я утверждаю, что компоненты этих массивов имеют тип NPY_BOOL, указатели, которые указывают на данные в массиве, также будут иметь тип NPY_BOOL. Это происходит с ошибкой SegFault, когда вы работаете с данными, непосредственно манипулирующими памятью.Это связано с тем, что NPY_BOOL является enum для целого числа (как указано в комментариях pv.) Для внутреннего использования NumPy. Для использования в коде существует C typedef npy_bool.логические значения. Scipy Docs .Когда я представил мои указатели с типом

npy_bool *adj_value_ptr, *mask_value_ptr, *state_value_ptr, *state_out_ptr;

Ошибка сегментации исчезла, и мне удалось манипулировать и вернуть массив Numpy.

Я не эксперт, но это решило мою проблему, укажите, если я ошибаюсь.

Часть, которая изменилась в исходном коде:

state_out = (PyArrayObject *) PyArray_FromDims(1,dims_new,NPY_BOOL);

npy_bool *adj_value_ptr, *mask_value_ptr, *state_value_ptr, *state_out_ptr;
npy_intp i,j;

for(i=0;i<dims[0];i++){
    npy_int sum = 0;
    npy_int conn_ctr = 0;

        for(j=0;j<dims[1];j++){

            adj_value_ptr = (adjacency_arr->data + i*adjacency_arr->strides[0]
                     +j*adjacency_arr->strides[1]);

            if (*adj_value_ptr == true){

                mask_value_ptr = (mask_arr->data + i*mask_arr->strides[0]
                +j*mask_arr->strides[1]);

                state_value_ptr = (state_arr->data + j*state_arr->strides[0]);

                if ( (*(bool *) mask_value_ptr ^ *(bool *)state_value_ptr) ==  true){
                    sum++;
                }
                conn_ctr++;
            }
        }
        state_out_ptr = (state_out->data + i*state_out->strides[0]);
        if (conn_ctr < sum*2){
            *state_out_ptr =  true;
        }
        else {
            *state_out_ptr =  false;
        }
}
...