numpy array C api

Tengo una función de C ++ que devuelve un std :: vector y quiero usarla en python, así que estoy usando la api C numpy:

static PyObject * py_integrate(PyObject *self, PyObject *args){ ... std::vector integral; cpp_function(integral); // This changes integral npy_intp size = {integral.size()}; PyObject *out = PyArray_SimpleNewFromData(1, &size, NPY_DOUBLE, &(integral[0])); return out; } 

Así es como lo llamo desde Python:

 import matplotlib.pyplot as plt a = py_integrate(parameters) print a fig = plt.figure() ax = fig.add_subplot(111) ax.plot(a) print a 

Lo que sucede es: la primera impresión está bien, los valores son correctos. Pero cuando planeo a no lo son; En la segunda impresión veo valores muy extraños como 1E-308 1E-308 ... o 0 0 0 ... como una memoria sin inicializar. No entiendo por qué la primera impresión está bien.

Solución parcial (no funciona):

 static void DeleteVector(void *ptr) { std::cout << "Delete" << std::endl; vector * v = static_cast<std::vector * >(ptr); delete v; return; } static PyObject * cppfunction(PyObject *self, PyObject *args) { std::vector *vector = new std::vector(); vector->push_back(1.); PyObject *py_integral = PyCObject_FromVoidPtr(vector, DeleteVector); npy_intp size = {vector->size()}; PyArrayObject *out; ((PyArrayObject*) out)->base = py_integral; return (PyObject*)(out); } 

Su objeto std::vector parece ser local para esa función. PyArray_SimpleNewFromData no hace una copia de los datos que usted pasa. Solo mantiene un puntero. Entonces, una vez que la función py_integrate vuelve, el vector se desasigna. La impresión funciona la primera vez porque todavía no se ha escrito nada en la memoria liberada, pero cuando llega a la siguiente impresión, otra cosa ha utilizado esa memoria, lo que hace que los valores sean diferentes.

Debe crear una matriz NumPy que posea su propio espacio de almacenamiento y luego copiar los datos en ella.

Alternativamente, asigne su vector en el montón. A continuación, guarde un puntero a él en un objeto CO . Proporcionar un destructor que elimina el vector. Luego, eche un vistazo al tipo PyArrayObject de nivel C. Tiene un miembro de PyObject * llamado base . Guarde su objeto allí. Luego, cuando se recolecta la matriz NumPy, el recuento de referencia en este objeto base se reducirá, y suponiendo que no haya tomado una copia en otro lugar, su vector se eliminará gracias al destructor que proporcionó.

Fijador superior

Olvidaste realmente crear el PyArray. Prueba esto:

(No DeleteVector , así que solo espero que esté bien)

 std::vector *vector = new std::vector(); vector->push_back(1.); PyObject *py_integral = PyCObject_FromVoidPtr(vector, DeleteVector); npy_intp size = {vector->size()}; PyObject *out = PyArray_SimpleNewFromData(1, &size, NPY_DOUBLE, &((*vector)[0])); ((PyArrayObject*) out)->base = py_integral; return out; 

Nota: no soy un progtwigdor de C ++, por lo que solo puedo asumir que &((*vector)[0]) funciona como se pretende con un puntero a un vector. Sé que el vector reasigna su área de almacenamiento si lo crece, así que no aumente su tamaño después de obtener ese puntero o ya no será válido.

Necesitará hacer una copia del vector, ya que el vector quedará fuera del scope y la memoria ya no se podrá utilizar para cuando lo necesite en Python (como lo indica kwatford).

Una forma de hacer la matriz Numpy que necesita (copiando los datos) es:

 PyObject *out = nullptr; std::vector *vector = new std::vector(); vector->push_back(1.); npy_intp size = {vector.size()}; out = PyArray_SimpleNew(1, &size, NPY_DOUBLE); memcpy(PyArray_DATA((PyArrayObject *) out), vector.data(), vector.size());