NumPy C-API: マルチイテレータで配列を飛び回る! `PyArray_MultiIter_GOTO()` 関数の使い方
void PyArray_MultiIter_GOTO(PyObject *multi, npy_intp *destination);
引数
destination
: 各イテレータが移動するN次元座標を表す配列へのポインタmulti
: マルチイテレータオブジェクトへのポインタ
動作
- いずれかのイテレータが指定された座標に到達できない場合、関数はエラーを返します。
- すべてのイテレータが指定された座標に到達すると、関数は正常終了します。
- 各座標値は、対応するイテレータが処理する配列要素のインデックスを表します。
PyArray_MultiIter_GOTO()
関数は、multi
で指定されたマルチイテレータ内の各イテレータを、destination
で指定されたN次元座標まで移動させます。
戻り値
なし
例
#include <numpy/arrayobject.h>
int main() {
// 2つの配列を作成
npy_intp dims1[] = {3, 4};
npy_intp dims2[] = {4, 3};
PyArrayObject *arr1 = PyArray_SimpleNewFromIntp(2, dims1, NPY_INT32);
PyArrayObject *arr2 = PyArray_SimpleNewFromIntp(2, dims2, NPY_INT32);
// マルチイテレータを作成
PyArrayMultiIter *multi = PyArray_MultiIterNew(2, arr1, arr2);
// 座標を指定
npy_intp destination[] = {2, 1};
// マルチイテレータ内の各イテレータを指定された座標まで移動
PyArray_MultiIter_GOTO(multi, destination);
// マルチイテレータ内の現在の要素を取得
npy_int32 *data1 = (npy_int32 *)PyArray_MultiIter_DATA(multi, 0);
npy_int32 *data2 = (npy_int32 *)PyArray_MultiIter_DATA(multi, 1);
// 現在の要素の値を出力
printf("arr1[%d, %d] = %d, arr2[%d, %d] = %d\n",
multi->index[0], multi->index[1], *data1, multi->index[0], multi->index[1], *data2);
// マルチイテレータを解放
PyArray_MultiIter_Free(multi);
// 配列を解放
Py_DECREF(arr1);
Py_DECREF(arr2);
return 0;
}
この例では、2つの配列 arr1
と arr2
を作成し、マルチイテレータ multi
を使用してそれらをイテレートします。その後、PyArray_MultiIter_GOTO()
関数を使用して、マルチイテレータ内の各イテレータを指定された座標 [2, 1]
まで移動します。最後に、現在の要素の値を出力して、マルチイテレータと配列を解放します。
PyArray_MultiIter_GOTO()
関数は、NumPy C-APIの一部であり、高度な操作にのみ使用することをお勧めします。- 多くの場合、
PyArray_MultiIter_NEXT()
関数を使用して、マルチイテレータ内の各イテレータを順次移動させる方が効率的です。 PyArray_MultiIter_GOTO()
関数は、マルチイテレータ内の各イテレータを個別に制御する必要がある場合に役立ちます。
マルチイテレータを使用して2つの配列の要素を足し合わせる
#include <numpy/arrayobject.h>
int main() {
// 2つの配列を作成
npy_intp dims1[] = {3, 4};
npy_intp dims2[] = {4, 3};
PyArrayObject *arr1 = PyArray_SimpleNewFromIntp(2, dims1, NPY_INT32);
PyArrayObject *arr2 = PyArray_SimpleNewFromIntp(2, dims2, NPY_INT32);
// 配列に値を割り当てる
for (int i = 0; i < arr1->size; i++) {
((npy_int32 *)arr1->data)[i] = i;
}
for (int i = 0; i < arr2->size; i++) {
((npy_int32 *)arr2->data)[i] = i + 10;
}
// マルチイテレータを作成
PyArrayMultiIter *multi = PyArray_MultiIterNew(2, arr1, arr2);
// 座標を指定
npy_intp destination[] = {1, 2};
// マルチイテレータ内の各イテレータを指定された座標まで移動
PyArray_MultiIter_GOTO(multi, destination);
// 対応する要素を足し合わせて結果を出力
npy_int32 *data1 = (npy_int32 *)PyArray_MultiIter_DATA(multi, 0);
npy_int32 *data2 = (npy_int32 *)PyArray_MultiIter_DATA(multi, 1);
printf("arr1[%d, %d] + arr2[%d, %d] = %d\n",
multi->index[0], multi->index[1], multi->index[0], multi->index[1], *data1 + *data2);
// マルチイテレータを解放
PyArray_MultiIter_Free(multi);
// 配列を解放
Py_DECREF(arr1);
Py_DECREF(arr2);
return 0;
}
この例では、マスクされた配列 mask
を作成し、マルチイテレータを使用して arr1
と arr2
の要素を処理します。その後、PyArray_MultiIter_GOTO()
関数を使用して、マルチイテレータ内の各イテレータを指定された座標まで移動します。最後に、マスクされた要素のみを処理し、結果を出力します。
#include <numpy/arrayobject.h>
int main() {
// 3つの配列を作成
npy_intp dims1[] = {3, 4};
npy_intp dims2[] = {4, 3};
npy_intp dims3[] = {3, 4};
PyArrayObject *arr1 = PyArray_SimpleNewFromIntp(2, dims1, NPY_INT32);
PyArrayObject *arr2 = PyArray_SimpleNewFromIntp(2, dims2, NPY_INT32);
PyArrayObject *mask = PyArray_SimpleNewFromIntp(2, dims3, NPY_BOOL);
// 配列に値を割り当てる
for (int i = 0; i < arr1->size; i++) {
((npy_int32 *)arr1->data)[i] = i;
}
for (int i = 0; i < arr2->size; i++) {
((npy_int32 *)arr2->data)[i] = i + 10;
}
for (int i = 0; i < mask->size; i++) {
((char *)mask->data)[i] = (i % 2 == 0);
}
// マルチイテ
代替方法
PyArray_MultiIter_NEXT()
関数を使用する
PyArray_MultiIter_NEXT()
関数は、マルチイテレータ内の各イテレータを次の要素に移動させます。この関数を繰り返し呼び出すことで、マルチイテレータ内のすべての要素を順次処理することができます。
PyArrayMultiIter *multi = PyArray_MultiIterNew(2, arr1, arr2);
while (PyArray_MultiIter_NEXT(multi)) {
// マルチイテレータ内の現在の要素を取得
npy_int32 *data1 = (npy_int32 *)PyArray_MultiIter_DATA(multi, 0);
npy_int32 *data2 = (npy_int32 *)PyArray_MultiIter_DATA(multi, 1);
// 現在の要素を処理
printf("arr1[%d, %d] = %d, arr2[%d, %d] = %d\n",
multi->index[0], multi->index[1], *data1, multi->index[0], multi->index[1], *data2);
}
PyArray_MultiIter_Free(multi);
- ループを使用して各イテレータを個別に制御する
各イテレータを個別に制御する必要がある場合は、ループを使用して各イテレータを指定された座標まで移動させることができます。
for (int i = 0; i < multi->itersize; i++) {
// イテレータを指定された座標まで移動
PyArray_Iter_GOTO(multi->iters[i], destination[i]);
}
- 条件付き処理を使用して必要な要素のみを処理する
必要な要素のみを処理する必要がある場合は、条件付き処理を使用してマルチイテレータ内の要素を検査することができます。
PyArrayMultiIter *multi = PyArray_MultiIterNew(2, arr1, arr2);
while (PyArray_MultiIter_NEXT(multi)) {
// マルチイテレータ内の現在の要素を取得
npy_int32 *data1 = (npy_int32 *)PyArray_MultiIter_DATA(multi, 0);
npy_int32 *data2 = (npy_int32 *)PyArray_MultiIter_DATA(multi, 1);
// 必要な条件を満たす場合のみ処理
if (/* 条件 */) {
printf("arr1[%d, %d] = %d, arr2[%d, %d] = %d\n",
multi->index[0], multi->index[1], *data1, multi->index[0], multi->index[1], *data2);
}
}
PyArray_MultiIter_Free(multi);
- 条件付き処理を使用して必要な要素のみを処理する
- 利点: 効率的
- 欠点: コードが複雑になる
- ループを使用して各イテレータを個別に制御する
- 利点: 柔軟性が高い
- 欠点: コードが複雑になる
- PyArray_MultiIter_NEXT() 関数を使用する
- 利点: シンプルでわかりやすい
- 欠点: 順番にしか処理できない