2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

概要

 有限要素法(FEM)や粒子法で非線形方程式を解く際、ニュートン法が使われます。しかし、ニュートン法は、適切な初期値を与えないと収束しません。

 今回の記事では、初期値に依存しないような方法、ホモトピー法について説明したいと思います。

以下のスライドを参考にしました。

ニュートン法

 最初に、ニュートン法について説明する。解きたい方程式を、

\begin{align}
f(x)=0
\end{align}

とする。ここで、既知の値を $x_n$ として、微小変化量 $\delta x$ を使い、

\begin{align}
f(x_n+\delta x)\approx0
\end{align}

となるような微小変化量 $\delta x$を求めることを考える。(ただし $f(x_n)\neq0$。$n$ は、暗に、繰り返し数を意味する。)

 この式をテイラー展開することで、

\begin{align}
f(x_n+\delta x)&\approx f(x_n)+\frac{\partial f(x)}{\partial x}\Big|_{x=x_n} \delta x \\
& \approx0
\end{align}
\begin{align}
\therefore \delta x = -\left(\frac{\partial f(x)}{\partial x}\right)^{-1}\Big|_{x=x_n} f(x_n) 
\end{align}

微小変化量 $\delta x$が求まる。

 ニュートン法のアルゴリズムは、$f(x)=0$ を満たす $x$ を、

\begin{align}
x_{n+1} = x_n -\left(\frac{\partial f(x)}{\partial x}\right)^{-1}\Big|_{x=x_n} f(x_n) 
\end{align}

として、繰り返し計算を行い求めていく。1次元の場合、プログラムはこんな感じになる(だろう)。

# 求めたい方程式
def f(x):
  return 方程式

# 求めたい方程式の微分
def df_dx(x):
  return 方程式の微分

iter = 1
old_x = 初期値

while(True):
  print('--------- iter = ' + str(iter) +'  ---------')
  # δu
  delta_x = -f(old_x)/df_dx(old_x)
  new_x = old_x + delta_x
  r = f(new_x)
  iter = iter + 1
  print(new_x,r)
  # 閾値を決め、誤差が閾値より小さくなったとき終了
  if np.abs(r) < 10**(-5) : break
  old_x = new_x

ホモトピー法

 $f(x)=0$ に対して、初期値 $x_0$ として以下の関数、

\begin{align}
g(x) &= f(x) -f(x_0) \\
h(t,x) &= tf(x)+(1-t)g(x)
\end{align}

を考える。
 
 $t=0$ の場合、$h(0,x)=g(x)$ となり、$t=1$ の場合、$h(1,x)=f(x)$ となる。ホモトピー法は、$t$ を $0$ から $1$ に変化させて$h(t,x)=0$ を解いていき、$t=1$ のとき、求めたい方程式 $f(x)=0$ となる $x$ が求まる。

具体的な $h(t,x)=0$ 解き方として、常微分方程式に帰着して解く方法がある。$h(t,x)$ を全微分すると、

\begin{align}
\mathrm{d} h(t,x) &= \frac{\partial h}{\partial t} \mathrm{d}t + \frac{\partial h}{\partial x} \mathrm{d}x \\
&= 0 \\ 
\\
\Rightarrow \frac{\mathrm{d} h}{\mathrm{d} t} &= \frac{\partial h}{\partial t}  + \frac{\partial h}{\partial x} \frac{\mathrm{d} x}{\mathrm{d} t} \\
&= 0 \\ 
\end{align}

となるので、

\begin{align}
\frac{\mathrm{d} x}{\mathrm{d} t}= -\left(\frac{\partial h}{\partial x}\right)^{-1}\frac{\partial h}{\partial t} 
\end{align}

と求まる。
 また

\begin{align}
&\frac{\partial h}{\partial t} = f(x) -g(x) = f(x_0) \\
&\frac{\partial h}{\partial x} = t\frac{\partial f}{\partial x} + (1-t)\frac{\partial f}{\partial x} = \frac{\partial f}{\partial x}
\end{align}

なので、微小量(刻み幅) $\delta$ として $dx/dt$ を単純に差分化すれば

\begin{align}
\frac{\mathrm{d} x}{\mathrm{d} t} &\approx \frac{x_{n+1}-x_n}{\delta} \\
&= -\left(\frac{\partial f}{\partial x}\right)^{-1} f(x_0)
\end{align}

と書ける。

 ホモトピー法のアルゴリズムは、$f(x)=0$ を満たす$x$ を、

\begin{align}
x_{n+1} = x_n -\delta \left(\frac{\partial f(x)}{\partial x}\right)^{-1}\Big|_{x=x_n} f(x_0) 
\end{align}

として繰り返し計算を行い、求めていく。アルゴリズムは、ニュートン法とほぼ変わらない。1次元の場合、プログラムはこんな感じになる(だろう)。

# 求めたい方程式
def f(x):
  return 方程式

# 求めたい方程式の微分
def df_dx(x):
  return 方程式の微分

iter = 1
delta = 刻み幅
t = 0.0 
x0=初期値
old_x = x0

while(True):
    print('--------- iter = ' + str(iter) +'  ---------')
    # δu
    delta_x = -f(x0)/df_dx(old_x)
    new_x = old_x + delta*delta_x
    r = f(new_x)
    t += delta 
    iter = iter + 1
    print(new_x,r)
    # t = 1 となったとき終了。小数点に気を付ける。
    if t >= 1.0 : break
    old_x = new_x

 以上のような単純な差分化のホモトピー法では、刻み幅 $\delta$ を小さく取らなければ収束しない欠点がある。

まとめ

 ニュートン法は、適切な初期値を与えなければ収束しない欠点がある。ホモトピー法は、そこまで初期値に依存はしないが、単純な差分化のホモトピー法では、刻み幅 $\delta$ を小さく取らなければ収束しない。
 
 ホモトピー法を使う場合、もう少し高度な差分化が必要となる。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?