python numpy swig

python - plt title position



¿Hay alguna forma de utilizar pythonappend con la nueva función incorporada de SWIG? (1)

Tengo un pequeño proyecto que funciona muy bien con SWIG. En particular, algunas de mis funciones devuelven std::vector s, que se traducen a tuplas en Python. Ahora hago muchos numerics, por lo que solo hago que SWIG los convierta en numpy arrays una vez que se devuelven desde el código de c ++. Para hacer esto, uso algo como lo siguiente en SWIG.

%feature("pythonappend") My::Cool::Namespace::Data() const %{ if isinstance(val, tuple) : val = numpy.array(val) %}

(En realidad, hay varias funciones llamadas Datos, algunas de las cuales devuelven flotantes, por lo que compruebo que val es en realidad una tupla). Esto funciona muy bien.

Pero, también me gustaría usar la bandera -builtin que ahora está disponible. Las llamadas a estas funciones de Datos son raras y en su mayoría interactivas, por lo que su lentitud no es un problema, pero existen otros bucles lentos que se aceleran significativamente con la opción incorporada.

El problema es que cuando uso ese indicador, la función pythonappend se ignora silenciosamente. Ahora, Data simplemente devuelve una tupla nuevamente. ¿Hay alguna manera de que todavía pueda devolver matrices numpy? Intenté usar mapas de tipos, pero se convirtió en un desastre gigante.

Editar:

Borealid ha respondido la pregunta muy bien. Solo para completar, incluyo un par de tipos de mapas relacionados pero sutilmente diferentes que necesito porque vuelvo por referencia constante y uso vectores de vectores (¡no empieces!). Estos son lo suficientemente diferentes como para que no quisiera que nadie más tropezara tratando de descubrir las pequeñas diferencias.

%typemap(out) std::vector<int>& { npy_intp result_size = $1->size(); npy_intp dims[1] = { result_size }; PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_INT); int* dat = (int*) PyArray_DATA(npy_arr); for (size_t i = 0; i < result_size; ++i) { dat[i] = (*$1)[i]; } $result = PyArray_Return(npy_arr); } %typemap(out) std::vector<std::vector<int> >& { npy_intp result_size = $1->size(); npy_intp result_size2 = (result_size>0 ? (*$1)[0].size() : 0); npy_intp dims[2] = { result_size, result_size2 }; PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(2, dims, NPY_INT); int* dat = (int*) PyArray_DATA(npy_arr); for (size_t i = 0; i < result_size; ++i) { for (size_t j = 0; j < result_size2; ++j) { dat[i*result_size2+j] = (*$1)[i][j]; } } $result = PyArray_Return(npy_arr); }

Editar 2:

Aunque no es exactamente lo que estaba buscando, problemas similares también pueden ser resueltos usando el enfoque de @ MONK ( explicado aquí ).


Estoy de acuerdo con usted en que usar el typemap se typemap un poco desordenado, pero es la forma correcta de llevar a cabo esta tarea. También tiene razón en que la documentación de SWIG no dice directamente que %pythonappend es incompatible con -builtin , pero está fuertemente implícito: %pythonappend agrega a la clase de proxy de Python , y la clase de proxy de Python no existe en absoluto junto con el -builtin bandera.

Antes, lo que hacían era hacer que SWIG convirtiera los objetos de C ++ std::vector en tuplas de Python, y luego pasar esas tuplas de nuevo a numpy , donde se volvían a convertir.

Lo que realmente quieres hacer es convertirlos una vez, en el nivel C.

Aquí hay un código que convertirá todos los objetos std::vector<int> en matrices de enteros NumPy:

%{ #include "numpy/arrayobject.h" %} %init %{ import_array(); %} %typemap(out) std::vector<int> { npy_intp result_size = $1.size(); npy_intp dims[1] = { result_size }; PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_INT); int* dat = (int*) PyArray_DATA(npy_arr); for (size_t i = 0; i < result_size; ++i) { dat[i] = $1[i]; } $result = PyArray_Return(npy_arr); }

Esto usa las funciones numpy de nivel C para construir y devolver una matriz. En orden, esto:

  • Asegura que el archivo arrayobject.h de NumPy esté incluido en el archivo de salida de C ++
  • Hace que se import_array a import_array cuando se carga el módulo de Python (de lo contrario, todos los métodos de NumPy segfault)
  • Mapas de cualquier devolución de std::vector<int> en matrices NumPy con un typemap

Este código debe colocarse antes de que %import los encabezados que contienen las funciones que devuelven std::vector<int> . Aparte de esa restricción, es totalmente independiente, por lo que no debería agregar demasiado "desorden" subjetivo a su base de código.

Si necesita otros tipos de vectores, puede simplemente cambiar NPY_INT y todos los bits int* e int , de lo contrario, duplicar la función anterior.