戻る

Nevilleのアルゴリズム

ここ最近、個人的に"Numerical Recipies in C"1 という、C言語の数値計算の本の一部をRustで書き直すことにハマっています。久しぶりに積分のコードを実装し、その際に補間・補外の章を読むことになりました。この記事では、その際に理解に詰まったNevilleのアルゴリズムについて自分なりにまとめています。

Nevilleのアルゴリズムとは?

互いに異なるNN個の点が与えられているとき、それらの点を通るLagrange補間多項式を計算し、任意のxxにおける補間多項式の値を返すアルゴリズムです。

文字や式の説明は後に回しますが、次の漸化式がNevilleのアルゴリズムの鍵になります:

Pi(i+1)(i+m)=(xxi+m)Pi(i+1)(i+m1)(xix)Pi(i+1)(i+m)xixi+m\begin{align} P_{i(i+1)\cdots(i+m)} = \frac{ (x - x_{i + m}) P_{i(i + 1) \cdots (i + m - 1)} - (x_i - x) P_{i(i + 1) \cdots (i + m)} }{ x_i - x_{i + m} } \end{align}

Lagrange補間多項式

NN個の点{(x1,y1),,(xN,yN)}\{(x_1, y_1), \ldots, (x_N, y_N)\}が与えられているとき、Lagrange補間多項式は

P(x)=(xx2)(xx3)(xxN)(x1x2)(x1x3)(x1xN)y1+(xx1)(xx3)(xxN)(x2x1)(x2x3)(x2xN)y2++(xx1)(xx2)(xxN1)(xNx1)(xNx2)(xNxN1)yN\begin{align} P(x) &= \frac{ (x - x_2) (x - x_3) \cdots (x - x_N) }{ (x_1 - x_2) (x_1 - x_3) \cdots (x_1 - x_N) } y_1 + \frac{ (x - x_1) (x - x_3) \cdots (x - x_N) }{ (x_2 - x_1) (x_2 - x_3) \cdots (x_2 - x_N) } y_2 \notag \\ &+ \cdots + \frac{ (x - x_1) (x - x_2) \cdots (x - x_{N-1}) }{ (x_N - x_1) (x_N - x_2) \cdots (x_N - x_{N-1}) } y_N \\ \end{align}

で与えられます。これは一意的です。

Li(x)L_i(x)

Li(x)=j=1(ji)(xxj)(xixj) L_i(x) = \prod_{j = 1 (j \neq i)} \frac{ (x - x_j)}{(x_i - x_j)}

のように表現しておけば、これはLi(xj)=δijL_i(x_j) = \delta_{ij}δij\delta_{ij}はKroneckerのデルタ)を満たします。 よって、P(x)=iLiyiP(x) = \sum_{i} L_i y_iのように書くこともできますね。

例:4点の場合でイメージをつかむ

残念ながら私は数式だけであまりイメージができなかったので、まずは簡単な場合を考えて意味ます。 フリーレンも言っていますね。

魔法はイメージの世界だ

フリーレンの画像

帰納的な図(Nevilleの三角表)

x1:y1=P1P12x2:y2=P2P123P23P1234x3:y3=P3P234P34x4:y4=P4\begin{array}{cccccccc} x_1:& y_1 = P_1 & & & \\ & & P_{12} & & \\ x_2:& y_2 = P_2 & & P_{123} & \\ & & P_{23} & & P_{1234}\\ x_3:& y_3 = P_3 & & P_{234} & \\ & & P_{34} & & \\ x_4:& y_4 = P_4 & & & \\ \end{array}

今、{(x1,y1),(x2,y2),(x3,y3),(x4,y4)}\{ (x_1, y_1), (x_2, y_2), (x_3, y_3), (x_4, y_4) \}の4点について考えていみましょう。まずは0次の補間は定数で、P1=y1,P2=y2,P3=y3,P4=y4P_1 = y_1, P_2 = y_2, P_3 = y_3, P_4 = y_4となります。さてそれぞれの隣り合う点同士の1次の補間関数は例えば、

P12(x)=(xx2)(x1x2)y1+(xx1)(x2x1)y2\begin{align} P_{12}(x) = \frac{(x - x_2) }{(x_1 - x_2)} y_1 + \frac{(x - x_1) }{(x_2 - x_1)} y_2 \end{align}

となります。明らかに1次関数であり、P12(x1)=y1P_{12}(x_1) = y_1P12(x2)=y2P_{12}(x_2) = y_2を満たすので、(x1,y1),(x2,y2)(x_1, y_1), (x_2, y_2)を通る直線を想像できるでしょう。

このセンスで、P12(x1)P_{12}(x_1)P23(x3)P_{23}(x_3)を通る2次曲線も構築できるでしょう。つまり、

P123(x)=(xx3)(x1x3)P12(x)+(xx1)(x3x1)P23(x)\begin{align} P_{123}(x) = \frac{(x - x_3) }{(x_1 - x_3)} P_{12}(x) + \frac{(x - x_1) }{(x_3 - x_1)} P_{23}(x) \end{align}

ということです。新しくできた2次関数(1次関数にさらにxxの項をかけているので)は明らかにP123(x1)=y1,P123(x2)=y3P_{123}(x_1) = y_1, P_{123}(x_2) = y_3です。 もちろんP123(x2)P_{123}(x_2)のときも

P123(x2)=(x2x3)(x1x3)P12(x2)+(x2x1)(x3x1)P23(x2)=(x2x3)y2(x2x1)y2(x1x3)=y2\begin{align*} P_{123}(x_2) &= \frac{(x_2 - x_3) }{(x_1 - x_3)} P_{12}(x_2) + \frac{(x_2 - x_1) }{(x_3 - x_1)} P_{23}(x_2) \\ &= \frac{(x_2 - x_3)y_2 - (x_2 - x_1)y_2}{(x_1 - x_3)} \\ &= y_2 \end{align*}

です。

このようにして、1次補間を何度も繰り返すことで、4次の補完関数まで求めることができます。

4つの点を補間する画像


Footnotes

  1. William H. Press et al (丹慶勝市 et al.), "Numerical Recipes in C", 1988 (日本語版 1993)

戻る