「SymPy」符号运算(2) 各种形式输出、表达式的化简合并与展开

目录

  • 导言
  • 输出
  • 替换、演化
  • 化简、合并与展开
    • 化简
    • 展开
    • 合并
    • `cancel`函数
    • `apart`函数
    • `rewrite`函数
    • `expand_func`函数

「SymPy」符号运算(2) 各种形式输出、表达式的化简合并与展开_第1张图片

导言

在前一篇文章中,我们简单学习了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 NotebookSpyder交互界面直接输入表达式并执行,将输出 LaTeX \LaTeX LATEX渲染后的公式
x**2 + log(y) + exp(sqrt(z))

输出:

「SymPy」符号运算(2) 各种形式输出、表达式的化简合并与展开_第2张图片

# 禁用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 \LaTeX{} LATEX格式文本输出
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=N) ,保留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 xx=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)

  1. 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 ↩︎

你可能感兴趣的:(SymPy符号运算系列,python,人工智能)