How to Return Numpy.Array from Boost::Python

how to return numpy.array from boost::python?

UPDATE: the library described in my original answer (https://github.com/ndarray/Boost.NumPy) has been integrated directly into Boost.Python as of Boost 1.63, and hence the standalone version is now deprecated. The text below now corresponds to the new, integrated version (only the namespace has changed).

Boost.Python now includes a moderately complete wrapper of the NumPy C-API into a Boost.Python interface. It's pretty low-level, and mostly focused on how to address the more difficult problem of how to pass C++ data to and from NumPy without copying, but here's how you'd do a copied std::vector return with that:

#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);
}

How to create a numpy array of boost::python::object types

You're using the dtype constructor correctly; it's obj that's causing the trouble.

The default construction boost::python::object obj; sets obj as the 'None' Python object. The dtype associated with 'None' is a NPY_DEFAULT array descriptor type. And that maps to a double when creating the numpy array, which explains your output. (That makes sense from a Python perspective - the default numpy array type is a double precision floating point type.)

You can constuct a dtype with an object type (NPY_OBJECT) using

boost::python::numpy::dtype dt = boost::python::numpy::dtype(boost::python::object("O"));

which, in your case, is the fix. I've also taken the liberty of using an anonymous temporary which is how it's done in the Boost documentation. The "O" denotes the object type.

boost python - nullptr while extracting ndarray

That error occurs since you're using the numpy module without first initializing it.

Notice the beginning of the official tutorial:

Initialise the Python runtime, and the numpy module. Failure to call these results in segmentation errors:

namespace np = boost::python::numpy;
int main(int argc, char **argv)
{
Py_Initialize();
np::initialize();

Your code is lacking the call to np::initialize();.

Passing boost::python::numpy::ndarray as (default or not) argument of a boost::python function?

To be able to use numpy first initialise the Python runtime and the numpy module:

Py_Initialize();
np::initialize();

Failure to call these results in segmentation errors.

=======================================================================

For the silly.cpp the workaround is not needed. Here is the implementation:

#include <boost/python.hpp>
#include <boost/python/numpy.hpp>
namespace bp = boost::python;
namespace np = boost::python::numpy;

int f(np::ndarray x, np::ndarray y = np::array(bp::list()) ) {
return (int)(x.shape(0)+y.shape(0));
};

BOOST_PYTHON_MODULE(silly)
{
Py_Initialize();
np::initialize();
bp::def("f", f, ( bp::arg("x"), bp::arg("y") = np::array(bp::list()) ) );
}

And the test results:

>>> import numpy, silly; silly.f(numpy.array([1, 2, 3]), numpy.array([1, 2]))
5
>>> import numpy, silly; silly.f(numpy.array([1, 2, 3]))
3

Passing C structs to python as numpy arrays using boost python

Ok, I've managed to answer my own question. It wasn't straight-forward, but it works now...

#include <numpy/arrayobject.h>

void MyBaseClass::myCallback(const MyRecord& data)
{
object func = get_override("myCallback");
if (func) {
PyArray_Descr* dtype;
PyObject* op = Py_BuildValue("[(s,s),(s,s),(s,s)]", "myInt", "<u4", "myString", "|S4", "myDouble", "<f8");
PyArray_DescrConverter(op, &dtype);
Py_DECREF(op);
PyObject* pya = PyArray_FromString(const_cast<char*>(reinterpret_cast<const char*>(&data)), sizeof(data), dtype, 1, NULL);
// PyObject_Print(pya, stdout, 0);
numeric::array bpa(static_cast<numeric::array>(handle<>(pya)));
func(bpa);
}
}

BOOST_PYTHON_MODULE(example3)
{
import_array()
class_<MyBaseClass>("MyBaseClass")
.def("myCallback", &MyBaseClass::myCallback);
}

Thanks again,

Paul



Related Topics



Leave a reply



Submit