Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> C-API: Py_BuildValue(). Ошибка при is not None 
:(
    Опции темы
wowka19
  Дата 27.5.2015, 07:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Написал модуль на C. Всего одна функция griddata. Она возвращает словарь либо None:
Код

...
if (is_empty) Py_RETURN_NONE;

return Py_BuildValue("{sfsfsfsfsO}",
                         "min_x", minimum_x,
                         "min_y", minimum_y,
                         "max_x", maximum_x,
                         "max_y", maximum_y,
                         "values", PyArray_Return(output_array)); // - ndarray float32


Модуль отрабатывает без нареканий. Однако уже в python-коде мне нужно проверить, что результат НЕ None. Делаю я это так:
Код

res = griddata(...)
if res:
    ...

или так:
Код

res = griddata(...)
if res is not None:
    ...

или так:
Код

res = griddata(...)
if isinstance(res, dict):
    ...

Во всех трех случаях программа иногда отрабатывает нормально либо иногда завершается крахом на уровне ОС, который питон не отлавливает.
Подчеркну, что это происходит примерно 50/50 при одинаковых входных данных.
Создается впечатление, что модуль на C возвращает неполноценный объект, который не способен нормально сравниваться с None.
Причем сравнивать результат с None:
Код

res = griddata(...)
if res is None:
    ...

то ошибок не бывает. Поэтому я решил схитрить:
Код

res = griddata(...)
if res is None:
    здесь просто заглушка 'print 0'
else:
    ...

но тогда ошибка возвращается.
Т.е. сравнить с None можно, с НЕ None иногда крах уровня ОС.

Вот код всего модуля:
Код

#include <Python.h>
#include <numpy/arrayobject.h>

#include <stdlib.h>
#include <stdbool.h>
#include <math.h>

typedef struct
{
    int x;
    int y;
} TPoint;

typedef struct
{
    float x;
    float y;
    float v;
} TPointF;

float min3(float a, float b, float c)
{
    if (a < b) return (a<c?a:c);
    else return (b<c?b:c);
}

float max3(float a, float b, float c)
{
    if (a > b) return (a>c?a:c);
    else return (b>c?b:c);
}

float min4(float a, float b, float c, float d)
{
    if (a < b)
    {
        if (a < c) return (a<d?a:d);
        else return (c<d?c:d);
    }
    else
    {
        if (b < c) return (b<d?b:d);
        else return (c<d?c:d);
    }
}

float max4(float a, float b, float c, float d)
{
    if (a > b)
    {
        if (a > c) return (a>d?a:d);
        else return (c>d?c:d);
    }
    else
    {
        if (b > c) return (b>d?b:d);
        else return (c>d?c:d);
    }
}

bool in_triangle(TPoint p, TPointF a, TPointF b, TPointF c)
{
    float ab = (a.x-p.x)*(b.y-a.y) - (b.x-a.x)*(a.y-p.y);
    float bc = (b.x-p.x)*(c.y-b.y) - (c.x-b.x)*(b.y-p.y);
    float ca = (c.x-p.x)*(a.y-c.y) - (a.x-c.x)*(c.y-p.y);

    if ((ab<=0 && bc<=0 && ca<=0) || (ab>=0 && bc>=0 && ca>=0)) return true;
    else return false;
}

float interpolation(TPoint p, TPointF a, TPointF b, TPointF c)
{
    float x_delta = p.x - a.x;
    float y_delta = p.y - a.y;
    float w_a = 1 / sqrtf(x_delta*x_delta + y_delta*y_delta);
    x_delta = p.x - b.x;
    y_delta = p.y - b.y;
    float w_b = 1 / sqrtf(x_delta*x_delta + y_delta*y_delta);
    x_delta = p.x - c.x;
    y_delta = p.y - c.y;
    float w_c = 1 / sqrtf(x_delta*x_delta + y_delta*y_delta);

    return (a.v*w_a + b.v*w_b + c.v*w_c) / (w_a+w_b+w_c);
}

static PyObject*
griddata(PyObject* self, PyObject* args)
{
    PyArrayObject* x_array = NULL;
    PyArrayObject* y_array = NULL;
    PyArrayObject* values_array = NULL;
    float minimum_value;
    float scale_factor;
    if (PyArg_ParseTuple(args, "O!O!O!ff",
        &PyArray_Type, &x_array,
        &PyArray_Type, &y_array,
        &PyArray_Type, &values_array,
        &minimum_value, &scale_factor) == 0) return NULL;

    /* Input validation */
    if (PyArray_TYPE(x_array) != NPY_FLOAT ||
        PyArray_TYPE(y_array) != NPY_FLOAT ||
        PyArray_TYPE(values_array) != NPY_FLOAT) return NULL;
    if (PyArray_NDIM(x_array) != 2 || PyArray_NDIM(y_array) != 2 || PyArray_NDIM(values_array) != 2) return NULL;
    int dims[2];
    dims[0] = x_array->dimensions[0];
    dims[1] = x_array->dimensions[1];
    if (! (dims[0] > 0 && dims[1] > 0)) return NULL;
    if (y_array->dimensions[0] != dims[0] || y_array->dimensions[1] != dims[1] ||
        values_array->dimensions[0] != dims[0] || values_array->dimensions[1] != dims[1]) return NULL;


    /* Find the minimum and maximum coordinates */
    float minimum_x;
    float minimum_y;
    float maximum_x;
    float maximum_y;
    {
        int i = 0;
        bool finded = false;
        for (; i < dims[0]; ++i)
        {
            for (int j = 0; j < dims[1]; ++j)
            {
                if (*(float*)PyArray_GETPTR2(values_array, i, j) < minimum_value) continue;
                float x = *(float*)PyArray_GETPTR2(x_array, i, j);
                float y = *(float*)PyArray_GETPTR2(y_array, i, j);
                minimum_x = maximum_x = x;
                minimum_y = maximum_y = y;
                finded = true;
                break;
            }
            if (finded) break;
        }
        if (! finded) Py_RETURN_NONE;

        finded = false;
        for (; i < dims[0]; ++i)
        {
            for (int j = 0; j < dims[1]; ++j)
            {
                if (*(float*)PyArray_GETPTR2(values_array, i, j) < minimum_value) continue;
                float x = *(float*)PyArray_GETPTR2(x_array, i, j);
                float y = *(float*)PyArray_GETPTR2(y_array, i, j);
                if (x < minimum_x) minimum_x = x;
                if (y < minimum_y) minimum_y = y;
                if (x > maximum_x) maximum_x = x;
                if (y > maximum_y) maximum_y = y;
                finded = true;
            }
        }
        if (! finded) Py_RETURN_NONE;
    }

    /* Transformation of coordinates */
    float* new_x_array = malloc(sizeof(float)*dims[0]*dims[1]);
    if (new_x_array == NULL) return NULL;
    float* new_y_array = malloc(sizeof(float)*dims[0]*dims[1]);
    if (new_y_array == NULL)
    {
        free(new_x_array);
        return NULL;
    }
    for (int i=0; i < dims[0]; ++i)
    {
        for (int j=0; j < dims[1]; ++j)
        {
            if (*(float*)PyArray_GETPTR2(values_array, i, j) < minimum_value) continue;
            float x = *(float*)PyArray_GETPTR2(x_array, i, j);
            float y = *(float*)PyArray_GETPTR2(y_array, i, j);
            int index = dims[1]*i + j;
            new_x_array[index] = (x - minimum_x) * scale_factor;
            new_y_array[index] = (y - minimum_y) * scale_factor;
        }
    }

    /* Creating the output array */
    int width = (int) ceilf((maximum_x - minimum_x) * scale_factor);
    int height = (int) ceilf((maximum_y - minimum_y) * scale_factor);
    if (width <= 0 || height <= 0) return NULL;
    int new_dims[2];
    new_dims[0] = height;
    new_dims[1] = width;
    PyArrayObject* output_array = PyArray_FromDims(2, new_dims, NPY_FLOAT);
    for (int i=0; i<height; ++i) for (int j=0; j<=width; ++j) *(float*)PyArray_GETPTR2(output_array, i,j) = minimum_value-1;

    /* Interpolation */
    bool is_empty = true;
    for (int i=0; i+1 < dims[0]; ++i)
    {
        for (int j=0; j+1 < dims[1]; ++j)
        {
            int index00 = dims[1]*i + j;
            int index01 = dims[1]*i + j+1;
            int index10 = dims[1]*(i+1) + j;
            int index11 = dims[1]*(i+1) + j+1;

            float v00 = *(float*)PyArray_GETPTR2(values_array, i,j);
            float v01 = *(float*)PyArray_GETPTR2(values_array, i,j+1);
            float v10 = *(float*)PyArray_GETPTR2(values_array, i+1,j);
            float v11 = *(float*)PyArray_GETPTR2(values_array, i+1,j+1);

            TPointF p00 = {.x = new_x_array[index00], .y = new_y_array[index00], .v = v00};
            TPointF p01 = {.x = new_x_array[index01], .y = new_y_array[index01], .v = v01};
            TPointF p10 = {.x = new_x_array[index10], .y = new_y_array[index10], .v = v10};
            TPointF p11 = {.x = new_x_array[index11], .y = new_y_array[index11], .v = v11};

            if (v00 < minimum_value)
            {
                if (v01 < minimum_value || v10 < minimum_value || v11 < minimum_value) continue;
                int begin_x = (int) ceilf(min3(p01.x, p10.x, p11.x));
                int end_x = (int) floorf(max3(p01.x, p10.x, p11.x));
                int begin_y = (int) ceilf(min3(p01.y, p10.y, p11.y));
                int end_y = (int) floorf(max3(p01.y, p10.y, p11.y));

                if (begin_x < 0) begin_x = 0;
                if (end_x >= width) end_x = width-1;
                if (begin_y < 0) begin_y = 0;
                if (end_y >= height) end_y = height-1;

                for (int y = begin_y; y <= end_y; ++y)
                {
                    for (int x = begin_x; x <= end_x; ++x)
                    {
                        TPoint p = {.x = x, .y = y};
                        if (in_triangle(p, p01, p10, p11))
                        {
                            *(float*)PyArray_GETPTR2(output_array, y, x) = interpolation(p, p01, p10, p11);
                            is_empty = false;
                        }
                    }
                }
            }
            else if (v01 < minimum_value)
            {
                if (v00 < minimum_value || v10 < minimum_value || v11 < minimum_value) continue;
                int begin_x = (int) ceilf(min3(p00.x, p10.x, p11.x));
                int end_x = (int) floorf(max3(p00.x, p10.x, p11.x));
                int begin_y = (int) ceilf(min3(p00.y, p10.y, p11.y));
                int end_y = (int) floorf(max3(p00.y, p10.y, p11.y));

                if (begin_x < 0) begin_x = 0;
                if (end_x >= width) end_x = width-1;
                if (begin_y < 0) begin_y = 0;
                if (end_y >= height) end_y = height-1;

                for (int y = begin_y; y <= end_y; ++y)
                {
                    for (int x = begin_x; x <= end_x; ++x)
                    {
                        TPoint p = {.x = x, .y = y};
                        if (in_triangle(p, p00, p10, p11))
                        {
                            *(float*)PyArray_GETPTR2(output_array, y, x) = interpolation(p, p00, p10, p11);
                            is_empty = false;
                        }
                    }
                }
            }
            else if (v10 < minimum_value)
            {
                if (v00 < minimum_value || v01 < minimum_value || v11 < minimum_value) continue;
                int begin_x = (int) ceilf(min3(p00.x, p01.x, p11.x));
                int end_x = (int) floorf(max3(p00.x, p01.x, p11.x));
                int begin_y = (int) ceilf(min3(p00.y, p01.y, p11.y));
                int end_y = (int) floorf(max3(p00.y, p01.y, p11.y));

                if (begin_x < 0) begin_x = 0;
                if (end_x >= width) end_x = width-1;
                if (begin_y < 0) begin_y = 0;
                if (end_y >= height) end_y = height-1;

                for (int y = begin_y; y <= end_y; ++y)
                {
                    for (int x = begin_x; x <= end_x; ++x)
                    {
                        TPoint p = {.x = x, .y = y};
                        if (in_triangle(p, p00, p01, p11))
                        {
                            *(float*)PyArray_GETPTR2(output_array, y, x) = interpolation(p, p00, p01, p11);
                            is_empty = false;
                        }
                    }
                }
            }
            else if (v11 < minimum_value)
            {
                if (v00 < minimum_value || v01 < minimum_value || v10 < minimum_value) continue;
                int begin_x = (int) ceilf(min3(p00.x, p01.x, p10.x));
                int end_x = (int) floorf(max3(p00.x, p01.x, p10.x));
                int begin_y = (int) ceilf(min3(p00.x, p01.y, p10.y));
                int end_y = (int) floorf(max3(p00.x, p01.y, p10.y));

                if (begin_x < 0) begin_x = 0;
                if (end_x >= width) end_x = width-1;
                if (begin_y < 0) begin_y = 0;
                if (end_y >= height) end_y = height-1;

                for (int y = begin_y; y <= end_y; ++y)
                {
                    for (int x = begin_x; x <= end_x; ++x)
                    {
                        TPoint p = {.x = x, .y = y};
                        if (in_triangle(p, p00, p01, p10))
                        {
                            *(float*)PyArray_GETPTR2(output_array, y, x) = interpolation(p, p00, p01, p10);
                            is_empty = false;
                        }
                    }
                }
            }
            else
            {
                int begin_x = (int) ceilf(min4(p00.x, p01.x, p10.x, p11.x));
                int end_x = (int) floorf(max4(p00.x, p01.x, p10.x, p11.x));
                int begin_y = (int) ceilf(min4(p00.y, p01.y, p10.y, p11.y));
                int end_y = (int) floorf(max4(p00.y, p01.y, p10.y, p11.y));

                if (begin_x < 0) begin_x = 0;
                if (end_x >= width) end_x = width-1;
                if (begin_y < 0) begin_y = 0;
                if (end_y >= height) end_y = height-1;

                for (int y = begin_y; y <= end_y; ++y)
                {
                    for (int x = begin_x; x <= end_x; ++x)
                    {
                        TPoint p = {.x = x, .y = y};
                        if (in_triangle(p, p00, p01, p10))
                        {
                            *(float*)PyArray_GETPTR2(output_array, y, x) = interpolation(p, p00, p01, p10);
                            is_empty = false;
                        }
                        else if(in_triangle(p, p10, p01, p11))
                        {
                            *(float*)PyArray_GETPTR2(output_array, y, x) = interpolation(p, p10, p01, p11);
                            is_empty = false;
                        }
                    }
                }
            }
        }
    }
    free(new_x_array);
    free(new_y_array);

    if (is_empty) Py_RETURN_NONE;

    return Py_BuildValue("{sfsfsfsfsO}",
                         "min_x", minimum_x,
                         "min_y", minimum_y,
                         "max_x", maximum_x,
                         "max_y", maximum_y,
                         "values", PyArray_Return(output_array));
}


static PyMethodDef
cgriddata_methods[] = {
    {"griddata", griddata, METH_VARARGS, "linear interpolation"},
    {NULL, NULL, 0, NULL}
};


PyMODINIT_FUNC
initcgriddata(void)
{
    (void) Py_InitModule("cgriddata", cgriddata_methods);
    import_array();
}


UPDATE: Решил обойти None и вместо него возвращать словарь с ключом "status" равным либо 0 (пусто) либо 1 (ок). В коде на C это выглядит так:
Код

if (is_empty) return Py_BuildValue("{si}", "status", 0);

    return Py_BuildValue("{sisfsfsfsfsO}",
                         "status", 1,
                         "min_x", minimum_x,
                         "min_y", minimum_y,
                         "max_x", maximum_x,
                         "max_y", maximum_y,
                         "values", PyArray_Return(output_array));

Запускаю:
Код

res = griddata(...)
if res['status'] == 1:
    ...

и в итоге получаю такое же поведение: иногда норм, иногда крах.
Что не так?

Это сообщение отредактировал(а) wowka19 - 27.5.2015, 07:27
PM MAIL   Вверх
wowka19
Дата 3.6.2015, 10:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



1. Выход за границы массива:
Код

for (int i=0; i<height; ++i) for (int j=0; j<=width; ++j) *(float*)PyArray_GETPTR2(output_array, i,j) = minimum_value-1;


2. Здесь утечка памяти:
Код

return Py_BuildValue("{sfsfsfsfsO}",
                         "min_x", minimum_x,
                         "min_y", minimum_y,
                         "max_x", maximum_x,
                         "max_y", maximum_y,
                         "values", PyArray_Return(output_array));

Надо так:
Код

PyObject* result = Py_BuildValue("{sfsfsfsfsO}",
                                     "min_x", minimum_x,
                                     "min_y", minimum_y,
                                     "max_x", maximum_x,
                                     "max_y", maximum_y,
                                     "values", PyArray_Return(output_array));
Py_DECREF(output_array);
return result;

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Python: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0847 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.