Passing a C++ std::Vector to numpy array in Python

前端 未结 4 748
走了就别回头了
走了就别回头了 2021-02-04 06:13

I am trying a pass a vector of doubles that I generate in my C++ code to a python numpy array. I am looking to do some downstream processing in P

4条回答
  •  心在旅途
    2021-02-04 06:40

    I'm not a cpp-hero ,but wanted to provide my solution with two template functions for 1D and 2D vectors. This is a one liner for usage l8ter and by templating 1D and 2D vectors, the compiler can take the correct version for your vectors shape. Throws a string in case of unregular shape in the case of 2D. The routine copies the data here, but one can easily modify it to take the adress of the first element of the input vector in order to make it just a "representation".

    Usage looks like this:

    // Random data
    vector some_vector_1D(3,1.f); // 3 entries set to 1
    vector< vector > some_vector_2D(3,vector(3,1.f)); // 3 subvectors with 1
    
    // Convert vectors to numpy arrays
    PyObject* np_vec_1D = (PyObject*) vector_to_nparray(some_vector_1D);
    PyObject* np_vec_2D = (PyObject*) vector_to_nparray(some_vector_2D);
    

    You may also change the type of the numpy array by the optional arguments. The template functions are:

    /** Convert a c++ 2D vector into a numpy array
     *
     * @param const vector< vector >& vec : 2D vector data
     * @return PyArrayObject* array : converted numpy array
     *
     * Transforms an arbitrary 2D C++ vector into a numpy array. Throws in case of
     * unregular shape. The array may contain empty columns or something else, as
     * long as it's shape is square.
     *
     * Warning this routine makes a copy of the memory!
     */
    template
    static PyArrayObject* vector_to_nparray(const vector< vector >& vec, int type_num = PyArray_FLOAT){
    
       // rows not empty
       if( !vec.empty() ){
    
          // column not empty
          if( !vec[0].empty() ){
    
            size_t nRows = vec.size();
            size_t nCols = vec[0].size();
            npy_intp dims[2] = {nRows, nCols};
            PyArrayObject* vec_array = (PyArrayObject *) PyArray_SimpleNew(2, dims, type_num);
    
            T *vec_array_pointer = (T*) PyArray_DATA(vec_array);
    
            // copy vector line by line ... maybe could be done at one
            for (size_t iRow=0; iRow < vec.size(); ++iRow){
    
              if( vec[iRow].size() != nCols){
                 Py_DECREF(vec_array); // delete
                 throw(string("Can not convert vector> to np.array, since c++ matrix shape is not uniform."));
              }
    
              copy(vec[iRow].begin(),vec[iRow].end(),vec_array_pointer+iRow*nCols);
            }
    
            return vec_array;
    
         // Empty columns
         } else {
            npy_intp dims[2] = {vec.size(), 0};
            return (PyArrayObject*) PyArray_ZEROS(2, dims, PyArray_FLOAT, 0);
         }
    
    
       // no data at all
       } else {
          npy_intp dims[2] = {0, 0};
          return (PyArrayObject*) PyArray_ZEROS(2, dims, PyArray_FLOAT, 0);
       }
    
    }
    
    
    /** Convert a c++ vector into a numpy array
     *
     * @param const vector& vec : 1D vector data
     * @return PyArrayObject* array : converted numpy array
     *
     * Transforms an arbitrary C++ vector into a numpy array. Throws in case of
     * unregular shape. The array may contain empty columns or something else, as
     * long as it's shape is square.
     *
     * Warning this routine makes a copy of the memory!
     */
    template
    static PyArrayObject* vector_to_nparray(const vector& vec, int type_num = PyArray_FLOAT){
    
       // rows not empty
       if( !vec.empty() ){
    
           size_t nRows = vec.size();
           npy_intp dims[1] = {nRows};
    
           PyArrayObject* vec_array = (PyArrayObject *) PyArray_SimpleNew(1, dims, type_num);
           T *vec_array_pointer = (T*) PyArray_DATA(vec_array);
    
           copy(vec.begin(),vec.end(),vec_array_pointer);
           return vec_array;
    
       // no data at all
       } else {
          npy_intp dims[1] = {0};
          return (PyArrayObject*) PyArray_ZEROS(1, dims, PyArray_FLOAT, 0);
       }
    
    }
    

提交回复
热议问题