ニュートン法（2変数）

## ニュートン法（１変数）
https://qiita.com/roadto93ds/items/476d84c94410edfe5b10

## ニュートン法（2変数）
2変数のニュートン法も作りました。

凸関数 $f(x, y)$ の最小解と最小値をニュートン法で求める

```math

\begin{aligned}
&\nabla f(x, y)=\left[\begin{array}{ll}
f_{x}(x, y) \\
f_{y}(x, y)
\end{array}\right] \\
&\nabla^{2} f(x, y)=\left[\begin{array}{ll}
f_{x x}(x . y) & f_{x y}(x, y) \\
f_{y x}(x, y) & f_{y y}(x, y)
\end{array}\right] \\
&\left(\begin{array}{l}
x_{new} \\
y_{new}
\end{array}\right)=\left(\begin{array}{l}
x_{old} \\
y_{old}
\end{array}\right)-\nabla^{2} f(x_{old}, y_{old})^{-1} \nabla f(x_{old}, y_{old})
\end{aligned}

```
更新式から最小解 $(x,y)$ を求めて、最後に最小値を出力する

## 実装
```python
import matplotlib.pyplot as plt
import numpy as np


# 実装
def newton_method_2val(func0,func1, func2, initial_x, initial_y, EPS):
    """
    func0: f(x,y)
    func1: f_x(x,y)
    func2: f_y(x,y)
    funcの部分はlambda関数で設定する。
        func = lambda x,y : x+y+3
        func(1,3) = 7
    EPS：更新幅を止める基準
    """
    count = 0
    # xの更新値の保存
    x_new_list = [ ]
    y_new_list = [ ]
    diff = 10 # EPS基準で止めに行くが、止まらない値で設定しておく
    
    print("========== processing ==========")
    
    while diff >= EPS:
        count += 1
        f_x = func1(initial_x, initial_y)
        f_y = func2(initial_x, initial_y)

        # nabla^2 f(x,y)
        h = 1e-10 # 微小区間
        # 中心差分公式で微分
        f_xx = (func1(initial_x + h, initial_y) - func1(initial_x - h, initial_y))/(2*h)
        f_xy = (func1(initial_x, initial_y+h) - func1(initial_x , initial_y-h))/(2*h)
        f_yx = (func2(initial_x + h, initial_y) - func2(initial_x - h, initial_y))/(2*h)
        f_yy = (func2(initial_x, initial_y+h) - func2(initial_x , initial_y-h))/(2*h)
        
        # 更新に必要なものを行列形式にまとめる
        initial = np.array([[initial_x], [initial_y]]) # 初期値格納
        nabla = np.array([[f_x], [f_y]]) # nabla(x,y)
        nabla2 = np.array([[f_xx, f_xy],[f_yx, f_yy]]) # nabla^2(x,y)
        inv_nabla2 = np.linalg.inv(nabla2) # nabla^2(x,y) の逆行列
        
        # 更新値を求める
        new = initial - np.dot(inv_nabla2, nabla)
        # count と 更新値
        print("{}回目:x_new = {},y_new={}".format(count,new[0,0],new[1,0]))
        x_new_list.append(new[0,0]) # xの更新値をリストに追加
        y_new_list.append(new[1,0]) # yの更新値をリストに追加
        
        
        # 更新幅
        diff_x = abs(initial_x - new[0,0])
        diff_y = abs(initial_y - new[1,0])
        # diffの大きい方でwhileを止める基準にしたい
        diff = max(diff_x,diff_y)
        # 値の更新
        initial_x = new[0,0]
        initial_y = new[1,0]

        
        if count == 100: # 100回で収束しなければ
            diff = 0 # diffを強制的に0にして
            print("========== Do not CONVERSION =========")  # while 文から抜ける
    
    print("========== Result ==========")
    print("solution:x = {}".format(new[0,0]))
    print("solution:y = {}".format(new[1,0]))
    value = func0(new[0,0],new[1,0]) # 解を代入した値
    print("min_value:{}".format(value))
    
    # グラフ描画
    trial = np.arange(1, count+1, 1) # 1 ~ n回

    fig = plt.figure(figsize=(15, 2.5))
    ax = fig.add_subplot(1, 2, 1)
    x_value = np.array(x_new_list)
    plt.plot(trial, x_value, color="red")
    plt.title("x_process")
    plt.xlabel('trial')
    plt.ylabel('x_new')

    ax = fig.add_subplot(1, 2, 2)
    y_value = np.array(y_new_list)
    plt.plot(trial, y_value, color="blue")
    plt.title("y_process")
    plt.xlabel('trial')
    plt.ylabel('y_new')


    plt.show()
```



## 投入

$$f(x, y)=\frac{x^{4}}{2}+\frac{x^{3}}{3}-2 x^{2} y+4 x+3 y^{2}+4 y+4$$

```python
newton_method_2val(lambda x,y: (1/2)*x**4+(1/3)*x**3-2*(x**2)*y+3*y**2+3*x-1*y+4,
                   lambda x,y: 2*x**3+x**2-4*x*y+3, 
                   lambda x,y: 6*y-2*x**2-1,
                   9,3, 0.0001)
```
========== processing ==========
1回目:x_new = 6.956495810248076,y_new=14.90540384620938
2回目:x_new = 4.61060249609451,y_new=5.418088454657781
3回目:x_new = 3.129220719387754,y_new=2.6991904039382333
4回目:x_new = 2.021337899706909,y_new=1.1194672031808257
5回目:x_new = 1.1684879443600464,y_new=0.3793366434284833
6回目:x_new = 0.3027062364792097,y_new=-0.05264901159486629
7回目:x_new = -2.290661442659664,y_new=-0.3261419277396098
8回目:x_new = -2.414577217675341,y_new=2.1049424354116724
9回目:x_new = -2.5851419887405522,y_new=2.384622254255956
10回目:x_new = -2.5704464991029425,y_new=2.368993071767485
11回目:x_new = -2.5702482687485855,y_new=2.368725374647714
12回目:x_new = -2.5702482387915295,y_new=2.3687253363369853
========== Result ==========
solution:x = -2.5702482387915295
solution:y = 2.3687253363369853
min_value:-4.38238055980867

![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698282/079d6392-a2ad-1ab2-5111-1c6b5d06a070.png)




前の記事では縦軸を差分で出していたので、trialを増すごとに差分が小さくなっていく様子が見れますが、今回は解の更新の推移を表示しているので、必ずしも小さくなるとは限りませんが収束はしていきます。

## 答え合わせ

![スクリーンショット 2021-09-10 18.26.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698282/12d3a162-3ebd-9324-212f-cfb99b781fb9.png)

![スクリーンショット 2021-09-10 18.26.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698282/919c5d3e-3764-cb00-be45-56f9e2788efa.png)

>答え合わせに使用した wolframAlpha
> https://www.wolframalpha.com/