Python: オイラーの公式

# はじめに
数学を利用したいのであれば、公式を丸覚えしたところでなんの足しにもならない。それは理解の拒絶であり、文字列として記憶しているだけだ。だが、理解するのが難しい場合も多いだろう。そういった時、私はpythonコードとして動かしながら何が起こっているかを確認しつつ理解している。本稿は、オイラーの公式についてpythonコードで実装し、何が起こっているかを確認しながらこの美しい公式への理解を深めていきたい。

# オイラーの公式
[wiki](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%A4%E3%83%A9%E3%83%BC%E3%81%AE%E5%85%AC%E5%BC%8F)より

数学の複素解析におけるオイラーの公式（オイラーのこうしき、英: Euler's formula）とは、複素指数函数と三角関数の間に成り立つ、以下の恒等式のことである：

$${\displaystyle e^{i x}=\cos x +i\sin x} $$

まずはこれをコードで記載し, y軸を実部, z軸を虚部として3次元上にプロットすることで確認していこう。

```python
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

x = np.linspace(-4*np.pi, 4*np.pi, 10000)
# 左辺
f = lambda x: np.e**(1j*x)
# 右辺
g = lambda x: np.cos(x) + 1j * np.sin(x)

fig = plt.figure(figsize=(10.0, 8.0))
ax = Axes3D(fig)

# 左辺をプロット
ax.plot(x, f(x).real, f(x).imag, "o", color='b', ms=5.0, label='e^ix')
# 右辺をプロット
ax.plot(x, g(x).real, g(x).imag, "o", color='r', ms=0.5, label='cos(x)+i*sin(x)')

ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.legend()
plt.show()
```

$e^{ix}$（青線）と$\cos x +i\sin x$（赤線）が一致することが確認できる。

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365961/d4c4d173-0889-add0-1b18-a99f986bd1d6.png)

これは何かと言うと、見る角度によっては先ほどのようなコイル状に見える。だが、以下の視点で見れば円運動であるし
※プロットする際少し歪んでしまうので綺麗にはならないですが…

```python
fig = plt.figure(figsize=(10.0, 8.0))
ax = Axes3D(fig)
# 視点をzy面にするとzとyの関係性は円運動に見える
ax.view_init(elev=0, azim=0)
ax.plot(x, f(x).real, f(x).imag, "o", color='b', ms=1.0, label='e^ix')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.legend()
plt.show()
```

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365961/ee7400ad-f7ea-772a-97b7-1c728b4e57b6.png)


以下の視点で見れば$sin$波であるし

```python
fig = plt.figure(figsize=(10.0, 8.0))
ax = Axes3D(fig)
# 視点をxz面にすると、xが変化した際のzの変化はsin波に見える
ax.view_init(elev=0, azim=-90)
ax.plot(x, f(x).real, f(x).imag, "o", color='b', ms=1.0, label='e^ix')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.legend()
plt.show()
```

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365961/000eb9f3-a27d-7543-61fc-7ff957b0efa9.png)


以下の視点で見れば$cos$波であるし

```python
fig = plt.figure(figsize=(10.0, 8.0))
ax = Axes3D(fig)
# 視点をxy面にすると、xが変化した際のyの変化はcos波
ax.view_init(elev=90, azim=-90)
ax.plot(x, f(x).real, f(x).imag, "o", color='b', ms=1.0, label='e^ix')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.legend()
plt.show()
```

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365961/0be6e938-cf90-e2ad-e959-73892580461f.png)


z軸方向から見た仰角(elev)を変えることは位相を変化させることに等しい。

```python
fig = plt.figure(figsize=(10.0, 8.0))
ax = Axes3D(fig)
# sin波とcos波はコイルを上から見るか手前から見るかで、これは斜めから見ている
ax.view_init(elev=45, azim=-90)
ax.plot(x, f(x).real, f(x).imag, "o", color='b', ms=1.0, label='e^ix')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.legend()
plt.show()
```

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365961/eaf4207a-779a-43a4-5030-42cede98bc44.png)

何が言いたいかというと、コイル（ばね）をある方向から見ると円だが、横から見ると波に見えて、ばねをくるくる回すと位相が変化していくということである。

# 余弦関数、正弦関数

実部と虚部の変化については3次元的に見るより色分けしてみたほうがわかりやすいので、以下のように色分けしながら見ていく。
※ラベルのrealは実部, imagは虚部を示している。

```python
plt.figure(figsize=(10.0, 5.0))
plt.plot(x, f(x).real, linewidth=3.0, c='r', label='e^ix : real')
plt.plot(x, f(x).imag, linewidth=3.0, c='g', label='e^ix : imag')
plt.legend()
plt.show()
```

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365961/ca835ad5-1d7b-b879-fb2f-8f3b92c1ebfe.png)

オイラーの公式により、三角関数を複素指数関数で表すことができる。余弦関数、正弦関数は

$${\displaystyle {\begin{aligned}\cos x&={\frac {e^{ix}+e^{-ix}}{2}},\\
\sin x&={\frac {e^{ix}-e^{-ix}}{2i}}\end{aligned}}}$$

ということなので、まず $\cos x$ から確認する。  
まず$x$に$-1$をかけると、かける前と比較し実部（赤と青）は一致するが、虚部（緑と黄）が反転しているので加算することで虚部が$0$になる。そして、実部は2倍になるので2で割ると$\cos x$になるわけだ。

```python
plt.figure(figsize=(10.0, 5.0))
plt.plot(x, f(x).real, linestyle='dashed', linewidth = 3.0, c='r', label='e^ix : real')
plt.plot(x, f(x).imag, linestyle='dashed', linewidth = 3.0, c='g', label='e^ix : imag')
plt.plot(x, f(-x).real, linewidth=1.0, c='b', label='e^-ix : real')
plt.plot(x, f(-x).imag, linewidth=1.0, c='y', label='e^-ix : real')
plt.legend()
plt.show()
```

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365961/282a81dd-1447-3991-8624-4a7d41792a3d.png)

つぎに、さらに外から-1をかけると、今度は虚部（緑と黄）が一致するが、実部（赤と青）が反転しているので加算すると実部が0になる。そして虚部は2倍になるので2iで割るとsinになるわけだ。

```python
plt.figure(figsize=(10.0, 5.0))
plt.plot(x, f(x).real, linestyle='dashed', linewidth = 3.0, c='r', label='e^ix : real')
plt.plot(x, f(x).imag, linestyle='dashed', linewidth = 3.0, c='g', label='e^ix : imag')
plt.plot(x, -1*f(-x).real, linewidth=1.0, c='b', label='e^-ix : real')
plt.plot(x, -1*f(-x).imag, linewidth=1.0, c='y', label='e^-ix : real')
plt.legend()
plt.show()
```

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365961/3f54b5d8-108e-375a-21ba-6ad83ea1e742.png)


これはcos(赤線)が以下のようにy軸に関して対称であることから、xの符号によって値が変化しない性質を持ち、sin(緑)が原点に関して対称であることから、xに符号がかわるとyの符号も変わる性質を持つためである。

```python
plt.figure(figsize=(10.0, 5.0))
plt.plot(x, np.cos(x), c='r', label='cos(x)')
plt.plot(x, np.sin(x), c='g', label='sin(x)')
plt.axvline(x=0, c='b')
plt.legend()
plt.show()
```

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365961/8cfe4992-61f9-e2f2-0114-da900806e2d2.png)

つまり、xにマイナスをかけて和をとれば、sinは打ち消しあって0となり、cosは一致するので2倍になる。

```python
plt.figure(figsize=(10.0, 5.0))
plt.plot(x, np.cos(x)+np.cos(-x), c='r', label='cos(x)')
plt.plot(x, np.sin(x)+np.sin(-x), c='g', label='sin(x)')
plt.axvline(x=0, c='b')
plt.legend()
plt.show()
```

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365961/ee5da4db-b083-b2f7-0b9b-3a29fb559a77.png)

差を取ればcosは打ち消しあって0となり、sinは一致するので2倍になる。

```python
plt.figure(figsize=(10.0, 5.0))
plt.plot(x, np.cos(x)-np.cos(-x), c='r', label='cos(x)')
plt.plot(x, np.sin(x)-np.sin(-x), c='g', label='sin(x)')
plt.axvline(x=0, c='b')
plt.legend()
plt.show()
```

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365961/ddb3b44a-781a-95f9-666c-d7aaad570d50.png)

# オイラーの等式

オイラーの公式は、複素数の極形式を簡明な表示に導く。すなわち、複素数の極形式 $z = r(\cos θ + i \sin θ)$ は $z = re^{iθ}$ に等しい。また、特に、θ = π のとき、

$$e^{i\pi}+1=0$$

実際に計算してみると計算誤差があるため0にはならないが、ほぼ0となる。

```python
np.e**(1j*np.pi) + 1
>>> 1.2246467991473532e-16j
```

これはつまり、 $x=\pi$ (青線)の時には実部(赤)が $-1$ となり虚部(青)が $0$ となるということ。

```python
x = np.linspace(-2*np.pi, 2*np.pi, 10000)
plt.figure(figsize=(10.0, 5.0))
plt.plot(x, np.cos(x), c='r', label='cos(x)')
plt.plot(x, np.sin(x), c='g', label='sin(x)')
plt.axvline(x=0, linestyle='dashed', linewidth=1.0, c='c')
plt.axvline(x=np.pi/2, linestyle='dashed', linewidth=1.0, c='c')
plt.axvline(x=np.pi, c='b')
plt.axvline(x=-np.pi/2, linestyle='dashed', linewidth=1.0, c='c')
plt.axvline(x=-np.pi, linestyle='dashed', linewidth=1.0, c='c')
plt.legend()
plt.show()
```

![img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365961/704615a4-0827-5f86-27d5-ae303b2061a2.png)

水色の破線部分も踏まえて整理すると。オイラーの等式に加えて以下も全て成り立つ。

$$e^{i\pi}+1=0$$

$$e^{i\frac{\pi}{2}}-i=0$$

$$e^{0}-1=0$$

$$e^{-i\frac{\pi}{2}}+i=0$$

$$e^{-i\pi}+1=0$$

実際に計算しても0となる（誤差には目をつぶってください）

```python
np.e**(1j*np.pi) + 1
>>> 1.2246467991473532e-16j

np.e**(1j*np.pi/2) - 1j
>>> (6.123233995736766e-17+0j)

print(np.e**0 - 1)
>>> 0.0

print(np.e**(-1j*np.pi/2) + 1j)
>>> (6.123233995736766e-17+0j)

print(np.e**(-1j*np.pi) + 1)
>>>-1.2246467991473532e-16j
```

# 最後に

いかがだったでしょうか？実際にpythonを使い動かしながら見ていくと、それが何を表しているのかわかりやすくワクワクしてこないでしょうか？ノートに公式を書いて暗記するのもいいですが、プログラムの勉強をしながら一緒に倒すのもまたいいものです。数学とプログラミングを一緒に学ぶモチベーションになったのであれば(・∀・)ｲｲﾈ!!でも押していただければ幸いです。それではアデュー(´っ･ω･)っ