Cython

2013-01-02 10 views
8

私はこの種のコードにコンパイルしようとしている中での2Dリストを宣言する方法:Cython

def my_func(double c, int m): 
    cdef double f[m][m] 

    f = [[c for x in range(m)] for y in range(m)] 
    ... 

提起:

Error compiling Cython file: 
------------------------------------------------------------ 
def grow(double alpha, double beta, double gamma, int m, int s): 
    cdef double f[m][m] 
        ^
------------------------------------------------------------ 
test.pyx:6:22: Not allowed in a constant expression 

た後、私は私がで変数を使用することはできません仮定を場所を指摘し、私は数値で試してみてください。

def my_func(double c, int m): 
    cdef double f[500][500] 

    f = [[c for x in range(500)] for y in range(500)] 
    ... 

が、その後私が手:

Error compiling Cython file: 
------------------------------------------------------------ 
    f = [[beta for x in range(500)] for y in range(500)] 
    ^
------------------------------------------------------------ 
test.pyx:13:6: Assignment to non-lvalue 'f' 

だから、私はどのように宣言し、サイフォンコードで2Dリストを作るのだろうかと思います。 I「はcythonの2Dリスト」

+0

私が宣言を残しておけば、コンパイルされたコードが出てきますので、宣言が間違っていると思います。 – theta

+0

実際にリストのリスト、または2次元C配列が欲しいですか? – delnan

+0

はい、それは書かれているようです。私はこの(さらに2つの)リストの各要素をループする非常に遅いPythonコードを高速化しようとしています。それがどれほど遅いか想像してみてください。 – theta

答えて

5
cdef double f[500][500] 

これは500倍の500のC配列のC配列を宣言されているためにグーグルの文書例のこの種を見つけることができませんでした。つまり、パフォーマンスとキャッシュの利用を助けますが、明らかに重大な制限が加えられます。間接指定を使わないで、500 * 500パックの二重の値(この場合はCythonが何かをファンキーにしない限りスタックに格納されます)です。たぶんあなたはこれが欲しいかもしれませんが、最初に何が意味するのかを知るには十分なCを学ぶべきです。ちなみに、1つの制限は、サイズがコンパイル時定数でなければならないということです(Cバージョンに応じて、C99とC10で許されます)。これは最初のエラーメッセージについてです。

アレイを使用している場合、意味がないので、fの初期化は行われません。 fは既に500x500の二重変数であり、配列全体に割り当てることはできません(後者のエラーメッセージがあなたに伝えようとしているものです)。特に、リストの理解は、完全に吹き飛ばされた「boxed」Pythonオブジェクト(この場合はfloatオブジェクト)を含む、完全に吹き飛ばされたPythonリストオブジェクト(Cythonからも使用できる、以下を参照)を作成します。リストはC配列と互換性がありません。初期化のための項目割り当てを持つネストされたforループを使用してください。最後に、そのような配列は500 * 500 * 8バイトをとり、これはほぼ2 MiBです。いくつかのシステムでは、それはスタック全体よりも大きく、他のすべてのシステムでは、スタックの大部分が悪い考えです。その配列をヒープ割り当てする必要があります。

Pythonリストを使用している場合は、パフォーマンスとメモリの使用量が大幅に改善されないことに注意してください(コードがほとんどそのリストを操作していることを前提とします)。 cdefを省略するか、タイプとしてlistを使用します(objectも機能するはずですが、何も得られないので省略することもできます)。

NumPyアレイは、より速く、メモリ効率が良く、の方が使いやすい場合があります。 NumPyの演算に関して、アルゴリズムのパフォーマンスに重要な部分を実装できる場合は、にまったく使用せずに、必要なスピードアップを得ることができます。

+0

あなたの説明をありがとう。私はCの本を探すべきだと思うし、同じアドバイスはちょうどCythonのドキュメントをブラウズするだけで浮動する。だから私はCの型と操作についてもっと学ぶまで、この例ではリストを使うだけです。 C配列はもっと効率的ですが、Cython関数からPythonコードに戻すことはできませんが、Cythonコード内で使用するだけですか?スピードアップは現在のところ3倍ですが、NumpyとCythonを使って、まずはNumpyの配列を使う代わりに、このサンプルコードのパフォーマンスを向上させることはできません。 – theta

8

Cythonでリスト内包を使用しないでください。彼らは通常のPythonのリストを作成するので、スピードアップはありません。あなたは以下のようCythonで動的割り当てを使用する必要があることをウィキsays、:

from libc.stdlib cimport malloc, free 

def my_func(double c, int m): 
    cdef int x 
    cdef int y 
    cdef double *my_array = <double *>malloc(m * m * sizeof(double)) 

    try: 

     for y in range(m): 
      for x in range(m): 
       #Row major array access 
       my_array[ x + y * m ] = c 

     #do some thing with my_array 

    finally: 
     free(my_array) 

しかし、あなたは、2次元配列のPythonオブジェクトを持っている必要がある場合は、そのNumPyを使用することをお勧めします。

+0

あなたのスニペットをありがとうが、私は 'malloc'とそれに類する言葉を見ると恐れている。私はまだそこにはいませんし、f2pyを使うのは簡単ですが、Cythonを使い始めたかったのです。私が答えたとき、CythonとNumpyの配列で、CythonとPythonのリストの代わりに試してみましょう。ありがとう – theta