🕌
不等間隔ノードに対する高速球面上フーリエ変換(NFSFT)
球面上フーリエ変換
球面上フーリエ変換とは,球面調和関数による展開のことです:
ここで,
球面調和関数の詳細は,Wikipedia等を参照してください.
今回は,この展開の数値計算を実行するC言語ライブラリNFFTについて説明します.
NFFTでは,任意に与えられた,
を計算します.ベクトルと行列で表すと,
となって,結局,巨大な疎行列
今回は,アルゴリズムの詳細には立ち入らず,C言語ライブラリNFFTによる計算方法だけ説明します.
計算量
計算量は,
です.
サンプルコード
実際のサンプルを示しながら説明します.
今回は,
に対して,ランダムにノード
となります.
以下が,サンプルコードです.
#include <stdio.h>
#include <math.h>
#include <complex.h>
#include <nfft3.h>
int main(void)
{
const int N = 2;
const int M = 4;
nfsft_plan plan;
nfsft_precompute(N, 1000.0, 0U, 0U);
nfsft_init(&plan, N, M);
for (int i = 0; i < plan.M_total; i++)
{
plan.x[2 * i] = nfft_drand48() - 0.5;
plan.x[2 * i + 1] = nfft_drand48() * 0.5;
}
nfsft_precompute_x(&plan);
for (int k = 0; k < plan.N; k++)
{
for (int n = -k; n <= k; n++)
{
if (k == 1 && (n == 1 || n == -1))
{
plan.f_hat[NFSFT_INDEX(k, n, &plan)] = - sqrt(2*M_PI/3)*k;
}
else
{
plan.f_hat[NFSFT_INDEX(k, n, &plan)] = 0;
}
}
}
nfsft_trafo(&plan);
nfsft_finalize(&plan);
nfsft_forget();
return 0;
}
宣言
const int N = 2;
const int M = 4;
nfsft_plan plan;
- NFSFTに必要な変数を宣言します.
-
N
はフーリエ級数の個数 -
M
はノード点数 -
nfsft_plan
はNFSFTに必要な変数をメンバに持つ構造体
予備計算1
nfsft_precompute(N, 1000.0, 0U, 0U);
- NFSFTを計算するために,事前にグローバル変数を計算する関数です.
-
N
は以下で計算する変換における,自由度の最大値です. -
1000
は,内部で実行される多項式変換(FTP)の上限です. - 2つの
0U
はNFSFTとFTPのフラッグです.詳細は分かりません.
よくわからない場合は,上記の設定にしておくと良いようです.
初期化
nfsft_init(&plan, N, M);
- 初期化です.
- 内部で必要な変数のメモリーを動的確保しています.
ノードの設定
for (int i = 0; i < plan.M_total; i++)
{
plan.x[2 * i] = nfft_drand48() - 0.5;
plan.x[2 * i + 1] = nfft_drand48() * 0.5;
}
- ノードを
与えます.\boldsymbol{x}_j -
を直接与えるのではなく,\boldsymbol{x}_j = (\theta_j, \varphi_j) を与えます.つまり,(\tilde{\theta_j},\tilde{\varphi}_j) \in ([0,1/2] \times [-1/2,1/2)
を与えます.
予備計算2
nfsft_precompute_x(&plan);
- 不等間隔フーリエ変換に必要な予備計算を行う関数です.
- これに関する詳細は,NFFTの記事をご覧ください.
フーリエ波数
for (int k = 0; k < plan.N; k++)
{
for (int n = -k; n <= k; n++)
{
if (k == 1 && (n == 1 || n == -1))
{
plan.f_hat[NFSFT_INDEX(k, n, &plan)] = - sqrt(2*M_PI/3)*k;
}
else
{
plan.f_hat[NFSFT_INDEX(k, n, &plan)] = 0;
}
}
}
- フーリエ波数を与えます.
- 内部では,配列の順番が異なるようなので,補助的なマクロ
NFSFT_INDEX
使いましょう.
球面フーリエ変換
nfsft_trafo(&plan);
- ここまで来れば変換は簡単です.
終了処理
nfsft_finalize(&plan);
nfsft_forget();
- 終了処理には,2段階あります.
- 1つ目の
nfsft_finalize
でplan
で確保したメモリーを破棄します. - 2つ目の
nfsft_forget
でnfsft_precompute
で確保したメモリーを破棄します.
以上です.
Discussion