77 votes

Existe-t-il un moyen d'utiliser pythonappend avec la nouvelle fonctionnalité intégrée de SWIG?

J'ai un petit projet qui fonctionne à merveille avec SWIG. En particulier, certains de mes fonctions renvoient std::vectors, qui se traduit pour les tuples en Python. Maintenant, je fais beaucoup de nombres, je viens donc de SWIG convertir ces tableaux numpy une fois qu'ils sont retournés à partir du code c++. Pour ce faire, j'utilise quelque chose comme ce qui suit dans GORGÉE.

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

(En fait, il existe plusieurs fonctions de Données nommée, certaines de retour de flotte, c'est pourquoi j'ai vérifier qu' val est en fait un n-uplet.) Cela fonctionne à merveille.

Mais, j'aimerais aussi utiliser l' -builtin drapeau qui est maintenant disponible. Les appels à ces fonctions de Données sont rares et la plupart du temps interactive, de sorte que leur lenteur n'est pas un problème, mais il y a d'autres lente boucles d'accélérer de façon significative avec le groupe builtin option.

Le problème est que lorsque j'utilise le drapeau, la pythonappend fonction est ignorée en mode silencieux. Maintenant, les Données retourne un tuple de nouveau. Est-il possible que je pourrais toujours retourner les tableaux numpy? J'ai essayé d'utiliser typemaps, mais elle s'est transformée en un gigantesque gâchis.

Edit:

Borealid a répondu à la question très bien. Juste pour être complet, j'ai inclus un couple connexes, mais subtilement différentes typemaps que j'ai besoin parce que j'retour par référence const et j'utilise des vecteurs de vecteurs (ne commencez pas!). Ces sont suffisamment différentes pour que je ne veux pas que quelqu'un d'autre titubant à essayer de comprendre les différences mineures.

%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);
}

Edit 2:

Bien que pas tout à fait ce que je cherchais, des problèmes similaires peuvent également être résolus à l'aide de @MOINE de l'approche (expliqué ici).

8voto

Borealid Points 35075

Je suis d'accord avec vous que l'utilisation d' typemap devient un peu bordélique, mais c'est la bonne façon d'accomplir cette tâche. Vous êtes également à bon droit que la GORGÉE de documentation ne sont pas directement dire qu' %pythonappend est incompatible avec l' -builtin, mais il est fortement implicite: %pythonappend s'ajoute à la Python classe proxy, et le Python de la classe proxy, il n'existe pas en conjonction avec l' -builtin drapeau.

Avant, ce que vous avez à faire, c'était d'avoir RASADE de convertir le C++ std::vector objets en Python tuples, et en passant ensuite les tuples de retour vers numpy - où ils ont été convertis de nouveau.

Vraiment ce que vous voulez faire est de les convertir en une seule fois, au C niveau.

Voici un code qui transformera std::vector<int> objets en NumPy entier tableaux:

%{
#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);
}

Il utilise le C-niveau numpy fonctions de construire et de retourner un tableau. Dans l'ordre, c':

  • Assure NumPy l' arrayobject.h le fichier est inclus dans le C++ fichier de sortie
  • Provoque import_array d'être appelé lorsque le module Python est chargé (sinon, tous les NumPy méthodes d'erreur de segmentation)
  • Les cartes de tous les retours d' std::vector<int> dans les tableaux NumPy avec un typemap

Ce code doit être placé avant vous %import les en-têtes qui contiennent les fonctions retournant std::vector<int>. Autre que cette restriction, il est entièrement autonome, il ne doit pas ajouter trop subjectif "gâchis" de votre base de code.

Si vous avez besoin d'autres types de vecteurs, il vous suffit de modifier l' NPY_INT et tous les int* et int bits, sinon la duplication de la fonction ci-dessus.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X