如何从 boost::p ython 返回 numpy.array
how to return numpy.array from boost::python?
我想从 c++ 代码返回一些数据作为numpy.array
对象。我看了一下boost::python::numeric
,但它的文档非常简洁。我可以得到一个示例,例如将一个(不是很大的(vector<double>
返回给 python?我不介意做数据的副本。
更新:我的原始答案(https://github.com/ndarray/Boost.NumPy(中描述的库已从Boost 1.63开始直接集成到Boost.Python中,因此独立版本现已弃用。 下面的文本现在对应于新的集成版本(仅命名空间已更改(。
Boost.Python现在将 NumPy C-API 的适度完整的包装器包含在 Boost.Python 接口中。 这是相当低级的,主要集中在如何解决更困难的问题,即如何在不复制的情况下将C++数据传入和传出 NumPy,但以下是您如何执行复制的 std::vector 返回:
#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);
}
一个不需要您下载任何特殊的第三方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.
}
当然,你可以从双倍*和大小编写一个函数,这是通用的,然后通过提取此信息从向量中调用它。您也可以编写模板,但需要从数据类型到NPY_TYPES
枚举的某种映射。
有点晚了,但是经过多次不成功的尝试,我找到了一种直接将 c++ 数组公开为 numpy 数组的方法。下面是一个使用 boost::python
和 Eigen 的简短 C++11 示例:
#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());
});
}
该示例描述了属性的"getter"。对于"setter",最简单的方法是使用 boost::python::stl_input_iterator<double>
从boost::python::object
手动分配数组元素。
直接使用 numpy api 不一定很困难,但我在我的项目中经常使用 boost::multiarray,并且发现在 C++/Python 边界之间自动传输数组的形状很方便。所以,这是我的食谱。使用 http://code.google.com/p/numpy-boost/或更好的是,此版本的 numpy_boost.hpp 标头;这更适合多文件 boost::p ython 项目,尽管它使用了一些 C++11。然后,从你的 boost::p ython 代码中,使用如下内容:
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;
}
我查看了可用的答案并想,"这将很容易"。 我继续花了几个小时尝试看似微不足道的例子/对答案的改编。
然后我完全实现了@max的答案(必须安装 Eigen(,它工作正常,但我仍然无法适应它。 我的问题主要是(按数字(愚蠢的语法错误,但此外,在向量似乎从堆栈中删除后,我使用了一个指向复制的 std::vector 数据的指针。
在此示例中,返回指向 std::vector 的指针,但您也可以返回 size 和 data(( 指针,或使用任何其他实现,让您的 numpy 数组以稳定的方式访问底层数据(即保证存在(:
class_<test_wrap>("test_wrap")
.add_property("values", +[](test_wrap& self) -> object {
return wrap(self.pvalues()->data(),self.pvalues()->size());
})
;
对于带有std::vector<double>
的test_wrap(通常 pvalues(( 可能只返回指针而不填充向量(:
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 放入虚拟环境如下 - 如果您可以按照 @max 的建议执行python -c "import numpy; print numpy.get_include()"
,这应该是不必要的:
# virtualenv, pip, path unnecessary if your Python has numpy
virtualenv venv
./venv/bin/pip install -r requirements.txt
export PATH="$(pwd)/venv/bin:$PATH"
玩得开心! :-(
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- 什么时候在C++中返回常量引用是个好主意
- 你能重载对象变量名本身返回的内容吗
- 为什么 Serial.println(<char[]>);返回随机字符?
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 如何获取std::result_of函数的返回类型
- QueryWorkingSet总是返回false
- (C++)分析树以计算返回错误值的简单算术表达式
- 访问者访问变体并返回不同类型时出错
- 如何返回一个类的两个对象相加的结果
- OpenInventor从9.8升级到10.4.2后,GLSL纹理返回零
- lower_bound()返回最后一个元素
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- C++返回 Numpy 数组的 Python 扩展模块
- pybind11 返回 numpy 对象数组
- 通过 Pybind11 返回 numpy 数组
- 如何向armadillo(C++)发送一个numpy数组,并从armadillo返回一个numdy数组
- 如何将numpy nd-array转换为cffi c 数组,然后再次返回
- 如何从 boost::p ython 返回 numpy.array
- 将numpy数组传递给c++函数并返回numpy数组作为输出的最有效方法是什么?