Transforming a C++ vector into a Numpy array

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.

  1. %typemap(out) std::vector<double> {
    
  2.     int length = $1.size();
    
  3.     $result = PyArray_FromDims(1, &amp;length, NPY_DOUBLE);
    
  4.     memcpy(PyArray_DATA((PyArrayObject*)$result),&amp;((*(&amp;$1))[0]),sizeof(double)*length);
    
  5. }

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.

  1. %typemap(out) std::vector<float> {
    
  2.     npy_intp length = $1.size();
    
  3.     $result = PyArray_SimpleNew(1, &amp;length, NPY_FLOAT);
    
  4.     memcpy(PyArray_DATA((PyArrayObject*)$result),$1.data(),sizeof(float)*length);
    
  5. }

4 thoughts on “Transforming a C++ vector into a Numpy array

  1. 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.

  2. 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);
    “`

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.