如何从boost ::蟒蛇返回numpy.array?如何从boost ::蟒蛇返回numpy.ar

2019-05-14 10:04发布

我想从C ++代码作为返回一些数据numpy.array对象。 我有一个看boost::python::numeric ,但它的文档非常简洁。 我可以得到例如返回(不是很大)为例vector<double>到Python? 我不介意做数据的副本。

Answer 1:

更新:在我原来的答复中描述的库( https://github.com/ndarray/Boost.NumPy )已经直接集成到Boost.Python的作为升压1.63,因此单机版现在已经过时。 下面现在的文本对应于新的集成的版本(仅在命名空间已经改变)。

Boost.Python的现在包括NumPy的C-API的适度完整包装成Boost.Python的接口。 这是相当级别较低,主要集中在如何解决如何通过C ++数据和从NumPy的没有复制,更困难的问题,但这里是你如何做一个复制的std ::向量回归:

#include "boost/python/numpy.hpp"

namespace bp = boost::python;
namespace bn = boost::python::numpy;

std::vector<double> myfunc(...);

bn::ndarray mywrapper(...) {
    std::vector<double> v = myfunc(...);
    Py_intptr_t shape[1] = { v.size() };
    bn::ndarray result = bn::zeros(1, shape, bn::dtype::get_builtin<double>());
    std::copy(v.begin(), v.end(), reinterpret_cast<double*>(result.get_data()));
    return result;
}

BOOST_PYTHON_MODULE(example) {
    bn::initialize();
    bp::def("myfunc", mywrapper);
}


Answer 2:

不需要你解决下载任何特殊的第三方C ++库(但你需要numpy的)。

#include <numpy/ndarrayobject.h> // ensure you include this header

boost::python::object stdVecToNumpyArray( std::vector<double> const& vec )
{
      npy_intp size = vec.size();

     /* const_cast is rather horrible but we need a writable pointer
        in C++11, vec.data() will do the trick
        but you will still need to const_cast
      */

      double * data = size ? const_cast<double *>(&vec[0]) 
        : static_cast<double *>(NULL); 

    // create a PyObject * from pointer and data 
      PyObject * pyObj = PyArray_SimpleNewFromData( 1, &size, NPY_DOUBLE, data );
      boost::python::handle<> handle( pyObj );
      boost::python::numeric::array arr( handle );

    /* The problem of returning arr is twofold: firstly the user can modify
      the data which will betray the const-correctness 
      Secondly the lifetime of the data is managed by the C++ API and not the 
      lifetime of the numpy array whatsoever. But we have a simple solution..
     */

       return arr.copy(); // copy the object. numpy owns the copy now.
  }

当然,你可能会写从double *和大小,这是通用的,然后通过提取该信息援引来自该载体的功能。 你也可以写一个模板,但你需要某种形式的数据类型映射到NPY_TYPES枚举。



Answer 3:

这是一个有点晚了,但很多不成功的尝试后,我找到了一种方法来揭露C ++数组作为直接numpy的阵列。 下面是一个使用短C ++ 11例如boost::python和本征:

#include <numpy/ndarrayobject.h>
#include <boost/python.hpp>

#include <Eigen/Core>

// c++ type
struct my_type {
  Eigen::Vector3d position;
};


// wrap c++ array as numpy array
static boost::python::object wrap(double* data, npy_intp size) {
  using namespace boost::python;

  npy_intp shape[1] = { size }; // array size
  PyObject* obj = PyArray_New(&PyArray_Type, 1, shape, NPY_DOUBLE, // data type
                              NULL, data, // data pointer
                              0, NPY_ARRAY_CARRAY, // NPY_ARRAY_CARRAY_RO for readonly
                              NULL);
  handle<> array( obj );
  return object(array);
}



// module definition
BOOST_PYTHON_MODULE(test)
{
  // numpy requires this
  import_array();

  using namespace boost::python;

  // wrapper for my_type
  class_< my_type >("my_type")
    .add_property("position", +[](my_type& self) -> object {
        return wrap(self.position.data(), self.position.size());
      });

}

这个例子说明该属性的“吸气剂”。 对于“设定器”,最简单的方式是从一个手动分配数组元素boost::python::object使用boost::python::stl_input_iterator<double>



Answer 4:

直接使用numpy的API做起来不一定很难,但我使用boost ::多阵列经常为我的项目,并发现它方便地自动转换C ++ / Python的边界之间的阵列的形状。 所以,这里是我的食谱。 使用http://code.google.com/p/numpy-boost/ ,或者更好的是, 这个版本的numpy_boost.hpp头的; 这是一个更适合多文件boost :: Python项目,虽然它使用了一些C ++ 11。 然后,从你的boost :: Python代码,使用这样的:

PyObject* myfunc(/*....*/)
{
   // If your data is already in a boost::multiarray object:
   // numpy_boost< double, 1 > to_python( numpy_from_boost_array(result_cm) );
   // otherwise:
   numpy_boost< double, 1> to_python( boost::extents[n] );
   std::copy( my_vector.begin(), my_vector.end(), to_python.begin() );

   PyObject* result = to_python.py_ptr();
   Py_INCREF( result );

   return result;
}


Answer 5:

我看了看现有的答案,并认为,“这将是很容易”。 我开始花时间尝试似乎像答案的一个简单的例子/改编。

然后,我实现了@最大的确切答案(必须安装艾根)和它的工作很好,但我仍然有麻烦适应它。 我的问题大多是(按编号)傻了,语法错误,但另外我是用一个指向拷贝的std :: vector的数据载体似乎下车栈之后。

在这个例子中,一个指针的std ::矢量返回,但你也可以返回的大小和数据()的指针或使用任何其它的实现,给出了一个稳定的方式(即保证基础数据的numpy的数组访问存在):

class_<test_wrap>("test_wrap")
    .add_property("values", +[](test_wrap& self) -> object {
            return wrap(self.pvalues()->data(),self.pvalues()->size());
        })
    ;

对于具有test_wrap std::vector<double> (通常p值()可能只返回指针,未填充的向量):

class test_wrap {
public:
    std::vector<double> mValues;
    std::vector<double>* pvalues() {
        mValues.clear();
        for(double d_ = 0.0; d_ < 4; d_+=0.3)
        {
            mValues.push_back(d_);
        }
        return &mValues;
    }
};

完整的例子是在Github上,那么可以跳过繁琐的转录步骤和少担心身材,库等等。你应该能够只是做以下,并得到一个有效的例子(如果你有安装了必要的功能和您的路径设置已经):

git clone https://github.com/ransage/boost_numpy_example.git
cd boost_numpy_example
# Install virtualenv, numpy if necessary; update path (see below*)
cd build && cmake .. && make && ./test_np.py

这应该给输出:

# cmake/make output
values has type <type 'numpy.ndarray'>
values has len 14
values is [ 0.   0.3  0.6  0.9  1.2  1.5  1.8  2.1  2.4  2.7  3.   3.3  3.6  3.9]

*在我的情况,我把numpy的到的virtualenv如下-这应该是不必要的,如果你可以执行python -c "import numpy; print numpy.get_include()"由@Max的建议:

# virtualenv, pip, path unnecessary if your Python has numpy
virtualenv venv
./venv/bin/pip install -r requirements.txt 
export PATH="$(pwd)/venv/bin:$PATH"

玩得开心! :-)



文章来源: how to return numpy.array from boost::python?