This question was asked on the Scipy mailing-list last year (well, one week ago). Nathan Bell proposed a skeleton that I used to create an out typemap for SWIG.
%typemap(out) std::vector<double> {
int length = $1.size();
$result = PyArray_FromDims(1, &length, NPY_DOUBLE);
memcpy(PyArray_DATA((PyArrayObject*)$result),&((*(&$1))[0]),sizeof(double)*length);
}
This typemap uses obviously Numpy, so don’t forget to initialize the module and to import it. Then there is a strange instruction in memcpy. &((*(&$1))[0]) takes the address of the array of the vector, but as it is wrapped by SWIG, one has to get to the std::vector by dereferencing the SWIG wrapper. Then one can get the first element in the vector and take the address.
Edit on May 2017: This is my most recent trials with this.
%typemap(out) std::vector<float> {
npy_intp length = $1.size();
$result = PyArray_SimpleNew(1, &length, NPY_FLOAT);
memcpy(PyArray_DATA((PyArrayObject*)$result),$1.data(),sizeof(float)*length);
}
Hello,
I tried to use your method (without really understanding it) in order to transform an std vector (that has been created on the c++ side) directly as a numpy ndarray.
On the python side, I hade hoped for something like this:
import MyC++Module
Thing = MyC++Module.Thing()
a = Thing.vec
On the C++ side, there would be a class Thing that has a public member vec of type
std::vector.
However, your code did not result in Thing.vec beging a numpy array; instead, it was an object of type
with which I could do nothing on the python side.
Is this the expected outcome?
When I use
%include "std_vector.i"
namespace std {
%template(vectord) vector;
};
instead, The object returned is of type
Which is still cumbersome; I can access the contents, it is iterable, but it is not a fast numpy ndarray.
Hi,
Can you provide a real working code?
Matt
Thanks, I found this helpful. FWIW, you can parameterise with SWIG macros:
“`
%define %numpy_vector_typemaps(DATA_TYPE, DATA_TYPECODE)
%typemap(out) std::vector {
npy_intp length = $1.size();
$result = PyArray_SimpleNew(1, &length, DATA_TYPECODE);
size_t ulength = static_cast(length);
memcpy(PyArray_DATA((PyArrayObject*)$result),$1.data(), sizeof(DATA_TYPE)*ulength);
}
%typemap(out) std::vector* {
npy_intp length = $1->size();
$result = PyArray_SimpleNew(1, &length, DATA_TYPECODE);
size_t ulength = static_cast(length);
memcpy(PyArray_DATA((PyArrayObject*)$result),$1->data(), sizeof(DATA_TYPE)*ulength);
}
%enddef
%numpy_vector_typemaps(double, NPY_DOUBLE)
%numpy_vector_typemaps(int, NPY_INT)
%numpy_vector_typemaps(float, NPY_FLOAT)
“`
You can even get the sizeof done at compile time more automatically, but I found this was making me uneasy with pointer types so I haven’t used it.
“`
constexpr size_t sizeof_member = sizeof(std::remove_reference::type::value_type);
“`
I agree that there are lots of things that could be done better with C++11, and thanks a lot for offering these enhancements!