1

計算速度を上げるために、Python スクリプトのいくつかの関数を c に移動しようとしています。入力として複数の 1 次元配列を持ち、numpy.i タイプマップを使用して double を返す関数に対して、これを成功させました。

ただし、c に移動したい別の関数は、入力として 3 次元の numpy 配列を取り、double の 1 次元配列を返します。以前の関数と同じアプローチを試みましたが、これまでのところ、関数が呼び出されたときにのみセグメンテーション違反が発生しました。

これは私がしたことです:

c の関数は次のように定義されます (3 次元配列は「WF」、返される配列は「料金」、「pos_x」、「pos_y、および pos_z」は 1 次元入力配列です):

void GetCharges(double* pos_x, double* pos_y, double* pos_z, double* charges, double*** WF, double resolution, double shape, int number){
...
}

「WF」のエントリは、コードでは として扱われますWF[i][j][k]

SWIG インターフェイス ファイルは次のようになります。

/* file: GetCharges.i */
%module GetCharges
%{
#define SWIG_FILE_WITH_INIT
#include "GetCharges.h"
%}

%include "numpy.i"

%init %{
import_array();
%}


%apply (double* IN_ARRAY1, int DIM1) {(double* pos_x, int number1),(double* pos_y, int number2),(double* pos_z, int number3)}
%apply (double* IN_ARRAY3, int DIM1, int DIM2, int DIM3) {(double*** WF, int dim1, int dim2, int dim3)}
%apply (double* INPLACE_ARRAY1, int DIM1) {(double* charges, int number4)}

%rename (GetCharges) GetCharges_temp;
%ignore GetCharges;
%inline %{

void GetCharges_temp(double* pos_x, int number1, double* pos_y, int number2, double* pos_z, int number3, double *charges, int number4, double*** WF, int dim1, int dim2, int dim3, double resolution, double  shape)
{
GetCharges(pos_x, pos_y, pos_z, charges, WF, resolution, shape, number1);
}
%}

%include "GetCharges.h"

ご覧のとおり、返される値の配列に INPLACE_ARRAY を使用しようとしました。

私はcに慣れていないので、エラーは非常に単純でばかげているかもしれません。

どんな助けでも大歓迎です。

4

1 に答える 1

2

マッピングを適用する方法を確認するには、numpy.i を参照してください。ここで、使用する typemap は次のように定義されます。

(DATA_TYPE* IN_ARRAY3, DIM_TYPE DIM1, DIM_TYPE DIM2, DIM_TYPE DIM3)

しかし、あなたはそれを次のように適用しています

%apply (double* IN_ARRAY3, int DIM1, int DIM2, int DIM3) {(double*** WF, int dim1, int dim2, int dim3)}

したがって、 を のdouble*上に置きますdouble***。C はこの引数を受け入れますが、メモリにアクセスするときにプログラムの segfault が発生します。

内部の 3 次元メモリを型の単一のベクトルとして定義するdouble*か、それをコピーする (遅い) か、適切なメモリ アドレスを提供する (速い) ことによって正しいマッピングを行う追加のラッパー関数が必要です。

既に一時的な関数を追加しているため、それを使用して適切なメモリ レイアウトを簡単に作成できますがGetCharges(...,double*** WF)、関数定義を次のように変更する必要があります。

%apply (double* IN_ARRAY3, int DIM1, int DIM2, int DIM3) {(double* WF, int dim1, int dim2, int dim3)}
%apply (double* INPLACE_ARRAY1, int DIM1) {(double* charges, int number4)}

...

void GetCharges_temp(double* pos_x, int number1, double* pos_y, int number2, double* pos_z, int number3, double *charges, int number4, double* WF, int dim1, int dim2, int dim3, double resolution, double  shape)

編集

あなたのコメントに答えるために、ここにさらにいくつかの行を追加します。すみません、それについて。

本当の問題は、WFinの要素にどのようにアクセスするのCかということです。double*全長 の が得られますDIM1*DIM2*DIM3。Numpy では、 経由で要素にアクセスしますWF[i][j][k]。同じことを行うには、この要素が (C 連続)行優先であり、(Fortran 連続) 列優先である場合Cに、この要素の正しいオフセットを計算する必要があります。にアクセスすると、numpy で順序を確認できます。また、numpy.ascontiguousarrayまたはnumpy.requireのいずれかを使用して、numpy で行優先順序を強制することもできます。WF[k+DIM3*(j +DIM2*i)]WFWF[i+DIM1*(j +DIM2*k)]WFWF.flagsCWF

したがって、基本的に、任意の次元のすべての numpy 配列は dim のベクトルであり、正しいオフセットを計算することによりn1*...*nd、同じ方法でアクセスされます。C

行優先の格納された要素では、高速インデックスは最後のインデックス (こちらk) ですが、列優先の高速インデックスは最初のインデックス (こちらi) です。C最大速度を上げるには、高速インデックスを最も内側のループに配置する必要があります。

于 2013-09-30T08:50:27.807 に答える