読者です 読者をやめる 読者になる 読者になる

倭算数理研究所

科学・数学・学習関連の記事を、「倭マン日記」とは別に書いていくのだ!

commons-math 解読 (15) : 高速正弦変換 FastSineTransformer、高速余弦変換 FastCosineTransformer

今回は高速正弦変換高速余弦変換を見ていきます。

実変換 RealTransformer

正弦/余弦変換は、フーリエ変換と異なり実関数を実関数へ変換する実変換 (Real Transform) です。 したがって、変換の返り値は double の配列で、引数にとれるのは double の配列もしくは(1変数)実数関数を表す型 UnivariateRealFunction です。

commons-math には実変換を表すインターフェース RealTransformer が定義されていて、高速正弦/余弦変換を表すクラス FastSineTransformer/FastCosineTransformer はこのインターフェースを実装しています:

package org.apache.commons.math.transform;

public interface RealTransformer{

    double[] transform(double[] f);
    double[] transform(UnivariateRealFunction f, double min, double max, int n);

    double[] inversetransform(double[] f);
    double[] inversetransform(UnivariateRealFunction f, double min, double max, int n);
}

使い方は FastFourierTransformer (こちらを参照)とだいたい同じです:

  1. FastSineTransformer / FastCosineTransformer クラスのインスタンスを生成する
  2. transform() / inversetransform() メソッドで変換を実行する

引数の配列(もしくはサンプリングする数)はやはり2の累乗でなければなりません(FastSineTransformer の場合*1)。 Groovy でのサンプルコードはこんなの:

import org.apache.commons.math.transform.FastSineTransformer
import org.apache.commons.math.analysis.UnivariateRealFunction

int n = 2**8

def f = { double x -> Math.random() } as UnivariateRealFunction

// 1. インスタンス生成
def trans = new FastSineTransformer()
// 2. 変換の実行
def Fn = trans.transform(f, -1d, 1d, n)

高速フーリエ変換を表すクラス FastFourierTransformer もそうだけど、いちいちインスタンス化して使わないといけない仕様なのが謎。 そんな大した手間ではありませんが。

ともかく、高速正弦/余弦変換をそれぞれ簡単に見ていきましょう。

高速正弦変換 FastSineTransformer

まずは高速正弦変換。 これは正弦関数 { \sin x } の直交関係

  { \displaystyle
\begin{align*}
     \sum_{n=0}^{N-1}\sin\left(\frac{nk}{N}\pi\right)\sin\left(\frac{nk'}{N}\pi\right) = \frac{N}{2}\delta_{k,k'}
\end{align*}
}

をベースにしています。 別に知らなくてもいいかもしれませんが・・・ まぁそれはともかく、FastFourierTransformer と同様、FastSineTransformer にも変換メソッドが2種類定義されています:

  • transform() / inversetransform()
  • transform2() / inversetransform2()

これらはやはり規格化だけの違いです。

transform() / inversetransform()
transform() :

  { \displaystyle
\begin{align*}
    f_n \mapsto F_n = \sum_{k=0}^{N-1} f_k \, \sin\left(\frac{nk}{N}\pi\right) \\
\end{align*}
}

inversetransform() :

  { \displaystyle
\begin{align*}
    F_n \mapsto  f_n = \frac{2}{N}\sum_{k=0}^{N-1} F_k \, \sin\left(\frac{nk}{N}\pi\right)
\end{align*}
}


transform2() / inversetransform2()
transform() :

  { \displaystyle
\begin{align*}
    f_n \mapsto F_n = \sqrt{\frac{2}{N}}\sum_{k=0}^{N-1} f_k \, \sin\left(\frac{nk}{N}\pi\right) \\
\end{align*}
}

inversetransform() :

  { \displaystyle
\begin{align*}
    F_n \mapsto  f_n = \sqrt{\frac{2}{N}}\sum_{k=0}^{N-1} F_k \, \sin\left(\frac{nk}{N}\pi\right)
\end{align*}
}


高速余弦変換 FastCosineTransformer

次は高速余弦変換。 こちらもほとんど FastFourierTransformer や FastSineTransformer と同じです。 ただし、引数の double の配列は2の累乗 + 1 でないといけないので注意。

transform() / inversetransform()
transform() :

  { \displaystyle
\begin{align*}
    f_n \mapsto F_n
        = \frac{1}{2}\left\{f_0 + (-1)^nf_N\right\}
            + \sum_{k=1}^{N-1} f_k \, \cos\left(\frac{nk}{N}\pi\right) \\
\end{align*}
}

inversetransform() :

  { \displaystyle
\begin{align*}
    F_n \mapsto  f_n
        = \frac{1}{N}\left\{F_0 + (-1)^n F_N\right\}
            + \frac{2}{N}\sum_{k=1}^{N-1} F_k \, \cos\left(\frac{nk}{N}\pi\right)
\end{align*}
}


transform2() / inversetransform2()
transform() :

  { \displaystyle
\begin{align*}
    f_n \mapsto F_n
        = \sqrt{\frac{1}{2N}}\left\{f_0 + (-1)^nf_N\right\}
            + \sqrt{\frac{2}{N}}\sum_{k=1}^{N-1} f_k \, \cos\left(\frac{nk}{N}\pi\right) \\
\end{align*}
}

inversetransform() :

  { \displaystyle
\begin{align*}
    F_n \mapsto  f_n
        = \sqrt{\frac{1}{2N}}\left\{F_0 + (-1)^n F_N\right\}
            + \sqrt{\frac{2}{N}}\sum_{k=1}^{N-1} F_k \, \cos\left(\frac{nk}{N}\pi\right)
\end{align*}
}

級数・フーリエ解析 (岩波 数学公式 2)

級数・フーリエ解析 (岩波 数学公式 2)

*1:FastCosineTrasformer の場合は2の累乗+1でなければなりません。