在前一篇文章中,我们简单学习了SymPy
及其符号和假设系统,表达式、(不)等式、常用函数和运算符。本篇我们将了解SymPy
丰富多彩的输出方式、表达式的化简、合并和展开方法及一些需要注意的限制。
「SymPy」符号运算(1) 简介/符号/变量/函数/表达式/等式/不等式/运算符
首先在脚本中导入SymPy
库:
from sympy import init_session
init_session()
'''
These commands were executed:
>>> 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()
'''
SymPy
提供了多种输出效果,可以输出普通的表达式字符串、由符号排版形成的公式、 LaTeX \LaTeX LATEX文本和图片、MathML
格式文本等1。
Jupyter Notebook
或Spyder
交互界面直接输入表达式并执行,将输出 LaTeX \LaTeX LATEX渲染后的公式x**2 + log(y) + exp(sqrt(z))
输出:
# 禁用LaTeX渲染输出
init_printing(use_latex=False)
x**2 + log(y) + exp(sqrt(z))
# 2 √z
# x + ℯ + log(y)
pprint()
pprint((x + 1)**2, use_unicode=False) # 改为True输出结果不变
# 2
# (x + 1)
pretty()
pretty((x + 1)**2, use_unicode=True)
# ' 2\n(x + 1) '
pretty((x + 1)**2, use_unicode=False)
# ' 2\n(x + 1) '
str
print(str(Integral(sympy.sqrt(1/x), x)))
# Integral(sqrt(1/x), x)
latex(x**2 / exp(y))
# 'x^{2} e^{- y}'
MathML
输出from sympy.printing.mathml import print_mathml
print_mathml(Integral(sqrt(1/x), x))
print(mathml(Integral(sqrt(1/x), x))) # 输出字符串形式的MathML
Dot
格式输出from sympy.printing.dot import dotprint
from sympy.abc import x
print(dotprint(x+2))
.subs(,
将表达式中的变量替换为某个值
x, y, z = symbols('x y z')
# 定义表达式
expr1 = x**2 + 1
# 获得x=1.5时表达式的值
print(expr1.subs(x, 1.5))
expr2 = x**3 + 4*x*y - z
expr2.subs([(x, 2), (y, 4), (z, 0)])
.subs(/
将表达式中的变量替换为另一个变量,甚至表达式
x, y, z = symbols('x y z')
expr1 = cos(x) + 1
expr1.subs(x, y)
# cos(y)
# 替换多项式中x的偶次幂项变量为y
expr2 = x**4 - 4*x**3 + 4*x**2 - 2*x + 3
replacements = [(x**i, y**i) for i in range(5) if i % 2 == 0]
expr2.subs(replacements)
# -4*x**3 - 2*x + y**4 + 4*y**2 + 3
.evalf(subs=
,保留N
位有效数字
x = Symbol('x')
expr1 = 2*x + 1
print(expr1.evalf(subs = {x:2}, n=5))
# 5.0000
sympy.lambdify()
函数,获得多个节点的函数值
import numpy
import sympy
a = numpy.arange(10)
expr = sympy.sin(x)
f = sympy.lambdify(x, expr, "numpy")
print(f(a))
# [ 0. 0.84147098 0.90929743 0.14112001 -0.7568025 -0.95892427
# -0.2794155 0.6569866 0.98935825 0.41211849]
在SymPy
中除了 x − x = 0 x-x=0 x−x=0或 8 = 2 2 \sqrt{8}=2\sqrt{2} 8=22这类显而易见的简化外,其他的简化过程并不自动进行。
并且注意==
运算符不能判断两个表达式变化之后是否相等,.equals()
函数会随机取一些点计算两个表达式,从而判断二者是否相等:
(x + 1)**2 == x**2 + 2*x + 1
# False
((x + 1)**2).equals(x**2 + 2*x + 1)
# True
化简sympy.simplify()
函数
x = sympy.Symbol('x')
expr1 = (x**3+x**2-x-1)/(x**2+2*x+1)
expr2 = sympy.simplify(expr1)
print(expr2)
# x - 1
三角函数化简sympy.trigsimp()
函数
x = sympy.Symbol('x')
expr1 = sympy.trigsimp(sympy.sin(x)/sympy.cos(x))
print(expr1)
# tan(x)
指数化简sympy.powsimp()
函数
x = sympy.Symbol('x')
a,b = sympy.symbols(':b')
expr1 = sympy.powsimp(x**a*x**b)
print(expr1)
# x**(a + b)
正数化简posify()
函数,假设表达式中的不确定正负(positive=None
)的符号均为正数,进行化简;返回表达式(符号被替换为新的、假设为正数的符号)、原符号和新符号的映射字典
from sympy import posify, Symbol, log, solve
from sympy.abc import x
posify(x + Symbol('p', positive=True) + Symbol('n', negative=True))
# (_x + n + p, {_x: x})
eq = 1/x
log(eq).expand()
# log(1/x)
log(posify(eq)[0]).expand()
# -log(_x)
p, rep = posify(eq)
log(p).expand().subs(rep) # 替换回原符号
# -log(x)
eq = x**2 - 4
solve(eq, x)
# [-2, 2]
eq_x, reps = posify([eq, x]); eq_x
# [_x**2 - 4, _x]
solve(*eq_x)
# [2]
多项式展开sympy.expand()
或.expand()
x, y = sympy.symbols('x y')
expr1 = ((x+y)**2)
print(expr1)
expr2 = expr1.expand()
# expr2 = sympy.expand(expr2)
print(expr2)
三角函数展开sympy.expand_trg(
expr = sympy.sin(2*x) + sympy.cos(2*x)
sympy.expand_trig(expr)
# 2*sin(x)*cos(x) + 2*cos(x)**2 - 1
指数函数展开sympy.expand_power_exp()
或sympy.expand_power_base()
expand_power_exp(x**(a + b))
expand_power_base((x*y)**a) # 正数可以满足化简条件
expand_power_base((z*t)**c) # 复数不满足化简条件
expand_power_base((z*t)**c, force=True) # 强制展开
指数函数展开(续)powdenest()
powdenest((x**a)**b) # 正数可以满足化简条件
powdenest((z**a)**b) # 复数不满足化简条件
powdenest((z**a)**b, force=True)
对数函数展开expand_log()
expand_log(log(x*y)) # 正数可以满足化简条件
expand_log(log(x/y))
expand_log(log(x**2))
expand_log(log(x**n))
expand_log(log(z*t)) # 复数不满足化简条件
多项式提取公因式合并sympy.factor()
或.factor()
x = sympy.Symbol('x')
y = sympy.Symbol('y')
expr1 = x**2 + 2*x*y
expr2 = sympy.factor(expr1)
print(expr2)
合并同类项sympy.collect()
x, y, z = sympy.symbols('x:z')
expr = x*y + x - 3 + 2*x**2 - z*x**2 + x**3
print(expr)
# x**3 - x**2*z + 2*x**2 + x*y + x - 3
collected_expr = collect(expr, x)
collected_expr
print(collected_expr)
# x**3 + x**2*(2 - z) + x*(y + 1) - 3
对数函数合并logcombine()
logcombine(log(x) + log(y))
logcombine(n*log(x))
logcombine(n*log(z))
logcombine(n*log(z), force=True)
cancel
函数sympy.cancel()
函数可以将有理函数转化为分式形式并进行化简
cancel((x**2 + 2*x + 1)/(x**2 + x))
# (x + 1)/x
apart
函数sympy.apart()
可以进行部分因式分解
expr = (4*x**3 + 21*x**2 + 10*x + 12)/(x**4 + 5*x**3 + 5*x**2 + 4*x)
print(apart(expr))
# (2*x - 1)/(x**2 + x + 1) - 1/(x + 4) + 3/x
rewrite
函数expr.rewrite(func)
将表达式expr
用函数func
重新表示
tan(x).rewrite(cos)
# cos(x - pi/2) / cos(x)
factorial(x).rewrite(gamma)
# Gamma(x+1)
expand_func
函数可以将特殊函数进行展开
expand_func(gamma(x + 3))
# x * (x + 1) * (x + 2) * Gamma(x)
Meurer A, Smith CP, Paprocki M, Čertík O, Kirpichev SB, Rocklin M, Kumar A, Ivanov S, Moore JK, Singh S, Rathnayake T, Vig S, Granger BE, Muller RP, Bonazzi F, Gupta H, Vats S, Johansson F, Pedregosa F, Curry MJ, Terrel AR, Roučka Š, Saboo A, Fernando I, Kulal S, Cimrman R, Scopatz A. (2017) SymPy: symbolic computing in Python. PeerJ Computer Science 3:e103 https://doi.org/10.7717/peerj-cs.103 ↩︎