Boost numpy пример не работает - PullRequest
0 голосов
/ 03 мая 2018

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

#include <boost/python.hpp>
#include <boost/python/numpy.hpp>
#include <iostream>

using namespace std;

namespace p = boost::python;
namespace np = boost::python::numpy;

np::ndarray test()
{
    int data[] = {1,2,3,4,5};
    p::tuple shape = p::make_tuple(5);
    p::tuple stride = p::make_tuple(sizeof(int));
    p::object own;
    np::dtype dt = np::dtype::get_builtin<int>();
    np::ndarray array = np::from_data(data, dt, shape,stride,own);
    std::cout << "Selective multidimensional array :: "<<std::endl
        << p::extract<char const *>(p::str(array)) << std::endl ;
    return array;
}


BOOST_PYTHON_MODULE(test_module)
{
    using namespace boost::python;

    // Initialize numpy
    Py_Initialize();
    boost::python::numpy::initialize();

    def("test", test);
}

Когда я компилирую как разделяемую библиотеку и загружаю модуль в python,

import test_module as test
print(test.test())

похоже, что ndarray правильно создается кодом C ++, но версия, которую получает python, является мусором; печатные массивы:

[1 2 3 4 5]
[2121031184      32554 2130927769      32554          0]

Что может быть причиной такой разницы?

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

Создание новой ссылки на массив перед его возвратом решило проблему. Хорошая новость заключается в том, что np::ndarray имеет метод copy(), который достигает точно такой же вещи. Таким образом, вы должны добавить

np::ndarray new_array = array.copy();

до выписки

0 голосов
/ 21 августа 2018

На этой неделе у меня была такая же проблема. Для решения моей проблемы я использую динамическую память:

np::ndarray test(){
    int *data = malloc(sizeof(int) * 5);
    for (int i=0; i < 5; ++i){
        data[i] = i + 1;
    }
    p::tuple shape = p::make_tuple(5);
    p::tuple stride = p::make_tuple(sizeof(int));
    p::object own;
    np::dtype dt = np::dtype::get_builtin<int>();
    np::ndarray array = np::from_data(data, dt, shape, stride, own);
    return array;
}

Я думаю, что разница согласно этому ответу: https://stackoverflow.com/a/36322044/4637693 составляет:

Разница между объявлением массива

int array[n];

и

int* array = malloc(n * sizeof(int));

В первой версии вы объявляете объект с автоматической продолжительностью хранения. Это означает, что массив живет только до тех пор, пока существует функция, которая его вызывает. Во второй версии вы получаете память с динамическим сроком хранения, что означает, что она будет существовать до тех пор, пока она не будет явно освобождена.

В следующие недели я потрачу больше времени, чтобы проверить, работает ли это и для матрицы.

EDIT

Или вы можете использовать динамическую структуру из списка Boost:

np::ndarray test(){
    boost::python::list my_list;
    for (int i=0; i < 5; ++i){
        my_list.append(i + 1);
    }
    np::ndarray array = np::from_object(my_list);
    return array;
}

Эта работа также для Матрицы, например:

np::ndarray test(){
    //This will use a list of tuples
    boost::python::list my_list;
    for (int i=0; i < 5; ++i){
        my_list.append(boost::python::make_tuple(i + 1, i, i-1));
    }
    //Just convert the list to a NumPy array.
    np::ndarray array = np::from_object(my_list);
    return array;
}

Полагаю (на данный момент), что с помощью функций повышения вы сможете избежать конфликтов памяти.

...