Pythonエンジニア必見!NumPy C-API `PyArray_CGT()` 関数で共役転置を極める
PyArray_CGT()
は、NumPy C-API における重要な関数の一つであり、複素数配列の共役転置を取得するために使用されます。
説明
PyArray_CGT()
関数は、入力として PyArrayObject *
型の複素数配列を受け取り、その共役転置を返す PyArrayObject *
型の配列を生成します。
共役転置とは、複素数の符号を反転し、実部と虚部を入れ替える操作です。
例
#include <numpy/arrayobject.h>
int main() {
// 複素数配列を作成
npy_intp dims[] = {2, 3};
PyArrayObject *arr = PyArray_ZEROS(2, dims, NPY_CDOUBLE);
// 配列の要素に値を設定
double real[] = {1, 2, 3, 4, 5, 6};
double imag[] = {7, 8, 9, 10, 11, 12};
PyArray_FillWithScalar(arr, (void*)real, NPY_REAL);
PyArray_FillWithScalar(arr, (void*)imag, NPY_IMAG);
// 共役転置を取得
PyArrayObject *cgt = PyArray_CGT(arr);
// 共役転置の要素を表示
for (int i = 0; i < PyArray_NDIM(cgt); i++) {
for (int j = 0; j < PyArray_DIMS(cgt)[i]; j++) {
npy_cdouble *ptr = (npy_cdouble*)PyArray_GetPtr(cgt, i, j);
printf("(%f, %f) ", ptr->real, ptr->imag);
}
printf("\n");
}
// メモリ解放
Py_DECREF(arr);
Py_DECREF(cgt);
return 0;
}
出力例
(1, -7) (2, -8) (3, -9)
(4, -10) (5, -11) (6, -12)
- 共役転置を取得した配列は、入力配列とは別のメモリ領域に割り当てられます。そのため、共役転置を取得した配列を使用する前に、
Py_DECREF()
でメモリ解放を行う必要があります。 PyArray_CGT()
は、入力配列がNPY_CDOUBLE
型であることを前提としています。他の複素数型配列を使用する場合は、適切な型変換を行う必要があります。
#include <numpy/arrayobject.h>
int main() {
// 複素数配列を作成
npy_intp dims[] = {2, 2};
PyArrayObject *arr = PyArray_ZEROS(2, dims, NPY_CDOUBLE);
// 配列の要素に値を設定
double real[] = {1, 2, 3, 4};
double imag[] = {5, 6, 7, 8};
PyArray_FillWithScalar(arr, (void*)real, NPY_REAL);
PyArray_FillWithScalar(arr, (void*)imag, NPY_IMAG);
// 共役転置を取得
PyArrayObject *cgt = PyArray_CGT(arr);
// 共役転置の要素を表示
for (int i = 0; i < PyArray_NDIM(cgt); i++) {
for (int j = 0; j < PyArray_DIMS(cgt)[i]; j++) {
npy_cdouble *ptr = (npy_cdouble*)PyArray_GetPtr(cgt, i, j);
printf("(%f, %f) ", ptr->real, ptr->imag);
}
printf("\n");
}
// メモリ解放
Py_DECREF(arr);
Py_DECREF(cgt);
return 0;
}
説明
この例では、2x2 の複素数配列を作成し、その共役転置を取得して要素を表示しています。
例 2: 条件付きで共役転置を取得する
#include <numpy/arrayobject.h>
int main() {
// 複素数配列を作成
npy_intp dims[] = {2, 2};
PyArrayObject *arr = PyArray_ZEROS(2, dims, NPY_CDOUBLE);
// 配列の要素に値を設定
double real[] = {1, 2, 3, 4};
double imag[] = {5, 6, 7, 8};
PyArray_FillWithScalar(arr, (void*)real, NPY_REAL);
PyArray_FillWithScalar(arr, (void*)imag, NPY_IMAG);
// 共役転置を取得するかどうかを判定
int is_transpose = 1; // 1: 共役転置を取得, 0: 共役転置を取得しない
PyArrayObject *cgt = NULL;
if (is_transpose) {
cgt = PyArray_CGT(arr);
} else {
cgt = PyArray_View(arr, NULL, NULL);
}
// 共役転置の要素を表示
for (int i = 0; i < PyArray_NDIM(cgt); i++) {
for (int j = 0; j < PyArray_DIMS(cgt)[i]; j++) {
npy_cdouble *ptr = (npy_cdouble*)PyArray_GetPtr(cgt, i, j);
printf("(%f, %f) ", ptr->real, ptr->imag);
}
printf("\n");
}
// メモリ解放
Py_DECREF(arr);
Py_XDECREF(cgt); // 共役転置を取得しなかった場合は、`Py_DECREF()` ではなく `Py_XDECREF()` を使用する
return 0;
}
説明
この例では、is_transpose
変数の値によって、共役転置を取得するかどうかを判定しています。
#include <numpy/arrayobject.h>
int main() {
// 複素数配列を作成
npy_intp dims[] = {2, 2};
PyArrayObject *arr = PyArray_ZEROS(2, dims, NPY_CDOUBLE);
// 配列の要素に値を設定
double real[] = {1, 2, 3, 4};
double imag[] = {5, 6, 7, 8};
PyArray_FillWithScalar(arr, (void*)real, NPY_REAL);
PyArray_FillWithScalar(arr, (
代替方法
- conj() 関数
- NumPy の
numpy.conj()
関数を使用すると、複素数スカラーや配列の共役を計算できます。 PyArray_CGT()
と異なり、conj()
は入力配列を変更しません。- 以下は、
conj()
関数を使用して共役転置を取得する例です。
- NumPy の
import numpy as np
# 複素数配列を作成
arr = np.array([[1 + 2j, 3 + 4j], [5 + 6j, 7 + 8j]], dtype=np.complex128)
# 共役転置を取得
cgt = np.conj(arr.T)
# 共役転置の要素を表示
print(cgt)
- 手動で計算
- 共役転置は、以下の式で手動で計算できます。
cgt[i, j] = conj(arr[j, i])
* この方法は、より高度な制御が可能ですが、コードが複雑になる可能性があります。
- 柔軟性
- 手動で計算する場合は、より高度な制御が可能ですが、コードが複雑になる可能性があります。
- パフォーマンス
- 計算量が多い場合は、
PyArray_CGT()
の方が高速な場合があります。 - ただし、
conj()
関数も十分に高速であり、多くの場合でパフォーマンス上の違いは顕著ではありません。
- 計算量が多い場合は、
- シンプルさ
conj()
関数は、簡潔でわかりやすいコードを書くために適しています。
- 詳細については、NumPy のドキュメントを参照してください。
- 上記以外にも、状況によっては
np.einsum()
やnp.vconj()
などの関数を使用することもできます。