2012-02-14 3 views
75

私はSWIGで美しく動作する小さなプロジェクトを持っています。特に、私の関数のいくつかはstd::vectorを返します。これはPythonのタプルに変換されます。さて、私は多くの数値を扱うので、SWIGはこれらをC++コードから返された後にnumpy配列に変換します。これを行うために、私はSWIGで次のようなものを使用します。SWIGの新しい組み込み機能でpythonappendを使う方法はありますか?

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

(実際には、浮動小数点数を返すそのうちのいくつかは、データという名前のいくつかの機能は、私はvalが実際にタプルであることを確認してください理由である、があります。)これはただ美しく動作します。

でも、現在利用可能な-builtinフラグを使用したいと思います。これらのデータ関数への呼び出しは稀で、ほとんどインタラクティブであるため、遅さは問題ではありませんが、組み込みオプションで大幅に高速化する他の低速ループもあります。

問題は、私がそのフラグを使用すると、pythonappend機能が静かに無視されることです。さて、データはタプルをもう一度返します。私はまだnumpy配列を返すことができる方法はありますか?私はタイプマップを使ってみたが、それは巨大な混乱に変わった。

編集:

Borealidは非常にうまく質問に答えました。完全性のために、私はconst参照によって返され、私はベクトルのベクトルを使用するので(開始しないでください!)、私が必要とする微妙に異なるタイプマップをいくつか含んでいます。これらは十分に異なっているので、他の誰かが微妙な違いを見つけようとしているのではありません。

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

編集2:

なく、かなり私が探していたものを、同様の問題がまたMONKのアプローチ(explained here)@使用して解決することができるけれども。

+4

typemapを書かずにCサイドでやっていないと、-builtinがpythonappendが普通に置かれているコードを取り除いてしまっているとは思いません。あなたはビルドインの方がはるかに高速です(つまり、プロファイリングで使用するように誘導しましたか?)私は2つのモジュールを使用するように誘惑されます。 – Flexo

+0

'-builtin'がpythonappendを無視するという警告はありません。私はnumpy配列に 'std :: vector'を型付けすることに挑戦するつもりはありません。私はプロフィールを作成し、インターフェイスで最も迷惑なループを大幅にスピードアップしました(休憩を取るのに十分な長さではなく、頻繁に待つのは長すぎます)。しかし、私はまた、私はこのループを私のC++コードに移すことができることを認識しました。だから私は行くつもりです。それでも、あなたの「2つのモジュール」の提案は面白く、他の場合には有用かもしれません。 – Mike

+0

-WallでSWIGに電話しましたか?私はその場合警告すると仮定した。 – Flexo

答えて

6

typemapを使用することはちょっと面倒ですが、この作業を行うのは正しい方法です。また、SWIGのマニュアルではとの互換性がないと直接的には言及していませんが、%pythonappendがPythonプロキシクラスに追加され、Pythonプロキシクラスが-builtinと一緒に存在しないことを強く暗示していますフラグ。

前に、SWIGがC++ std::vectorオブジェクトをPythonタプルに変換してから、それらのタプルをnumpyに戻してから再び変換したのです。

あなたが本当にやりたいことは、Cレベルで1回変換することです。ここ

はnumpyの整数アレイに全てstd::vector<int>オブジェクトを向けるだろういくつかのコードは次のとおり

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

これは、配列を作成し、返すためにCレベルのnumpyの関数を使用します。ためには、それ:

  • はPythonモジュールがロードされたときに
  • 原因import_arrayがどの
  • 地図(そうでない場合は、すべてのnumpyの方法は、セグメンテーションフォールトします)と呼ばれるようにnumpyののarrayobject.hファイルは、C++出力ファイルに含まれている保証しますtypemap

このコードでnumpyのアレイにstd::vector<int>の返品はお%importヘッダがWH前を配置する必要がありますこれらは、std::vector<int>を返す関数を含みます。その制限以外にも、それは完全に自己完結型なので、コードベースにあまりにも多くの主観的な「混乱」を加えるべきではありません。

他のベクタータイプが必要な場合は、NPY_INTとすべてint*intビットを変更することができます。そうでない場合は、上記の関数を複製します。

+0

素晴らしい!私はあなたがtypemapに持っているすべての要素を持っていましたが、私はそれらを適切にまとめませんでした。正式に私のプロジェクトでこの作業をしているわけではありませんが、もっと簡単なモジュールを構築することでかなり徹底的なテストを行ってきました。どうもありがとう! – Mike

関連する問題