倭算数理研究所

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

単位球体内の一様分布 : 2次元

今回から何度かに渡り、いくつかの次元における単位球体内の一様分布を生成する方法を見ていきます。 単位球面上の一様分布を得るには、半径 r を1にするだけで OK です。 今回は2次元。 2次元の単位球体は単に「円」(内部を含む)です。

目次

極座標

2次元の極座標は以下のように与えられるのでした(『極座標のヤコビ行列とヤコビアン : 2次元参照』):

  { \displaystyle\begin{align*}
    \begin{cases}
          x = r \cos \theta \\
          y = r \sin \theta
    \end{cases}
    \qquad
    \begin{pmatrix}
         0\le r < \infty \\
         0 \le \theta < 2\pi
    \end{pmatrix}
\end{align*}}

単位球体(円)内での積分は以下のようになります:

  { \displaystyle\begin{align*}
    \int_0^1 rdr \int_0^{2\pi} d\theta
\end{align*}}

一様分布する変数

一様分布する変数を同定するには、積分測度が全微分形(って言うんだっけ?)で書けるような変数を見つけ、変数変換を行います。 { \theta } はすでにそのような形になっており、{ r } についても簡単に見つけることが出来ます:

  { \displaystyle\begin{align*}
    \left(r,\,\theta\right) \rightarrow \left(R,\,\theta\right) = \left(\tfrac{1}{2} r^2,\, \theta\right)
        \quad \in [0,\, \tfrac{1}{2}] \times [0,\,2\pi )
\end{align*}}

このとき、単位球体内の積分は以下のようになり、

  { \displaystyle\begin{align*}
    \int_0^{1/2} dR \int_0^{2\pi} d\theta
\end{align*}}

確かに全微分形になってます。

直交座標の計算

通常必要なのは直交座標なので、{ (x,\,y) } を用いて { R,\,\theta } を表す必要があります。 まずは、{ (r,\,\theta) }{ R,\,\theta } で表しましょう:

  { \displaystyle\begin{align*}
    (r,\,\theta) = (\sqrt{2R},\,\theta)
\end{align*}}

これを極座標の定義式に代入すれば任務完了:

  { \displaystyle\begin{align*}
    \begin{cases} x = \sqrt{2R} \cos\theta \\ y = \sqrt{2R}\sin\theta \end{cases}
\end{align*}}

これを用いて2次元球体内の一様分布を生成するためには、{ R } に2を吸収させて(定義域にも反映させます)、以下の形で座標を計算します:

  { \displaystyle\begin{align*}
    \begin{cases}
        x = \sqrt{\tilde{R}} \cos\tilde{\theta} \\
        y = \sqrt{\tilde{R}}\sin\tilde{\theta}
    \end{cases}
    \qquad
    \begin{pmatrix}
        0 \le R \le 1 \\
        0 \le \theta < 2\pi
    \end{pmatrix}
\end{align*}}
ただし、変数 { X \in [a,\,b] } に対して、 { \tilde{X} }区間 { [a,\,b] } 間に一様分布する変数とします。

Java コード

実際に Java で2次元球体内の一様乱数を生成してみましょう。 Java コードは以下のようになります:

import static java.lang.Math.*;

public class UniformDistributionB2{

    public static void main(String... args){
        
        for(int i = 0; i < 100000; i++){
            double r = sqrt(random());
            double theta = random() * 2 * PI;
            
            double x = r * cos(theta);
            double y = r * sin(theta);
            
            System.out.println(x+" "+y);
        }
    }
}

random() メソッドは java.lang.Math クラスに定義されているメソッドで、0と1の間の一様乱数を生成します(念のため)。

結果をプロットすると下図のようになります: