微分積分をプログラミングで学ぼう！（Python - Sympy）

# 1. 微分の仕方
### 1.1 一般的な微分

```math
y = x^2 + 2x + 1
```

という関数があったとします。
微分も関数によって解き方が異なりますが、一般的には次のように計算します。

:::note
【微分の計算方法】
```math
\frac{d}{dx}x^n = n\cdot x^{n-1}
```
:::

$\frac{d}{dx}$は<font color="red">$x$で微分するという意味</font>です。
上記の微分法に基づいて最初の式を微分すると、

```math
\begin{align}
y' &= \frac{d}{dx}(x^2+2x+1)\\
&= \frac{d}{dx}(x^2)+\frac{d}{dx}(2x)+\frac{d}{dx}(1)\\
&= \frac{d}{dx}(x^2)+\frac{d}{dx}(2x)+\frac{d}{dx}(x^0)\\
&= (2\cdot x^{2-1})+(1\cdot 2x^{1-1})+(0\cdot x^{0-1})\\
&= 2x+2+0\\
&=2x+2
\end{align}
```
となります。

**他にも「合成関数」「三角関数」などといったものは、少し違った解き方になりますので、ご注意ください。**

### 1.2 合成関数の微分
合成関数の場合、

```math
y = \log(u),\; u=g(x)
```

と考えます。
例として、$y=\log(x^2+1)$とかを考えると良いでしょう。
この場合、$y = f(x)$と書き表すことができ、<font color="red">**$y$は$x$の関数**</font>です。
ここで、${\color{blue}{u=x^2+1}}$と置くと、${\color{blue}{y=\log u}}$となります。
このとき、**$y=f(u)$となり、$y$は$u$の関数（$y=f(u)$）、また$u$は$x$の関数（$u=g(x)$）**になります。ですが、$y=f(u)$より、$y=f(u)=f(g(x))$より<font color="red">**$y$は$x$の関数**</font>と言えます。

このような合成関数の場合、微分をするには次のように計算します。

```math
\begin{align}
\frac{d}{dx}y &= \frac{d}{dx}(\log u)\\
y' &= \frac{d}{du}(\log u)\cdot \frac{d}{dx}{\color{red}{u}}\tag{1}\\
&= \frac{d}{du}(\log u)\cdot\frac{d}{dx}({\color{red}{x^2+1}})\\
&= \frac{1}{u}\cdot(\color{red}{2x})\\
&= \frac{{\color{red}{2x}}}{x^2+1}
\end{align}
```

:::note
【合成関数の微分法】
$y=f(u)$, $u=g(x)$がいずれも微分可能なとき、
```math
y' = \frac{dy}{dx} = {\color{red}{\frac{dy}{du}\frac{du}{dx}}}
```
:::

### 1.3 三角関数の微分
三角関数$\sin x$, $\cos x$, $\tan x$の場合は暗記するだけで良いです。

:::note
【三角関数の微分】
- $y = \sin x \leftrightarrow y' = \cos x$
- $y = \cos x \leftrightarrow y' = -\sin x$
- $y = \tan x \leftrightarrow y' = \frac{1}{\cos^2 x}$
:::

となります。

# 2. 積分
### 2.1 不定積分
「**微分の反対は積分だ！**」ということを耳にしたことがある人も多いと思います。
半分正解です。正しくは「**微分の反対は不定積分**」と言うべきだと思います。

つまり、<font color="red">**先ほど微分した関数$y=x^2+2x+1$は$y'=2x+2$となり、これを不定積分すると$y=x^2+2x+1$に戻るはず**</font>です。

一般的に積分は次のような公式で計算します。

:::note
$\int f(x)dx = F(x)$とすると、

```math
\int x^n\;dx = \frac{1}{n+1}x^{n+1}
```
:::

では、この公式を元に先ほど微分した関数（導関数）を不定積分してみましょう。

```math
\begin{align}
\int(2x+2)\;dx &= \bigg\{2\cdot\frac{1}{1+1}x^{1+1}+2\cdot\frac{1}{0+1}x^{0+1}\bigg\}\\
&= x^2+2x
\end{align}
```

積分してみると、確かに微分する前の値に戻りかけましたが、<font color="red">**「$+1$」が戻っていません！！**</font>

この結果から分かるように、積分では完全に元に戻らないものがあります。それが「**定数**」です。
これだけは元に戻せません。

そのため、不定積分では積分したあとの関数に定数があることを考慮して「**積分定数**」というものを付けます。

:::note warn
よって、$F'(x) = f(x)$とするとき、
```math
\int f(x)\;dx = F(x) + C
```
（$C$は積分定数）
:::

つまり、先程解いた不定積分は$x^2+2x+C$（$C$は積分定数）と書くのが正しいです。

この他にも「**置換積分**」「**部分積分**」などがありますが、今回は割愛します。

### 2.2 定積分
さて、最後のお話です。
定積分は不定積分と何が違うのでしょうか？
定積分は積分区間[$a$, $b$]を定め、その区間内で関数を積分します。その時に値を得ることができます。その値が「**面積**」です。

ではまとめてみます。

:::note
【定積分とは】
区間[$a$, $b$]内で関数$f(x)$を積分して面積を求めます。
:::

では、定積分の公式を紹介します。

:::note
$\int f(x)dx = F(x)$とするとき、区間[$a$, $b$]で積分すると、
```math
\begin{align}
\int_a^b f(x)\;dx &= [F(x)]_a^b\\
&=F(b) - F(a)
\end{align}
```
:::

では、$f(x) = 2x+2$を区間[$0$, $1$]で定積分してみましょう。

```math
\begin{align}
\int_0^1(2x+2)\;dx &= \bigg[x^2+2x\bigg]_0^1\\
&=\bigg[x^2\bigg]_0^1 + \bigg[2x\bigg]_0^1\\
&=\bigg[1^2-0^2\bigg] + \bigg[2(1-0)\bigg]\\
&=1+2\\
&=3
\end{align}
```

これで微分、積分ができるようになりましたね！！？
では、ここからはPythonを用いて数式計算をできるようにしてみましょう。

**【推奨】
環境 : Google Colaboratory**

# 3. Pythonで微分積分いい気分！（Sympy使用）
ではPythonを使える環境を立ち上げてください。
おすすめは**Google Colaboratory**です。
今回はWSL2で動かしますが、Google Colabの方が今回に関しては使いやすいと思うので、使える方はそちらを使用してみてください。

```python
import sympy as sp
```

これを1行目に書きます。
今回は「<font color="purple">**Sympy**</font>」と呼ばれるものを使用します。これを利用すれば簡単に微分積分や線形代数などの数学計算ができます。

【[参考 : SymPyの使い方](https://gochikika.ntt.com/Features/SymPy.html#id54)】

### 3.1 四則演算（Sympyは必要なし）
- 足し算
    ```python
    # a + bの計算結果
    a + b
    ```
- 引き算
    ```python
    # a - bの計算結果
    a - b
    ```
- 掛け算
    ```python
    # a × bの計算結果
    a * b
    ```
- 割り算
    ```python
    # a ÷ bの計算結果
    a / b
    ```
### 3.2 分数
$\frac{a}{b}$をPythonで表示したいとき、次のように書きます。
```python
sp.Rational(a,b)
```

### 3.3 べき乗（Sympyは必要なし）
$a^n$をPythonで表示したいとき、次のように書きます。
```python
a**n
```

### 3.4 平方根
$\sqrt{a}$をPythonで表示したいとき、次のように書きます。
```python
sp.sqrt(a)
```
また、$a=12$のような数の場合、$\sqrt{12} = 2\sqrt{3}$のように簡単にしてくれます。

### 3.5 円周率・ネイピア数・∞
円周率（$\pi$）をPythonで表示したいとき、次のように書きます。
```python
sp.pi
```

ネイピア数（$e$）をPythonで表示したいとき、次のように書きます。
```python
sp.E
```

$\infty$をPythonで表示したいとき、次のように書きます。
```python
sp.oo
```

### 3.6 変数
やはり数学では欠かせないのが「変数」です。
先ほどまで微分積分の解き方を紹介した際は「$x$」を変数として扱いましたね！
今回はPythonでも$x$を変数として扱いますので、次のように書きます。
```python
# xを変数として扱えるように設定
x = sp.symbols("x")
```

### 3.7 微分
先ほどまで微分していたとき、
```math
\frac{d}{d{\color{red}{x}}}
```
と書いていました。これは、<font color="red">$x$</font>で微分するという意味でした。
今回はPythonでも$x$で微分するようにします。
$x^2+2x+1$を$x$で微分するには次のように書きます。
<font color="red">**第2引数は$x$で微分することを意味する変数**</font>を書きます。
```python
sp.diff(x**2+2*x+1, x)
```

また、2階微分する場合は第3引数に「2」と書きます。
```python
sp.diff(x**2+2*x+1, x, 2)
```

### 3.8 積分
まずは不定積分の仕方を紹介します。
<font color="red">**第2引数には$x$で積分するということを意味する変数**</font>を書きます。
```python
sp.integrate(2*x+2, x)
```
**実行結果**
> $x^2+2x$

（※積分定数は表示されません。）

次に定積分の仕方を紹介します。
<font color="red">**第2引数には「積分することを意味する変数」「開始区間」「終了区間」**</font>を書きます。
```python
sp.integrate(2*x+2, (x,0,1))
```
今回は先程の例題を元に区間[$0$, $1$]の場合を書いてみました。
**実行結果**
> 3

# 4. プログラミングに挑戦！
ここからはこれらの知識を使って、微分・積分するプログラムを作成してみます。
```python:diff_and_integral.py
import sympy as sp
x = sp.symbols("x")	# xを変数に設定

def func1():
	F = str(input("微分する式を入力 > "))
	f = sp.diff(F, x)
	print(f)

def func2():
	f = str(input("不定積分する式を入力 > "))
	F = sp.integrate(f, x)
	print(F)

def func3():
	f = str(input("定積分する式を入力 > "))
	a = str(input("区間の「開始」を入力 > "))
	b = str(input("区間の「終了」を入力 > "))
	F = sp.integrate(f, (x, a, b))
	print(F)

def main():
	selection = int(input("1:微分, 2:不定積分, 3:定積分 > "))
	print()
	if selection == 1:
		func1()
	elif selection == 2:
		func2()
	elif selection == 3:
		func3()
	else:
		print("正しい値を入力してください。")

if __name__ == "__main__":
	main()

```

**実行結果**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925398/a76444c4-b4d7-6676-7711-89231e25c78a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925398/b37e7648-47ba-c4fd-9777-8c4d99af1262.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925398/b71dc378-dcc9-4424-de84-8da900f882c8.png)