[SymPy] 数式の簡略化

[SymPy] 数式の簡略化

数式の簡略化

 SymPy には数式を 簡略化 (simplification) するための色々な関数が用意されています。

sympy.simplify()

 sympy.simplify() は最も適切だと思われる簡略化関数を自動選択して適用します。
 アバウトな指定方法なので、必ずしも思った通りの結果が得られるとは限りませんが、簡略化の傾向を知っておけば、それなりに使い勝手の良い関数です。最初に simplify() をトライして、必要であれば個々の簡略化関数で細かな微調整を施すようにします。下に simplify() による簡約化の例をいくつか挙げておきます。

 多項式はベキ乗順に並び替えられます:

# SIMPLIFY-1

from sympy import *

# a,b,c,d,x,yを記号として定義
var ("a b c d x y")

expr = d + b*x**2 + a*x**3 + c*x

# 数式を簡略化
expr = simplify(expr)

print(expr)
a*x**3 + b*x**2 + c*x + d

 数式全体の共通因子があれば括ります:

# SIMPLIFY-2

expr = a*x + a*b*y + a*b + a

# 数式を簡略化
expr = simplify(expr)

print(expr)
a*(b*y + b + x + 1)

 約分可能であれば、約分して返します:

# SIMPLIFY-3

# 分数式を定義
expr = (x**3 - 7*x**2 + 7*x + 15) / (x + 1)

# 簡略化(約分)
expr = simplify(expr)

print(y)
x**2 - 8*x + 15

 指数関数の積を渡すと指数部分を1つにまとめます:

# SIMPLIFIY-4

# 指数関数の積
expr = exp(a)*exp(2*a)*exp(b)

# 簡略化(指数をまとめる)
expr = simplify(expr)

print(y)
exp(3*a + b)

 三角関数の公式が適用できるところはまとめます:

# SIMPLIFY-5

# 三角関数の積
expr = 2*sin(x)*cos(x)

# 簡略化(倍角公式)
expr = simplify(expr)

print(expr)
sin(2*x)

 分数式の分母に無理数が含まれていれば有理化します:

# SIMPLIFY-6

expr = 1 / (3 + sqrt(5))

# 分母を有理化
expr = simplify(expr)

print(expr)
3/4 - sqrt(5)/4

 simplify() は trigsimp() や radsimp() などの簡略化関数を複合的に適用します。

# SIMPLIFY-7

expr = (cos(x)**2 + sin(x)**2 + log(x) + log(a)) / (1 + sqrt(2))

# 数式を簡略化
expr = simplify(expr)

print(expr)
-log(a) + sqrt(2)*log(a) - log(x) + sqrt(2)*log(x) - 1 + sqrt(2)

 とはいえ、simplify() だけですべてが解決するわけではありません。
 上のコードの実行結果は共通項でまとまっていません。
 こういう場合は結果を見てから必要な簡略化関数を適用します。
 因数分解が可能かもしれないので、factor() を試します。

# SIMPLIFY-8

# 因数分解
expr = factor(expr)

print(expr)
(-1 + sqrt(2))*(log(a) + log(x) + 1)

 simplify() は対数関数の簡略化はしないので、必要であれば logcombine() で明示的に結合します。

# SIMPLIFY-9

# 対数関数を結合
expr = logcombine(expr, force=True)

print(expr)
(-1 + sqrt(2))*(log(a*x) + 1)

 こうした手続きを毎回実行するのは面倒なので、1つの関数としてまとめておくと便利です。

# SIMPLIFY-10

def simplify_2(expr):
    f = simplify(expr)
    g = factor(f)
    h = logcombine(g, force=True)
    return h

# 数式を定義
expr = (cos(x)**2 + sin(x)**2 + log(x) + log(a)) / (1 + sqrt(2))

# 数式を整理
expr = simplify_2(expr)

print(expr)
(-1 + sqrt(2))*(log(a*x) + 1)

 

separatevars()

 separatevars(expr) は数式を共通因子で括ります。

# SEPARATEVARS

from sympy import *
var ("a x")

y = x*log(x) + a*log(x) + log(x)**2

# 共通因子で括る
y = separatevars(y)

print(y)
(a + x + log(x))*log(x)

 

collect()

 collect(expr, syms) は数式 expr を syms で指定した記号のベキ順に整理します。

# COLLECT-1

from sympy import *
var ("a b c x")

y = c*x + a*x**3 + b*x**2

# yをxについて整理
y = collect(y, x)

print(y)
a*x**3 + b*x**2 + c*x

 複雑な項を指定して整理することもできます。

# COLLECT-2

y = a*sin(x) + sin(x)*cos(x) + b

# yをxについて整理
y = collect(y, sin(x))

print(y)
b + (a + cos(x))*sin(x)

 

ratsimp()

 ratsimp(expr) は分数の和で表された式を1つの分数にまとめます。

# RATSIMP

from sympy import *
var ("a:c")

expr = 1/a + 1/ b + 1/c

# 1つの分数にまとめる
expr = ratsimp(expr)

print(expr)
(a*b + a*c + b*c)/(a*b*c)

 

radsimp()

 sympy.radsimp() は分母を有理化します。

# RADSIMP-1

from sympy import *

var("a b x")

expr = a / (b + sqrt(2))

# 分母を有理化
expr = radsimp(expr)

print(expr)
a*(b - sqrt(2))/(b**2 - 2)

 分母が二重根号であっても有理化してくれます。

# RADSIMP-2

# 分母が二重根号を含む式
x = 1/sqrt(a + b + sqrt(a*b))

# 分母を有理化
x = radsimp(x)

print(x)
(a + b - sqrt(a*b))*sqrt(a + b + sqrt(a*b))/(a**2 + a*b + b**2)

 人間には手に負えないような有理化も難なく実行してくれます。
 三重根号を含む式を有理化してみましょう。

# RADSIMP-3

init_printing()

# 分母が三重根号を含む式
x = 1/sqrt(11 + sqrt(6 + sqrt(19)))

# 分母を有理化
x = radsimp(x)

print(x)
\[\frac{\sqrt{\sqrt{\sqrt{19} + 6} + 11} \left(- 115 \sqrt{\sqrt{19} + 6} - \sqrt{19} \sqrt{\sqrt{19} + 6} + 11 \sqrt{19} + 1265\right)}{13206}\]

 

rad_rationalize()

 rad_rationalize(num, den) に分子と分母を渡すと、分母が有理化された分数をタプル表式で返します。

# RATIONALIZE

from sympy.simplify.radsimp import rad_rationalize

# (num,den)=(1,1+sqrt(2))を有理化
y = rad_rationalize(1, 1 + sqrt(2))

print(y)
(-1 + sqrt(2), 1)