中心差分を用いた接線の交点の求め方とPythonのライブラリであるmatplotlibによる可視化

# 目次
[はじめに](#はじめに)
[実行環境](#実行環境)
[接線の交点の座標の求め方](#接線の交点の座標の求め方)
[微分係数の求め方](#微分係数の求め方)
[ソースコード](#ソースコード)
[結果](#結果)
[まとめ](#まとめ)

# はじめに

**様々な関数の任意の2点の接線の交点を求めると面白そう**だったので、2つの接線の交点のx座標とy座標の式を求めました。
また、Pythonのライブラリである<font color="red"> **`matplotlib`** </font>を用いて**関数のグラフ、任意の2点を通る2つの接線、2つの接線の交点**を描画しました。

--------

よろしければこちらもどうぞ!!

<details><summary>マイページについて</summary>

:::note info
主に<ins>**Pythonについての記事**</ins>を投稿してます!!
:::

[<font color="blue"><ins>**マイページはこちら**</ins></font>](https://qiita.com/blueman,"マイページ")

----------------------

</details>

<details><summary>X(Twitter)について</summary>

:::note info
<ins>**Qiitaの新着記事の通知**</ins>や<ins>**おススメの理工学書の紹介**</ins>をツイートしてます!!
:::
[<font color="blue"><ins>**X(Twitter)はこちら**</ins></font>](https://twitter.com/0ca00118726208m,"X(Twitter)")

--------------------------------

</details>

<details><summary>Zennについて</summary>

:::note info
主に<ins>**自分の書いたQiitaの記事の転載**</ins>と<ins>**Pythonを使っていて遭遇したエラーの対処法のような記事**</ins>を投稿していく予定です!!
:::
[<font color="blue"><ins>**Zennはこちら**</ins></font>](https://zenn.dev/blueman,"Zenn")

--------------------------------

</details>

# 実行環境
実行環境は次の通りです。

<details><summary>実行環境</summary>

- **実行環境**
    -  **`Windows 10`**
    -  **`Python 3.10.5`**
- **ライブラリ**
    -  **`matplotlib 3.6.1`**

--------

</details>

# 接線の交点の座標の求め方
<ins>**微分係数を用いた接線の公式**</ins>は、<font color="red">**任意の$x$座標**</font>を<font color="blue">$a$</font>とし<font color="red">**任意の関数**</font>を<font color="blue">$f(x)$</font>とすると<font color="red">**$x$座標のときの$y$座標**</font>は<font color="blue">$f(a)$</font>と表せます。
また、<font color="red">**任意の$x$座標での微分係数**</font>を<font color="blue">$f'(x)$</font>とし、これを用いると<ins>**任意の点での接線の傾き**</ins>を求められ<font color="red">**$x=a$での傾き**</font>は<font color="blue">$f'(a)$</font>と表せます。

これらの値から<font color="red">**$x=a$での接線**</font>は、以下のように表せます。

```math
y-f(a)=f'(a)(x-a) \label{a}\tag{1}
```

ここで、<font color="red">**新たに任意の$x$座標**</font>を<font color="blue">$b$</font>とし上記と同様に考えると、接線は以下のように表せます。

```math
y-f(b)=f'(b)(x-b) \label{b}\tag{2}
```

<font color="green">$(1)-(2)$</font>より、

```math
\begin{align}
f(b)-f(a) & =\Bigl(f'(a)-f'(b)\Bigl)x+f'(b)b-f'(a)a\\
\Bigl(f'(a)-f'(b)\Bigl)x &= f(b)-f(a)-f'(b)b+f'(a)a\\
x&=\frac{f(b)-f(a)-f'(b)b+f'(a)a}{f'(a)-f'(b)} \label{c}\tag{3}
\end{align}
```

また、<font color="green">$(1)\times f'(b)$</font>より、

```math
f'(b)\times y-f(a)\times f'(b)=f'(a)\times f'(b)\times x-f'(a)\times f'(b)\times a \label{d}\tag{4}
```

一方で、<font color="green">$(2)\times f'(a)$</font>より、

```math
f'(a)\times y-f'(a)\times f(b)=f'(a)\times f'(b)\times x-f'(a)\times f'(b)\times b \label{e}\tag{5}
```

<font color="green">$(4)-(5)$</font>より、

```math
\begin{align}
\Bigl(f'(b)-f'(a)\Bigl)y+f'(a)f(b)-f(a)f'(b) & =f'(a)f'(b)b-f'(a)f'(b)a\\
\Bigl(f'(b)-f'(a)\Bigl)y&= (b-a)f'(a)f'(b)-f'(a)f(b)+f(a)f'(b)\\
y&= \frac{(b-a)f'(a)f'(b)-f'(a)f(b)+f(a)f'(b)}{f'(b)-f'(a)}\label{f}\tag{6}
\end{align}
```
したがって、<font color="blue">$(3)$と$(6)$</font>が<font color="red">**2つの接線の交点の$x$座標と$y$座標**</font>です。

#### 微分係数の求め方
ここで、<ins>**微分係数の定義式**</ins>を考えると、

```math
f'(a)=\lim_{h \to 0}\frac{f(a+h)-f(a)}{h} \label{g}\tag{7}
```
であり、<ins>**$h$を0に近づけるという極限操作をしなければなりません。**</ins>しかし、<font color="red"><ins>**コンピュータ上では極限操作を行うことができません。**</ins></font>

そこで、<ins>**数値微分を行うことで近似的に微分係数を計算**</ins>しました。
[**数値微分における3つの差分とその誤差について**](https://qiita.com/Negelon/items/fafec9b0d33ab96d1446)を参照すると、
><font color="Red">**中心差分が最も接線の傾きに近い**</font>

らしいので**中心差分**を用いて微分係数を求めることにしました。ちなみに、**中心差分**は<ins>以下の式</ins>で求められるそうです。

```math
f'(x)\approx \frac{f(x+h)-f(x-h)}{2h}
```
# ソースコード
実行環境で示した環境で実行すればおそらく動くはず。

<details><summary>ソースコード</summary>

```python:sessen_kouten.py
#任意の関数の二接線の交点の座標を算出

#ライブラリのインポート
import numpy as np
import matplotlib.pyplot as plt

#中心差分の式のhを定義
h = 10**(-4)

#aとbを定義
a = -2
b = 2

x = np.linspace(-10,10,1001) #xの値を定義

'''接線の交点を求めたい関数の宣言
本コードでは

 y=x^2

とした'''

def func(x):
	return x**2

#定義したa,bでの微分係数の計算
dydx_a = (func(a+h)-func(a-h))/(2*h) #x=aでの微分係数
dydx_b = (func(b+h)-func(b-h))/(2*h) #x=bでの微分係数

y_a = dydx_a*x-dydx_a*a+func(a) #x=aでの接線の計算
y_b = dydx_b*x-dydx_b*b+func(b) #x=bでの接線の計算

'''交点のx座標を計算

          f(b)-f(a)-f'(b)b+f'(a)a
x_交点 =  ----------------------
               f'(a)-f'(b)

'''

x_inter = (func(b)-func(a)-dydx_b*b+dydx_a*a)/(dydx_a-dydx_b)

if x_inter == -0.0:              #x_interが-0.0になったとき
                                 #(左側極限を考える)
    x_inter = 0.0                #x_interを0.0にする
                                 #(-0.0と0.0は、点を考える上では同一と考えてもよいため)

'''交点のy座標を計算

          (a-b)f'(a)f'(b)+f'(a)f(b)-f'(b)f(a)
y_交点 =  -----------------------------------
                     f'(a)-f'(b)

'''

y_inter = ((a-b)*dydx_a*dydx_b+dydx_a*func(b)-dydx_b*func(a))/(dydx_a-dydx_b)

#print("f(a) = {:.3f}".format(func(a))) #コメントアウトを外すとx=aでのy座標が出力される
#print("f'(a) = {:.3f}".format(dydx_a)) #コメントアウトを外すとx=aでの微分係数が出力される
#print("f(b) = {:.3f}".format(func(b))) #コメントアウトを外すとx=bでのy座標が出力される
#print("f'(b) = {:.3f}".format(dydx_b)) #コメントアウトを外すとx=bでの微分係数が出力される
#print("x_inter = {:.3f}".format(x_inter)) #コメントアウトを外すと2つの接線の交点のx座標が出力される
#print("y_inter = {:.3f}".format(y_inter)) #コメントアウトを外すと2つの接線の交点のy座標が出力される

#print("(%f,%f)" % (x_inter,y_inter)) #コメントアウトを外すと2つの接線の交点の座標が出力される

plt.xlim(-10,10)  #x軸の表示範囲を制限
#plt.ylim(0,2) #y軸の表示範囲を制限
plt.plot(x,func(x)) #任意の関数のグラフを描画
plt.plot(x,y_a) #任意の関数のx=aでの接線を描画
plt.plot(x,y_b) #任意の関数のx=bでの接線を描画
plt.scatter(x_inter,y_inter) #2つの接線の交点を描画

#plt.plot(x,np.zeros(len(x))) #コメントアウトを外すとx=0の直線を描画
plt.show()
```

----------------

</details>

# 結果
ソースコードを実行した結果は次の通りです。

<details><summary>実行結果のグラフ</summary>

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3198998/3621ce49-e4c1-4253-d8c3-390bdcced4c7.png alt="グラフ">

:::note
分かりやすいように<ins>**接線の交点**</ins>をプロットしてます。
:::

--------------------------

</details>
<details><summary>実行結果のコマンドプロンプト上の表示</summary>

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3198998/6316b256-4679-b3f9-8f51-9733d563b1a4.jpeg alt="計算結果の表示">

:::note
上から
- $x=a$での$y$座標である **`f(a)`**
- $x=a$での微分係数である **`f'(a)`**
- $x=b$での$y$座標である **`f(b)`**
- $x=b$での微分係数である **`f'(b)`**
- 2つの接線の交点の$x$座標である **`x_inter`**
- 2つの接線の交点の$y$座標である **`y_inter`**
- 2つの接線の交点の座標(**`(x,y)表記`**)

です。

:::

</details>

# まとめ
関数の任意の2点の接線の交点の$x$座標と$y$座標を求め、その結果をもとに **`Python`** のライブラリである<font color="red">**`matplotlib`**</font>を用いて接線の交点を描画しました。
この記事をQiitaに投稿するかどうか迷ったが<font color="Red">**自分のやったことの整理のために有用である**</font>と考えたので投稿することにしました。
この記事が実際に役に立つかどうかは分からないですが、誰かの役に立ってくれると嬉しいです。
記事を執筆する余力があれば、次回も記事を投稿する予定です。
次回の予定としては、**中心差分を用いて画像の<font color="Red">**画素ごとの微分**</font>を行ってその結果を Pythonのライブラリである<font color="Red"> **`OpenCV`** </font>を用いて表示させた**のでそれに関する記事を投稿する予定です。