SymPy

 

 

Advertisement

SymPyの基本的な使い方

 SymPy とは Symbol (記号) による演算、すなわちコンピュータで代数演算を実行する機能を備えた計算機代数システム (CAS ; Computer Algebra System) です。

記号の定義

 x を記号として定義すると、x ** 2 + 1 のような式を x の多項式として扱うことができます。記号の定義には次の 2 通りの方法があります。

x = sympy.Symbol('x')
sympy.var('x')

 複数の記号を定義することもできます。

(x, y) = sympy.symbols('x y')
sympy.var('x y')

 生成されたオブジェクトは sympy.core.symbol.Symbolクラスに属しますが、当サイトではこのクラスに属するオブジェクトを簡単に Symbol と記述します。

# In[1]

# sympyをインポート
import sympy

# Symbolクラスのインスタンスを生成(記号の定義)
sympy.var('x')

# 多項式を定義
expr = x ** 2 + 1

print(expr)
print(type(x))
x**2 + 1
<class 'sympy.core.symbol.Symbol'>

 
 記号に数値を代入するときは subs() メソッドを用います。

# In[2]

# xに3を代入
val = expr.subs(x, 3)

print(val)
10

 複数の記号に数値を代入するときは、(記号, 数値) のタプルを要素に持つリストを渡します。

# In[3]

# 記号yを定義
sympy.var('y')

# 多項式zを定義
z = x ** 2 + 2 * x * y + y ** 2

# xに3, yに5を代入
z = z.subs([(x, 3), (y, 5)])

print(z)
64

 
 数式同士で加減乗除を実行することもできます。

# In[4]

# 記号 a, b を定義
sympy.var('a b')

# 多項式f1を定義
f1 = a + 2 * b + 1
f2 = a + b + 5

print(f1 + f2)
2*a + 3*b + 6

 sympy.Rational() に分子と分母を渡すと、分数型(有理数型)インスタンスを生成することができます。正確なクラス名は sympy.core.numbers.Rational です。

# In[5]

# a = 3/5
a = sympy.Rational(3, 5)

# b = 1/7
b = sympy.Rational(1, 7)

# 分数の和を計算
print(a + b)
26/35

 

SymPy のバージョン確認とアップデート

 インストールされている SymPy のバージョンを確認したいときは __version__ 属性にアクセスしてください。

import sympy

# 現在の環境におけるSymPyのバージョンを確認する
print(sympy.__version__)
1.4

 SymPy を最新バージョンにアップデートする場合は、Anaconda プロンプトで以下のコマンドを打ちこみます。

> conda update sympy

 特定のバージョンをインストールする場合は以下のコマンドを実行してください。

> conda install sympy=1.2

 ただし、Anaconda 環境においては、単独パッケージのバージョン変更が他のライブラリとの依存関係を壊してしまう可能性があります。定期的に Anaconda 全体をアップデートすることをおすすめします。
 

検算に SymPy を活用しています

 姉妹サイト『Excel VBA 数学教室』の演習問題コーナーには "あとりえこばと" が作成したオリジナル問題が載っていたりしますが、万が一にも解答が間違っていたら大変なので(←何度も間違えているくせに)、ミスをなるべく減らすために検算に SymPy を活用しています。一例として、演習問題 SQ-28 を題材に Python の実践コードを紹介します。SQ-28 では複素数の和を計算します。

 Python において、複素数は complex型として扱います。
 下のサンプルは $2k-1+i^k$ の $k=10$ ~ $12$ の和をとる計算です。

# sの初期値
s = 0

# 虚数iを定義
cpx = 1j

# a_k = 2k - 1 + i**k の k = 10, 11, 12 の和をとる
for k in range(10, 13):
    s += 2 * k - 1 + cpx ** k

print(s)
(63-1j)

 complex型は a + bj のような形式で定義します。上のコードでは虚数 $i$ を cpx = 1j と定義してあります。わざわざ変数を使う理由は、1j のような文字が式の中に入り込んでしまうと、

  s += 2 * k - 1 + (1j) ** k

のようになって、目がちかちかしてして見えにくいからです。for文では range関数を使って 10, 11, 12 という数を順に生成しています。つい忘れがちですが、このような場合は range(10, 12) ではなく、range(10, 13) と記述します。

 次も複素数の和をとる計算です。先ほどより少し複雑で、
 
\[\sum_{M=1}^{12}\left\{M^2-\frac{(i-1)(i^M-1)}{2}\right\}\]
という計算をさせるコードです。

# SymPyによる検算例

# sの初期値
s = 0

# 虚数iを定義
cpx = 1j

for k in range(1, 13):
    s += k ** 2 - (cpx - 1) * (cpx ** k - 1) / 2

print(s)
(644+6j)

 $k$ について $1$ から $12$ の和をとるので、for文のイテラブルオブジェクトは range(1, 13) です。このコードで虚数を変数に置き換えていないと、

  s += k ** 2 - ((1j) - 1) * ((1j) ** k - 1) / 2

のようになって、目がちかちかちかっとなってしまいます。