自動微分(1) — 1変数の場合

前回の記事が適当すぎたので仕切り直しを。

「値と微分係数を同時に計算する型」AutoDiff型は,\(\mathbf{R}\times\mathbf{R}\)に適当な演算を入れたものと考えられる。微分を考える変数を \(x\),微分を計算したい点を \(t\) とするとき,第一成分を「\(x=t\) における値」,第二成分を「\(x=t\) における微分係数」と考える。AutoDiff型の値を \(y=(y_0,y_1)\) とすると,\(y\) はある関数 \(f\) について \(y=(f(t),f'(t))\) となっている。\(h(x)=g(f(x))\) という関数があったとき,すでに得られている \(f(t),f'(t)\) の値を使って \(h(t),h'(t)\) を計算したいとする。合成関数の微分は\[h'(x)=g'(f(x))f'(x)\]で与えられるので、ここに \(x=t\) を代入すれば\[h'(t)=g'(f(t))f'(t)=g'(y_0)y_1\]となる。\(h(t)\) はもちろん \(h(t)=g(y_0)\) で与えられる。

今度は \(k(x)=g(l(x))\) という関数を考えてみよう。\(x=t\) における \(l\) の値と \(l’\) の値はすでに計算されているとして、これを \(z=(z_0,z_1)=(l(t),l'(t))\) とおく。このとき,先ほどと同じように \(k(t)=g(z_0)\),\(k'(t)=g'(z_0)z_1\) がわかる。

このようにして,\(g\) という関数は、AutoDiff型からAutoDiff型への関数を定める。この関数を \(g_*\) とすると,AutoDiff型の値 \((y_0,y_1)\) を与えた時の \(g_*\) の値は\[g_*(y_0,y_1)=(g(y_0),g'(y_0)y_1)\]となる。AutoDiff型が「これまで計算した関数の値と微分係数」を表す型だとすれば,\(g_*\) という関数は「これまで計算した関数に \(g\) という関数を合成した時の、関数の値と微分係数」を表す型である。

上の説明では \(g\) と \(g_*\) を区別して書いたが、実際のプログラミングでは関数や演算子のオーバーロード、あるいは型クラスを使って、\(g_*\) に相当する関数も同じ演算子・関数名で書けるようにするのが普通である。

いくつかの演算について、AutoDiff型を \(\mathbf{R}\times\mathbf{R}\) とみなしたときの計算方法を与えておく。\begin{align*}
(x_0,x_1)\pm(y_0,y_1)&=(x_0\pm y_0,x_1\pm y_1) \\
(x_0,x_1)\cdot(y_0,y_1)&=(x_0 y_0,x_1 y_0+x_0 y_1) \\
(x_0,x_1)/(y_0,y_1)&=(x_0/y_0,(x_1 y_0-x_0 y_1)/y_0^2),
\end{align*}\(g\colon\mathbf{R}\to\mathbf{R}\)(微分可能) に対し、\[g_*((x_0,x_1))=(g(x_0),g'(x_0)x_1),\]\(g\colon\mathbf{R}\times\mathbf{R}\to\mathbf{R}\)(微分可能) に対し、\[g_*((x_0,x_1),(y_0,y_1))=(g(x_0,y_0),g_x(x_0,y_0)x_1+g_y(x_0,y_0)y_1),\]となる。

文章書くのだるい。気が向いたら続く。