「SymPy」符号运算(1) 简介/符号/变量/函数/表达式/等式/不等式/运算符

SymPy

1 简介

SymPy是开源免费的python库,具有强大的符号运算和数值计算功能,覆盖方程求根、线性代数、微积分、常/偏微分方程求解等科学计算内容,完全由python语言编写并完全运用于python语言当中1

相关信息与学习资料:

SymPy GitHub网站SymPy 官网SymPy基础应用
SymPy版本信息SymPy官方PDF文档下载v1.11.1

2 导入库

anaconda为例。

SymPy及其依赖库已经集成在anaconda中,不需要安装;如果使用其他集成开发环境,需要先安装mpmath库,再安装SymPy库。如果已经下载安装了anaconda并且想更新SymPy库,在命令行中输入

conda update sympy

在脚本中导入SymPy库:

import sympy

通过sympy.init_session()函数可以导入一些常用的常量和变量

from sympy import init_session
sympy.init_session() 

# sympy.init_session() 等价于执行下列语句
from __future__ import division    # 使得1/2 = 0.5
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中,总有如下假设

  • 所有符号如未指定、均默认为复数( C \mathbb{C} C),因此简化运算必须在复数满足的情况下才会进行

  • 符号的类型可以通过定义来指定:symbols('x y', positive=True)

    在后面的介绍中,若未重定义,总假设x, y为正数,ab为实数,tc为复数 ,即

    x, y = symbols('x y', positive=True)
    a, b = symbols('a b', real=True)
    z, t, c = symbols('z t c')
    

3 定义符号

定义单个变量用sympy.Symbol('<var>'),空格、其他符号均计入变量名的一部分(包括转义符、#号等),这种方法是定义并初始化了一个Symbol类的对象

class Symbol(sympy.core.expr.AtomicExpr, sympy.logic.boolalg.Boolean)

定义多个变量用sympy.symbols(<str>),变量名之间用空格/逗号分隔,但都在引号内,这种方法可以一次性定义多个Symbol类的对象

symbols(names, *, cls=<class 'sympy.core.symbol.Symbol'>, **args)

# 定义单个自变量x
x1 = sympy.Symbol('x')              # x1 = x
x2 = sympy.Symbol('x y')            # x2 = x y

# 定义多个变量
y1, y2 = sympy.symbols('y1 y2#')    # y1 = y1, y2 = y2#
y3, y4 = sympy.symbols('y3,y4@')    # y3 = y3, y4 = y4@
y5     = sympy.symbols('y5,y6 ')    # y5 = tuple(y5, y6)
y6     = sympy.symbols('y6')        # y6 = y6

# 定义一个加粗符号
u = sympy.Symbol('\\boldsymbol u')

# 输出简单表达式
print(x1)
print(2*x1 + 3)

sympy.symbols()中第一个参数可以为元组、列表和字典:

sympy.symbols(('a', 'b', 'c'))
sympy.symbols(['a', 'b', 'c'])
sympy.symbols({'a', 'b', 'c'})

利用冒号:定义一系列自变量

sympy.symbols('x:10')            # (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9)
sympy.symbols('x5:10')           # (x5, x6, x7, x8, x9)
sympy.symbols('x5(:2)')          # (x50, x51)
sympy.symbols('x5:10,y:5')       # (x5, x6, x7, x8, x9, y0, y1, y2, y3, y4)
sympy.symbols(('x5:10', 'y:5'))  # ((x5, x6, x7, x8, x9), (y0, y1, y2, y3, y4))

sympy.symbols('x:z')             # (x, y, z)
sympy.symbols('x:c')             # ()
sympy.symbols('x(:c)')           # (xa, xb, xc)
sympy.symbols(':c')              # (a, b, c)
sympy.symbols('a:d, x:z')        # (a, b, c, d, x, y, z)
sympy.symbols(('a:d', 'x:z'))    # ((a, b, c, d), (x, y, z))
sympy.symbols('x:2(1:3)')        # (x01, x02, x11, x12)

sympy.symbols('x((a:b))')        # (x(a), x(b))
sympy.symbols(r'x(:1\,:2)')      # (x(0,0), x(0,1))

定义整数变量

a = symbols('a', integer=True)
a.is_integer                      # True

4 定义函数

SymPy中,函数也是一种符号。定义函数:

# 方法1
f = Function('f')       # f
f = Function('f')(x)    # f(x)
# 方法2
g, h = symbols('g,h', cls=Function)

被定义为函数的符号继承了基类class sympy.core.function.Function(*args)的一些函数,后面慢慢介绍。当函数被指定了自变量后,就可以做一些符号运算了:

f = Function('x')
f(x).diff(x)
# Derivative(f(x), x)

# 或
f = Function('x')(x)
f.diff(x)
# Derivative(f(x), x)

5 表达式

由符号经过运算符或函数处理返回的结果是表达式,单个符号也可以看作表达式。如

from sympy import symbols
x, y = symbols('x y')
expr = x + 2*y
expr
# x + 2*y

SymPy可以将字符串转化为表达式,使用sympy.simpify()函数

x = sympy.symbols('x')
str1  = 'x**3 + 2'
expr1 = sympy.sympify(str1)

print(f"{expr1} = {expr1.subs(x, 2)}, when x=2")

查询表达式是否为正数

x = Symbol('x', positive=True)
expr = 1 + x**2
expr.is_positive
# True
expr.is_negative
# False

6 等式/不等式

SymPy中,等式不用=表示,而用Eq函数表示

expr = Eq(x, y)

SymPy中,任何没有用Eq组成等式的表达式,在求解方程时其值默认为零,即下列三个语句具有相同的输出

solveset(Eq(x**2, 1), x)
solveset(Eq(x**2 - 1, 0), x)
solveset(x**2 - 1, x)
# {-1, 1}

SymPy中,大于、小于、大于等于、小于等于可以直接用><>=<=符号表示

expr = x > y
expr
# x > y

7 SymPy假设与限制

  1. SymPy中,当存在特殊情况使得表达式不能被简单地化简时,simplify()函数不起作用。因此在定义符号时,最好加上对符号/变量的限制

    from sympy import Symbol, simplify
    x = Symbol('x')			# 默认为复数
    sqrt(x**2)				# x为正则sqrt(x**2)=x, 为负时sqrt(x**2)=-x
    # sqrt(x**2)
    
    # 对符号进行限制,排除特殊情况后,简化正常进行
    y = Symbol('y', positive=True)
    sqrt(y**2)
    # y
    
    # 在程序中,也可以查询某个符号是否为正(或其他限制 is_*)
    y.is_positive
    # True
    
  2. is_*查询变量/符号/表达式具有某种性质时,复杂的表达式不能被完全分析,栗子:下面的完全平方使被展开后,SymPy就给出了无法判断的结果None。这是由于is_*判断在SymPy中先于许多初等运算执行,对效率要求很高,完全解析将会使整体运算效率下降。

    x = Symbol('x', real=True)
    expr = 1 + (x - 2)**2
    expr
    # (x - 2)**2 + 1
    expr.is_positive
    # True
    expr2 = expr.expand()
    expr
    # x**2 - 4*x + 5
    print(expr2.is_positive)
    # None
    
  3. SymPy中定义两个不同的符号、但其初始化内容相同时,会被认作是相等的

    x1 = Symbol('x')
    x2 = Symbol('x')
    x1 == x2
    # True
    
    # 如果限制不同,则不相等
    x1 = Symbol('x')
    x2 = Symbol('x', positive=True)
    x1 == x2
    # False
    
  4. 当使用字符串形式的表达式输入时,字符串内的符号会被隐式地定义为符号,此时不会对符号做任何的假设

    from sympy import solve
    solve('x**2 - 1')
    # [-1, 1]
    

    此时可以通过parse_expr()显式地作假设

    from sympy import parse_expr
    parse_expr('x**2 - 1')
    eq = parse_expr('x**2 - 1', {'x':Symbol('x', positive=True)})
    solve(eq)
    # [1]
    
  5. 关于符号的所有限制,可以通过*.assumptions0属性查看

    x.assumptions0
    ''' 输出
    'algebraic': True,
     'commutative': True,  # 可交换的,默认True,即a*b==b*a为True
     'complex': True,
     'extended_negative': False,
     'extended_nonnegative': True,
     'extended_nonpositive': False,
     'extended_nonzero': True,
     'extended_positive': True,
     'extended_real': True,    # 实数+正负无穷
     'finite': True,
     'hermitian': True,
     'imaginary': False,
     'infinite': False,    # oo,-oo,或zoo
     'integer': True,
     'irrational': False,
     'negative': False,
     'noninteger': False,
     'nonnegative': True,
     'nonpositive': False,
     'nonzero': True,
     'positive': True,
     'rational': True,
     'real': True,
     'transcendental': False,
     'zero': False}
     '''
    

    此外还有很多参数,如偶数(odd)、正整数(prime)等,详见官方文档

  6. 暗示(implications),或隐含的限制,如当一个符号是实数、非负、非零时,它也是正数;当各个限制存在冲突时,会报错InconsistentAssumptions

    x = Symbol('x', real=True, negative=False, zero=False)
    x.is_positive
    # True
    

8 运算符/函数

SymPy表达式使用函数时返回副本,原表达式不进行原位更改

常用运算符/函数

  • +, -, *, /, **
  • 求平方根:sqrt(var)
  • 求n次方根:root(8, n)
  • 求阶乘:factorial(4)

数学常数

  • 虚数单位:I
  • 自然对数的底:E
  • 无穷大:oo
  • 圆周率:pi

三角函数

  • 正弦函数:sin() ,余弦函数:cos()
  • 正切函数:tan() ,余切函数:cot()
  • 正割函数:sec() ,余割函数:csc()
  • 反正弦:asin() , 反余弦:acos()
  • 反正切:atan(), 反余切:acot()
  • 反正割:asec(), 反余割:acsc()
  • sinc函数:sinc()
  • 此外还有sinh(), cosh(), tanh(), coth()及其反函数等

复杂函数

  • Γ \Gamma Γ函数:gamma()
  • ζ \zeta ζ函数:zeta()
  • 误差函数:erf()
  • δ \delta δ(Kronecker运算符):KroneckerDelta()

指数运算

  • 指数运算:exp()

  • 自然对数:log()

  • 以十为底的对数:log(var, 10)

  • 自然对数:ln(x)log(x)

假设

IdentitySufficient conditions to holdCounterexample when conditions are not metImportant consequences
x a x b = x a + b x^ax^b=x^{a+b} xaxb=xa+bAlways trueNoneNone
x a y a = ( x y ) a x^a y^a = (xy)^a xaya=(xy)a x , y ≥ 0 x,y≥0 x,y0 and a ∈ R a\in R aR ( − 1 ) 1 / 2 ( − 1 ) 1 / 2 ≠ ( − 1 ⋅ − 1 ) 1 / 2 (-1)^{1/2}(-1)^{1/2} \ne (-1\cdot -1)^1/2 (1)1/2(1)1/2=(11)1/2 x y ≠ x y \sqrt{x} \sqrt{y} \ne \sqrt{xy} x y =xy in general
( x a ) b = x a b (x^a)^b=x^{ab} (xa)b=xab b ∈ Z b\in Z bZ ( ( − 1 ) 2 ) 1 / 2 = ( − 1 ) 2 ⋅ 1 / 2 ((-1)^2)^{1/2} = (-1)^{2\cdot 1/2} ((1)2)1/2=(1)21/2 x 2 ≠ x \sqrt{x^2}\ne x x2 =x and 1 x ≠ 1 x \sqrt{\dfrac{1}{x}} \ne \dfrac{1}{\sqrt{x}} x1 =x 1 in general

后续对于指数展开(expand)部分,这些假设成为了限制展开的因素。


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

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值