Sympy+Jupyterで最強の電卓環境を作る

Sympy + Jupyterで最強の電卓環境を作ってみましょう。

# Sympyとは？
[Sympy](http://www.sympy.org/en/index.html)はPythonで書かれた代数計算ライブラリで、MathematicaやMaximaみたいなものと思ってください。
Pythonで数式を書けるのでプログラマにとってはこちらの方が使いやすいです、下記のページは素晴らしいSympy入門です、Sympyを知らない方はご一読ください。

[3.2. Sympy : Python での代数計算](http://www.turbare.net/transl/scipy-lecture-notes/packages/sympy.html)

# JupyterからSympyを使う

特に特別な事をする必要はないのですが、Jupyterの最初のセルに数式とグラフを表示するために'おまじない'を打ちます。

```python
from sympy import *
init_printing()
```

次に数式を打ってみましょう。

```python
x = Symbol('x')
y = Symbol('y')
Rational(3 ,2)*pi + exp(I*x) / (x**2 + y)
```

$$\frac{3 \pi}{2} + \frac{e{i x}}{x{2} + y}$$

数式が出れば成功です。

![Untitled - Google Chrome_021.png](https://qiita-image-store.s3.amazonaws.com/0/140075/102218c2-e4b2-75ee-8d99-78b8b27f8e50.png)

## init_session()について

@void99_ さんからの情報で`init_printing`よりも高機能な`init_session`というものがあるそうです。

```python
from sympy import *
init_session()
```

よく使う変数、関数があらかじめ定義されます、便利ですね。

```
IPython console for SymPy 1.0 (Python 3.5.2-64-bit) (ground types: python)

These commands were executed:
>>> from __future__ import division
>>> from sympy import *
>>> x, y, z, t = symbols('x y z t')
>>> k, m, n = symbols('k m n', integer=True)
>>> f, g, h = symbols('f g h', cls=Function)
>>> init_printing()

Documentation can be found at http://docs.sympy.org/1.0/
```

# シンボルの設定
数式のシンボルは`Symbol'で設定できます。

```python
x = Symbol('x')
y = Symbol('y')
```

複数のシンボルは`symbols`を使えば、一気に設定も可能です。

```python
x, y = symbols("x y")
```

他にも`sympy.abc`モジュールを使って設定も可能です。

```python
from sympy.abc import x, y
```

# 数式の簡素化

電卓として扱う場合に一番便利な機能は数式の簡素化でしょう、数式をこねくりまわしているとすごく長い数式ができてしまうのですが、Sympyを使えば一発です。

例えば以下の数式があったとしましょう。
この数式は、たしか私がベジェ曲線の数式か何かこねくりまわして出た数式です。

```
(A-B)*C + B**2 + (-B-A)*C + B**2
```
Sympyで書くと以下のようになります。

```python
from sympy.abc import A, B, C
f = (A-B)*C + B**2 + (-B-A)*C + B**2
```

```math
2 B^{2} + C \left(- A - B\right) + C \left(A - B\right)
```

Sympyに式を代入すると、見やすいように項を並び替えてくれます。
さらに数式の簡素化したい場合は`simpfly`を使います。

```python
simplify(f)
```
```math
2 B \left(B - C\right)
```

`A`が消えて、ものすごく簡素になりましたね。
Maximaでよく使う`ratsimp`も使えます。

```python
ratsimp(f)
```
```math
2 B^{2} - 2 B C
```

式の簡素化には色々な種類があります、詳細は以下を参照してください。

http://docs.sympy.org/dev/modules/simplify/simplify.html

# 方程式を解く
```python
from sympy.abc import A, B, C, D

(A-B)*D + C**2 + (-B-A)*C+B**2
```
```math
B^{2} + C^{2} + C \left(- A - B\right) + D \left(A - B\right)
```

上の数式で`A`について解きたい場合、`solve`を使います。

```python
solve((A-B)*D + C**2 + (-B-A)*C+B**2, A)
```
```math
\left [ \frac{1}{C - D} \left(B^{2} - B C - B D + C^{2}\right)\right ]
```

# 式の変数に値を代入する

`subs`で式の変数に値を代入できます。

```python
f = (A-B)*D + C**2 + (-B-A)*C+B**2

# A,B,Cに値を代入する
f.subs([(A, 10), (B, 20), (C, 30)])
```
```math
- 10 D + 400
```

`subs`の引数は辞書を渡すこともできます。

```python
f.subs({A: 10, B: 20, C: 30})
```

```math
- 10 D + 400
```

代入したい変数が1しかない場合は、第1引数に変数、第2引数に値を指定可能です。

```python
f.subs(A, 10)
```
```math
B^{2} + C^{2} + C \left(- B - 10\right) + D \left(- B + 10\right)
```


# 微分/偏微分
微分/偏微分は`diff`を使います。

```python
diff(x**2 + 3*x + 100)
```
```math
2 x + 3
```

偏微分の場合は第2引数を指定します。

```python
diff(3*x**2 + 3*x*y + y**2, x)
```
```math
6 x + 3 y
```

# 因数分解/素因数分解
因数分解は`factor`を使います。

```python
factor(x**2-x-6)
```

```math
\left(x - 3\right) \left(x + 2\right)
````

素因数分解は`factorint`を使います。

```python
factorint(3417)
>>> {3:1,17:1,67:1}
```
辞書が返ってます、`3^1 * 17^1 * 67^1 = 3417`という事になります。

# 行列/ベクトル
`Matrix`クラスを使います。

```python
Matrix([[1, 0], [0, 1]])
```
```math
\left[\begin{matrix}1 & 0\\0 & 1\end{matrix}\right]
```

ベクトルはあるにはあるんですが、使いにくいので1列の行列として扱います。

```python
θ = Symbol("θ")

P = Matrix([2*cos(θ), 2*sin(θ)])
```
```math
\left[\begin{matrix}2 \cos{\left (θ \right )}\\2 \sin{\left (θ \right )}\end{matrix}\right]
```

ベクトルの演算をする場合は`transpose`関数で転置させます。

```python
transpose(P) * P
```
```math
\left[\begin{matrix}4 \sin^{2}{\left (θ \right )} + 4 \cos^{2}{\left (θ \right )}\end{matrix}\right]
```

# 数式をLatexでコピペする

JupyterとSympyを使えば、出力された数式をQiitaに簡単にコピペできます。
数式を右クリックし「Show Math As」→「Tex Commands」を選択します。

![メニュー_013.png](https://qiita-image-store.s3.amazonaws.com/0/140075/f258cefe-b4ec-3667-4c8a-3a1d7f040375.png)

こんなポップアップが出てくるので、数式をコピペします。

![MathJax Equation Source - Google Chrome_015.png](https://qiita-image-store.s3.amazonaws.com/0/140075/695674ed-b176-714f-591f-65a8608f6166.png)

このLatexはQiitaにそのまま貼り付け可能なので便利です。

# AAで数式を出力する

`pprint`を使えば、アスキーアート？で数式も出力できます。

```python
pprint(Integral(sqrt(1/x), x), use_unicode=True)
"""
⌠           
⎮     ___   
⎮    ╱ 1    
⎮   ╱  ─  dx
⎮ ╲╱   x    
⌡  
"""
```         

ソースコードに数式を貼り付けるときに便利・・・なんでしょうか。

# グラフを書く

`sympy.plotting.plot`でグラフを描くことができます。
`Sympy`の数式をそのまま引数に渡せるので便利です。

```python
from sympy.plotting import plot

y = -(x+2)*(x+1)*(x-1)

# xが-4から4までのグラフを描く
plot(y, (x, -4, 4))
```

![ダウンロード (9).png](https://qiita-image-store.s3.amazonaws.com/0/140075/beca4d0e-64a1-5c43-2061-ce3739a95be2.png)



# .ipynbのテンプレートで素早く開始する

Jupyter + Sympyはすごく便利なのですが、１セル目に`おまじない`を毎回打ち込まなくてはなりません。
これって意外と面倒なんですよね。

私の記事で[PythonでJupyterノートブック「.ipynb」を生成する](http://qiita.com/pashango2/items/589522868a27ccdfdc55)があります。
これを使って.最初から色々入力済みのipynbを生成するスクリプトを書いてみましょう。

### JupyterとPyCharmの連携
[PyCharm](https://www.jetbrains.com/pycharm/)はPythonの統合開発環境(IDE)です、非常に強力な補完機能を持っており最強のPython開発環境です。
実はPyCharmはJupyterと連携が可能で、Jupyterの表現力＋PyCharmの強力な補完機能はかなり快適です。

![メニュー_011.png](https://qiita-image-store.s3.amazonaws.com/0/140075/5e923ba5-b74a-4db8-5a53-c7ce84d58b9c.png)

ただし、数式を扱う場合はPyCharmのJupyter出力は貧弱ですので、ブラウザ版のJupyterを使った方がよいでしょう。
ですので、PyCharmのJupyterは使いません、かわりに`Extranal Tools`を使います。

### .ipynb生成スクリプトを作る

どこか参照しやすい場所に以下のスクリプトを作成します。

```python
#!/usr/bin/env python3
# coding:utf-8
import sys
import os
import nbformat

output_dir = sys.argv[1]
output_file = input("input ipynb name:")

nb = nbformat.v4.new_notebook()

title = "# タイトル"

code = """
%matplotlib inline
from sympy import *
init_session()
"""

nb["cells"] = [
    nbformat.v4.new_markdown_cell(title),
    nbformat.v4.new_code_cell(code)
]

if not output_file.endswith(".ipynb"):
    output_file += ".ipynb"

with open(os.path.join(output_dir, output_file), "w") as f:
    nbformat.write(nb, f)

print("ok.")
```

### PyCharmのExternal Toolとして登録する

PyCharmの「File(F)」メニューを開き、「Settings...」を選択します。

![メニュー_016.png](https://qiita-image-store.s3.amazonaws.com/0/140075/99409710-8747-b270-83df-d308cc1e13e0.png)

設定ダイアログの「Tools」→「External Tools」を選択して、「＋」ボタンを押します。

![Settings_017.png](https://qiita-image-store.s3.amazonaws.com/0/140075/693e1a3e-d087-0684-41f1-6e54623abf50.png)

設定ダイアログが出るので、以下の項目を追加します。

| 項目 | 入力 |
|:-:|:--|
| Name  | 適当な名前を入れてください  |
| Description  | 適当な説明をいれてください  |
| Program  | JupyterがインストールされているPythonパス  |
| Parameters  | 先ほどのスクリプトパス \$FileDir\$  |

![Edit Tool_018.png](https://qiita-image-store.s3.amazonaws.com/0/140075/d1cff633-afdf-3d8d-080e-5c7d230ce2a0.png)

### PyCharmの右クリックメニューから.ipynbが生成可能に！

PyCharmの右クリックメニューから「External Toos」→「登録したツール名」を選択します。

![メニュー_019.png](https://qiita-image-store.s3.amazonaws.com/0/140075/b4841a0f-5540-e535-c499-af901a1c380d.png)

コンソールにファイル名を入力すると、最初から色々入力済みの.ipynbファイルが生成されます。

![python35 - [~-PycharmProjects-python35] - ...-document-document.ipynb - PyCharm Community Edition 2016.3.2_020.png](https://qiita-image-store.s3.amazonaws.com/0/140075/838d7aa6-2c04-0a44-2bb4-a8707f993f8f.png)

もっと便利な使い方がありましたら、是非とも投稿してください。

# あとがき
Sympyよりも.ipynbの出力の方が説明長かったですが、Sympyは非常に便利です。

ゲームプログラマや数式を使う人たちには凄い役に立ちます。
数学が苦手な人にこそ是非とも使ってほしいライブラリです。