インターリーブされた複素数 API を使用するように MEX ファイルをアップグレード
このトピックでは、インターリーブされた複素数 API を使用するように MEX ファイルをアップグレードする方法を説明します。-R2017b
オプションを指定して mex
コマンドを呼び出すと、引き続き実数/虚数分離型複素数 API を使用することができます。ただし、このオプションの使用の詳細については、インターリーブされた複素数 API を使用するために MEX ファイルをアップグレードする必要があるかを参照してください。
メモ
mex
コマンドで -compatibleArrayDims
オプションを使用して MEX ファイルをビルドする場合、まず 64 ビット API を使用するようにソース コードを更新しなければなりません。詳細については、64 ビット API を使用するように MEX ファイルをアップグレードを参照してください。
MEX ソース コードを更新するには、次のチェックリストを使用します。
コードで、
pr
およびpi
ポインターの使用法と、関数mxGetPr
/mxGetPi
および関数mxGetData
/mxGetImagData
によって返されるポインターを確認してください。インターリーブされた複素数 API には、1 つのポインター (pa
) があります。これはmxGetDoubles
およびその他の型付きデータ関数によって返される値です。データを読み取る前に、入力配列の実数/複素数をチェックすることが重要です。複素配列でmxGetPr
およびmxGetData
を呼び出した場合、インターリーブされた複素数 API の結果は実数/虚数分離型複素数 API と異なります。編集する前にコードを準備します。
コードを変更する前に、MEX 関数が
-R2017b
API で動作することを確認します。少なくとも想定される入出力のリストを作成するか、完全なテスト スイートを作成します。これらのテストを使用して、結果を更新されたソース コードと比較します。結果は両者で一致しなければなりません。すべてのソース ファイル、バイナリ ファイル、テスト ファイルのバックアップを取ります。
次の条件を確認することによって、既存のコードを繰り返しリファクタリングします。
変更のたびにインターリーブされた複素数 API を使用してコンパイルします。
myMexFile.c
をビルドするには、以下を入力します。mex -R2018a myMexFile.c
myMexFile.F
をビルドするには、以下を入力します。mex -R2018a myMexFile.F
エラーと警告を解決します。
リファクタリングの実施ごとにテストします。
インターリーブされた複素数 API でコンパイル済みの MEX 関数を実行して、元のバイナリの結果と比較します。差異やエラーがある場合は、デバッガーを使用して原因を調べます。デバッガー機能の詳細については、コンパイラのドキュメンテーションを参照してください。
mxIsComplex
を使用して配列の実数/複素数を確認
配列に複素数要素があるかどうかを判定するために関数 mxGetPi
を呼び出すコードの場合、代わりに関数 mxIsComplex
を使用してください。この関数は -R2017b
API と -R2018a
API の両方でビルド可能です。コード内の次のパターンを検索します。
C ソース コードの置換 | 次に置き換えます。 |
---|---|
mxArray *pa; ... if (mxGetPi(pa)) { /* process complex array */ } | mxArray *pa; ... if (mxIsComplex(pa)) { /* process complex array */ } |
double *ptr; ptr = mxGetPi(pa); if (ptr != NULL) { /* process complex array */ } |
両方の複素数表現をサポートするために MX_HAS_INTERLEAVED_COMPLEX
を追加
-R2017b
API と -R2018a
API の両方でビルド可能なコードを作成するには、MX_HAS_INTERLEAVED_COMPLEX
マクロを追加します。-R2018a
オプションを使用して MEX ファイルをビルドすると、このマクロは true
を返します。
次のコードを #if MX_HAS_INTERLEAVED_COMPLEX
ステートメントでラップすると、このコードが -R2017b
または -R2018a
mex
オプションのどちらかで確実にビルド可能になります。しかし、この例では、-R2018a
を使用してビルドした場合に実行するコードがありません。
C ソース コードの置換 | 次に置き換えます。 |
---|---|
static void analyze_double(const mxArray *array_ptr) { mwSize total_num_of_elements, index; double *pr, *pi; total_num_of_elements = mxGetNumberOfElements(array_ptr); pr = mxGetPr(array_ptr); pi = mxGetPi(array_ptr); for (index=0; index<total_num_of_elements; index++) { if (mxIsComplex(array_ptr)) { mexPrintf("%g + %gi\n", *pr++, *pi++); } else { mexPrintf("%g\n", *pr++); } } } | static void analyze_double(const mxArray *array_ptr) { mwSize total_num_of_elements, index; total_num_of_elements = mxGetNumberOfElements(array_ptr); #if MX_HAS_INTERLEAVED_COMPLEX /* interleaved complex API processing */ mxComplexDouble *pc; mxDouble *p; if (mxIsComplex(array_ptr)) { pc = mxGetComplexDoubles(array_ptr); for (index=0; index<total_num_of_elements; index++) { mexPrintf(" = %g + %gi\n",(*pc).real,(*pc).imag); pc++; } } else { p = mxGetDoubles(array_ptr); for (index=0; index<total_num_of_elements; index++) { mexPrintf(" = %g\n", *p++); } } #else /* separate complex API processing */ double *pr, *pi; pr = mxGetPr(array_ptr); pi = mxGetPi(array_ptr); for (index=0; index<total_num_of_elements; index++) { if (mxIsComplex(array_ptr)) { mexPrintf("%g + %gi\n", *pr++, *pi++); } else { mexPrintf("%g\n", *pr++); } } #endif } |
Fortran ソース コードの置換 | 次に置き換えます。 |
---|---|
mwPointer prhs(*), pr pr = mxGetPr(prhs(1)) | mwPointer prhs(*), pr #if MX_HAS_INTERLEAVED_COMPLEX pr = mxGetDoubles(prhs(1)) #else pr = mxGetPr(prhs(1)) #endif |
型付きのデータ アクセス関数の使用
関数 mxGetData
および mxGetImagData
を使用するには、入力 mxArray
の型を検証し、正しい型へのポインター出力を手動でキャストしなければなりません。型付きのデータ アクセス関数は、配列の型を検証し、正しいポインター型を返します。関数 mxGetInt16s
および mxGetComplexInt16s
を次のコードで使用して配列 int16
を処理する場合、対応する C の short int
型を記憶する必要はありません。
C ソース コードの置換 | 次に置き換えます。 |
---|---|
static void analyze_int16(const mxArray *array_ptr) { short int *pr, *pi; pr = (short int *)mxGetData(array_ptr); pi = (short int *)mxGetImagData(array_ptr); if (mxIsComplex(array_ptr)) { /* process complex data *pr,*pi */ } else { /* process real data *pr */ } } | static void analyze_int16(const mxArray *array_ptr) { mxComplexInt16 *pc; mxInt16 *p; if(mxIsComplex(array_ptr)) { pc = mxGetComplexInt16s(array_ptr); /* process complex data (*pc).real,(*pc).imag */ } } else { p = mxGetInt16s(array_ptr); /* process real data *p */ } } } |
複素 mxArrays
の処理
次の例は、MATLAB® が 1 つの配列変数を使用してどのように複素配列を表すかを示します。
複素数 C mxArrays
次の複素 mxArray
変数があり、x
と y
の実数と虚数を追加して配列 z
を作成するとします。配列 x
と配列 y
は同じサイズです。
mxArray * x, y, z;
配列 x
に 2 つのポインター xr
と xi
を作成する代わりに、mxComplexDouble
型のポインター xc
を 1 つ作成します。要素 xc[i]
の実数部と虚数部にアクセスするには、xc[i].real
と xc[i].imag
を使用します。
C ソース コードの置換 | 次に置き換えます。 |
---|---|
double *xr, *xi, *yr, *yi, *zr, *zi; /* get pointers to the real and imaginary parts of the arrays */ xr = mxGetPr(x); xi = mxGetPi(x); yr = mxGetPr(y); yi = mxGetPi(y); zr = mxGetPr(z); zi = mxGetPi(z); ... /* perform addition on element i */ zr[i] = xr[i] + yr[i]; zi[i] = xi[i] + yi[i]; | /* get pointers to the complex arrays */ mxComplexDouble * xc = mxGetComplexDoubles(x); mxComplexDouble * yc = mxGetComplexDoubles(y); mxComplexDouble * zc = mxGetComplexDoubles(z); ... /* perform addition on element i */ zc[i].real = xc[i].real + yc[i].real; zc[i].imag = xc[i].imag + yc[i].imag; |
次のコードは、mxArray
を出力引数にコピーします。このコードは、複素配列のテストとコピーの方法を示します。
C ソース コードの置換 | 次に置き換えます。 |
---|---|
mxGetPr(plhs[0])[0] = mxGetPr(prhs[0])[index]; if (mxIsComplex(prhs[0])) { mxGetPi(plhs[0])[0] = mxGetPi(prhs[0])[index]; } | if (mxIsComplex(prhs[0])) { mxGetComplexDoubles(plhs[0])[0] = mxGetComplexDoubles(prhs[0])[index]; } else { mxGetDoubles(plhs[0])[0] = mxGetDoubles(prhs[0])[index]; } |
複素数 Fortran mxArrays
2 つの double 型複素数の mxArrays
があり、次のように定義された入力引数 x
と y
を使用してそれらを Fortran 関数に渡すとします。
complex*16 x(*), y(*)
各 mxArray
の実数部と虚数部を個別に変換するのではなく、関数 mxGetComplexDoubles
を使用します。
Fortran ソース コードの置換 | 次に置き換えます。 |
---|---|
mwPointer mxGetPr, mxGetPi C Copy the data into native COMPLEX Fortran arrays. call mxCopyPtrToComplex16( + mxGetPr(prhs(1)), + mxGetPi(prhs(1)),x,nx) call mxCopyPtrToComplex16( + mxGetPr(prhs(2)), + mxGetPi(prhs(2)),y,ny) | mwPointer mxGetComplexDoubles integer*4 status integer*4 mxCopyPtrToComplex16, mxCopyComplex16ToPtr C Copy the data into native COMPLEX Fortran arrays. status = + mxCopyPtrToComplex16(mxGetComplexDoubles(prhs(1)),x,nx) C Test status for error conditions status = + mxCopyPtrToComplex16(mxGetComplexDoubles(prhs(2)),y,ny) C Test status for error conditions |
mxArray
の実数/複素数の維持
次の C コード スニペットは、実数で double の入力配列 prhs[0]
を複素数配列に変換する方法を示しています。次のコードでは、配列の虚数部を連続する数値で埋めるために使用される変数を設定します。
// code to check number of arguments and expected types mwSize rows = mxGetM(prhs[0]); mwSize cols = mxGetN(prhs[0]); mwSize sz = mxGetElementSize(prhs[0]);
次のコードは、mxMakeArrayComplex
を使用して、実数で double の入力配列をインターリーブされた複素数 mxArray
に変換する方法を示しています。他の例については、mxMakeArrayComplex (C)
を参照してください。
C ソース コードの置換 | 次に置き換えます。 |
---|---|
plhs[0] = mxDuplicateArray(prhs[0]); mxDouble *dc = (mxDouble*)mxMalloc(rows*cols*sz); mxSetImagData(plhs[0], dc); for (int i = 0 ; i < rows*cols ; i++) { dc[i] = i+1; } | plhs[0] = mxDuplicateArray(prhs[0]); if (mxMakeArrayComplex(plhs[0])) { mxComplexDouble *dt = mxGetComplexDoubles(plhs[0]); for (int i = 0 ; i < rows*cols ; i++) { dt[i].imag = i+1; } } |
実数/虚数分離型複素関数の置換
次の関数はインターリーブされた複素数 API にありません。複素数データを処理する場合は、インターリーブされた複素関数に置き換えなければなりません。
mxGetPi
mxSetPi
mxGetImagData
mxSetImagData
mxGetPr
および mxGetPi
への呼び出しを、mxGetComplexDoubles
への呼び出しに置き換えることができます。この関数では、配列に mxComplexDouble
型の要素が含まれることが検証されます。同様に、mxSetPr
と mxSetPi
は mxSetComplexDoubles
に置き換わります。
関数 mxGetData
および mxGetImagData
は、配列の型をチェックしません。代わりに、ユーザーが戻り値を、入力によって指定される型と一致するポインター型にキャストしなければなりません。mxGetData
および mxGetImagData
への呼び出しを、mxGetComplexInt64s
など、単一の適切な型付きデータ アクセス関数に置き換えてください。
C ソース コードの置換 | 次に置き換えます。 |
---|---|
mxArray *pa; mwSize numElements; int64_T *pr, *pi; pr = (int64_T *)mxGetData(pa); pi = (int64_T *)mxGetImagData(pa); numElements = mxGetNumberOfElements(pa); | mxArray *pa; mwSize numElements; mxComplexInt64 *pc; pc = mxGetComplexInt64s(pa); numElements = mxGetNumberOfElements(pa); |
mxGetElementSize
を使用して配列のデータ サイズを計算
-R2018a
API では、関数 mxGetElementSize (C)
は、データ型 T
の複素 mxArray
に対して sizeof(std::complex<T>)
を返します。この値は、-R2017b
API の関数によって返される値の 2 倍です。同様に、-R2018a
API の mxGetElementSize (Fortran)
によって返される値は、-R2017b
API の関数によって返される値の 2 倍となります。
廃止予定関数の置き換えの検討
次の関数は -R2017b
API と -R2018a
API の両方にあります。これらの関数を型付きデータ アクセス関数で置き換える必要はありませんが、型付きデータ関数は型チェックを提供します。また、mxGetPr
を使用する場合に、複素配列処理に mxGetPi
を選択するおそれがあります。このコード パターンは、-R2018a
MEX 関数を作成する際にエラーになります。
mxGetPr
mxSetPr
mxGetData (C)
とmxGetData (Fortran)
- 数値配列の場合mxSetData (C)
とmxSetData (Fortran)
- 数値配列の場合
mxGetPr
への呼び出しを mxGetDoubles
への呼び出しに置き換えることができます。この関数では、配列に mxDouble
型の要素が含まれることが検証されます。同様に、mxSetDoubles
は mxSetPr
を置き換えます。関数 mxGetData
および mxSetData
への呼び出しを置き換えるには、mxGetInt64s
や mxSetInt64s
などの適切な型付きデータ アクセス関数を選択してください。
C ソース コードの置換 | 次に置き換えます。 |
---|---|
double *y; /* create a pointer y to input matrix */ y = mxGetPr(prhs[1]); | mxDouble *p; p = mxGetDoubles(prhs[1]); |
Fortran ソース コードの置換 | 次に置き換えます。 |
---|---|
mwPointer pr mwPointer mxGetPr C Create a pointer to input matrix pr = mxGetPr(prhs(1)) | mwPointer pr mwPointer mxGetDoubles pr = mxGetDoubles(prhs(1)) |
MEX ヘルプ ファイルへのビルド情報の追加
ビルド情報が含まれるヘルプ ファイル (MEX 関数でのヘルプ ファイルの使用で説明) を作成することを検討してください。たとえば、以下のテキストを含むファイル displayTypesafeNumeric.m
を作成します。
% displayTypesafeNumeric.m Help file for displayTypesafeNumeric C MEX function % % Use the following command to build this MEX file: % mex -R2018a displayTypesafeNumeric.c
MATLAB コマンド プロンプトで、以下のように入力します。
help displayTypesafeNumeric
displayTypesafeNumeric.m Help file for displayTypesafeNumeric C MEX function Use the following command to build this MEX file: mex -R2018a displayTypesafeNumeric.c