• Python之Sympy代数符号运算库

    • 计算器与数学
    • 计算机代数系统 CAS
    • Sympy符号运算的基本使用指南
      • Sympy 与 Math 函数的区别
      • 定义变量 Symbol(‘x’), symbols(‘u v w’) 函数
      • 基本数值类型(real-rational-integer-positive-negative-complex-zero)
      • 构造抽象函数(Function(‘f’))
      • 数学符号与代数式
      • 变量替换(.subs)
      • 多项式排序重组
        • 单变量情形
        • 多变量情形
      • 因式分解与展开(factor-expand)
        • expand()的参数
        • factor()的参数
      • 有理式的简化、分解与合并(cancel-apart-together)
      • 多种特殊代数式化简
      • 代数式求值(替换subs)
      • 代数方程和方程组
        • 解一元一次方程
        • 解多元一次方程组
        • 解一元二次方程组
      • 微积分Calculus
        • 高阶微分与偏导
        • 求不定积分
        • 求定积分
        • 求多重积分
        • 求极限
        • 求和
      • 复数
      • 函数
        • 三角函数
        • 球谐函数
        • 阶乘和伽马函数
        • Zeta函数
      • 多项式
      • 常微分ODE方程
      • 偏微分PDE方程
      • 数论
      • 线性代数
        • 矩阵
      • 集合
        • 定义闭区间和开区间(Interval(s,e),Interval.open(s,e))
        • 长度用 .measure方法来表示
        • 其闭包用 .closure方法来表示
        • 其内点用 .interior方法来表示
        • 判断其边界条件可以使用 left_open 或者 right_open 来做
        • 两个集合之间的操作
      • 逻辑
      • 级数
        • 级数展开
        • 级数收敛
        • 级数求和
        • 级数连乘
      • 求代数式的浮点数 .evalf(n)方法
      • SymPy的范畴论工具
      • 系数匹配
      • 打印输出
        • 标准 print
        • 字符艺术打印(Pretty Printing) pprint
        • Python字符串打印成一行 Python printing
        • 输出成LaTeX形式 LaTeX printing
        • 输出成MathML形式 MathML
    • 数学符号
    • 相关参考链接

Python之Sympy代数符号运算库

人的一生中学习数学很多时候都浪费在反复解题、不断运算上。现在计算机普及,手机流行,很多计算方法、运算技巧、笔算能力以及数学公式都可以方便获取。笔算与解题在人工智能AI、图形图像、数据分析等上被软件所取代。

计算器与数学

APP中无数的数学计算器,常见的是 加减乘除 四则运算,有了它,我们就可以摆脱 笔算和心算 的痛苦。

数学的应用应该生活化、普及化,而不是只属于天才的专利,计算器帮我们改变了这一切。

计算器还可以做 科学运算,比如 乘方、开方、指数、对数、三角函数 等,尽管这些知识在我们初中时代,通过纸笔也是能运算起来的,但是也仅限于一些极其常用和简单的运算,一旦复杂起来,通过纸笔来运算就是一项复杂的工程了。所以说,计算器可以让我们离数学的应用更近

但是学生时代所学的数学可远不止这些,尤其是 高等数学(微积分)、线性代数、概率统计 等数学知识应用非常广泛,但是由于其运算非常复杂,我们即便掌握了这些知识,想要应用它又谈何容易,那有没有 微积分、线性代数、概率统计 等的计算器呢?

答案是有的,它们就是计算机代数系统Computer Algebra System,简称CAS,Python的 Sympy 库也支持带有数学符号的微积分、线性代数等进行运算。

有了计算器,我们才能真正脱离数学复杂的解题本身,把精力花在对数学原理和应用的学习上,而这才是(在工作方面)数学学习的意义。

计算机代数系统 CAS

Python语言在 专业数学(数学、数据科学等)领域,由于其拥有非常多而且强大的第三方库,譬如Numpy,构成了一个极其完善的生态链。
Sympy 是基于 Python之上的数学库,可以实现数学符号的运算,用它来进行数学代数式的符号推导和验算,处理带有数学符号的导数、极限、微积分、方程组、矩阵等,就像科学计算器一样简单,可以完成 计算机代数系统CAS的绝大部分功能。

Sympy符号运算的基本使用指南

如果之前是学数学相关专业了解计算机代数系统CAS,就会对数学符号的运算比较熟悉,而如果之前是程序员,可能会有点不太明白,下面我们就来了解一下。

Sympy 与 Math 函数的区别

我们先来看一下Sympy库和Python内置的 Math 函数对数值计算的处理有什么不同。为了让代码可执行,下面的代码都是基于Python3的完整代码。

import sympy,math
print(math.sqrt(8))
print(sympy.sqrt(8))

执行之后,结果显示为:

2.8284271247461903
2*sqrt(2)

math 模块是直接求解出一个浮点值,而 Sympy 则是用数学符号表示出结果,结合LaTex的语法就可以得出我们在课本里最熟悉的的:222\sqrt{2}22​

定义变量 Symbol(‘x’), symbols(‘u v w’) 函数

Symbol('x') 函数定义单个数学符号symbols('x y z)函数定义多个数学符号

对比与其他的计算机代数系统,在SymPy中要明确声明符号变量:

>>> x = Symbol('x')
>>> x + 1
x + 1
>>> x,y,z=symbols('x y z')
>>> crazy = symbols('unrelated')
>>> crazy + 1
unrelated + 1
>>> x = symbols('x')
>>> expr = x + 1
>>> x = 2
>>> print(expr)
x + 1
#将x赋值2,并没有改变 expr变量. 因为 x = 2 是改变 Python 变量 x 为 2, 但是不影响
#SymPy的expr中的符号 x

基本数值类型(real-rational-integer-positive-negative-complex-zero)

SymPy 有三个内建的数值类型:实数,有理数和整数。有理数类用 两个整数 来表示一个有理数。分子与分母,所以 Rational(1,2) 代表 1/2Rational(5,2)代表5/2,等等。

>>>from sympy import *
>>>a = Rational(1,2)
>>>a
1/2
>>>a*2
1
>>>Rational(2)**50/Rational(10)**50
1/88817841970012523233890533447265625

还可以通过设置得到 复数,实数,有理数,整数,正数,负数,非零数,零,非负数,非正数等的变量。

>>> from sympy import Symbol
>>> from sympy.abc import x
>>> x.assumptions0
{'commutative': True}
>>> r=Symbol('r', real=True)
>>> n=Symbol('n', Integer=True)   # 整数
>>> n.assumptions0
{'Integer': True, 'commutative': True}>>> y=Symbol('y', positive=True)  # 正数
>>> y.assumptions0
{'positive': True, 'imaginary': False, 'commutative': True, 'zero': False,
'nonzero': True, 'complex': True, 'real': True, 'nonpositive': False,
'hermitian': True, 'nonnegative': True, 'negative': False}
  • commutative - Bing dictionary
    US[kə’mju:tətɪv]UK[kə’mju:tətɪv]
    adj.交换的(排列次序不影响结果)
    网络可交换的;交换律;交换性
  • Hermitian Matrix
    埃尔米特矩阵主对角线上的元素都是实数的,其特征值也是实数。

构造抽象函数(Function(‘f’))

构造抽象函数 Function(),直接用 f=Function(“f”),注意一点,在python之中和 C 中的不同之处,C 的创建对象实例有点像定义一个变量,和函数调用是不一样的,所以发现奇奇怪怪的比如student zhangsan; 我们就知道这肯定是创建zhangsan这个对象。而python的是和函数的一样的,所以注意分辨。再要注意的是,这个 Function 创建的是 类而不是对象实例。也就是说 f 是一个继承下来的类。还需要用 t=f(x,y) 去创建函数 t 这个对象。最终我们才能得到 t 这个抽象函数。

数学符号与代数式

我们要对数学方程组、微积分等进行运算时,就会遇到 变量 比如 x,y,z,u,v,w,f,g,hx,y,z,u,v,w,f,g,hx,y,z,u,v,w,f,g,h 等的问题,也会遇到 求导、积分 等代数符号代数式,而 Sympy 就可以保留变量,计算有代数符号的代数式。

>>> from sympy import *
>>> from sympy.abc import x,y,z,a,b,c,k,m,n
>>> print(a*x**m+b*y**n+c*z)
a*x**m + b*y**n + c*z
>>> x = Symbol('x')  #只申请一个符号变量
>>> y = Symbol('y')
>>> k, m, n = symbols('k m n')  #同时申请多个符号变量

输出的结果为:a∗x∗∗m+b∗y∗∗n+c∗za*x**m + b*y**n + c*za∗x∗∗m+b∗y∗∗n+c∗z,转化为 LaTex 表示法之后结果为 axm+byn+czax^m+by^n+czaxm+byn+cz,输出的结果就带有 x,y,z,a,b,cx, y, z, a,b,cx,y,z,a,b,c 等符号变量。

变量替换(.subs)

当个变量替换用 expr.subs(var,value); 多个变量替换用词典 expr.subs({v1:val1, v2:val2, ...}), 或者用列表方式 expr.subs([(v1,val1), (v2,val2), ...]

>>> x = symbols('x')
>>> expr = x + 1
>>> expr.subs(x, 2)
3
>>> from sympy import pi, exp, limit, oo
>>> from sympy.abc import x, y
>>> (1 + x*y).subs(x, pi)
pi*y + 1
>>> (1 + x*y).subs({x:pi, y:2})
1 + 2*pi
>>> (1 + x*y).subs([(x, pi), (y, 2)])
1 + 2*pi
>>> reps = [(y, x**2), (x, 2)]
>>> (x + y).subs(reps)
6
>>> (x + y).subs(reversed(reps))
x**2 + 2
>>> (x**2 + x**4).subs(x**2, y)
y**2 + y
>>> (x**2 + x**4).xreplace({x**2: y})
x**4 + y
>>> (x/y).subs([(x, 0), (y, 0)])
0
>>> (x/y).subs([(x, 0), (y, 0)], simultaneous=True)
nan
>>> ((x + y)/y).subs({x + y: y, y: x + y})
1
>>> ((x + y)/y).subs({x + y: y, y: x + y}, simultaneous=True)
y/(x + y)
>>> limit(x**3 - 3*x, x, oo)
oo

多项式排序重组

单变量情形

>>> collect(a*x**2 + b*x**2 + a*x - b*x + c, x)
c + x**2*(a + b) + x*(a - b)#The same result can be achieved in dictionary form::>>> d = collect(a*x**2 + b*x**2 + a*x - b*x + c, x, evaluate=False)
>>> d[x**2]
a + b
>>> d[x]
a - b
>>> d[S.One]
c

多变量情形

>>> myexpr = x*y + x -3 + 2*x**2 - x**2 + x**3 + y**2 + x**2*y**2
>>> sympy.collect(myexpr,x) # 按照变量 x 排序
x**3 + x**2*(y**2 + 1) + x*(y + 1) + y**2 - 3
>>> sympy.collect(myexpr,y) # 按照变量 y 排序
x**3 + x**2 + x*y + x + y**2*(x**2 + 1) - 3
>>> myexpr.coeff(x,2) # x*2的系数
y**2 + 1
>>> myexpr.coeff(y,1) # y的系数
x>>> collect(x**2 + y*x**2 + x*y + y + a*y, [x, y])
x**2*(y + 1) + x*y + y*(a + 1)#Also more complicated expressions can be used as patterns::>>> from sympy import sin, log
>>> collect(a*sin(2*x) + b*sin(2*x), sin(2*x))
(a + b)*sin(2*x)>>> collect(a*x*log(x) + b*(x*log(x)), x*log(x))
x*(a + b)*log(x)#You can use wildcards in the pattern::>>> w = Wild('w1')
>>> collect(a*x**y - b*x**y, w**y)
x**y*(a - b)#It is also possible to work with symbolic powers, although it has more
#complicated behavior, because in this case power's base and symbolic
#part of the exponent are treated as a single symbol::>>> collect(a*x**c + b*x**c, x)
a*x**c + b*x**c
>>> collect(a*x**c + b*x**c, x**c)
x**c*(a + b)#However if you incorporate rationals to the exponents, then you will get well
#known behavior::>>> collect(a*x**(2*c) + b*x**(2*c), x**c)
x**(2*c)*(a + b)#Note also that all previously stated facts about :func:`collect` function
#apply to the exponential function, so you can get::>>> from sympy import exp
>>> collect(a*exp(2*x) + b*exp(2*x), exp(x))
(a + b)*exp(2*x)>>> from sympy import Derivative as D, collect, Function
>>> f = Function('f') (x)>>> collect(a*D(f,x) + b*D(f,x), D(f,x))  #求导
(a + b)*Derivative(f(x), x)>>> collect(a*D(D(f,x),x) + b*D(D(f,x),x), f)
(a + b)*Derivative(f(x), (x, 2))>>> collect(a*D(D(f,x),x) + b*D(D(f,x),x), D(f,x), exact=True)
a*Derivative(f(x), (x, 2)) + b*Derivative(f(x), (x, 2))>>> collect(a*D(f,x) + b*D(f,x) + a*f + b*f, f)
(a + b)*f(x) + (a + b)*Derivative(f(x), x)#Or you can even match both derivative order and exponent at the same time::>>> collect(a*D(D(f,x),x)**2 + b*D(D(f,x),x)**2, D(f,x))
(a + b)*Derivative(f(x), (x, 2))**2#Finally, you can apply a function to each of the collected coefficients.
#For example you can factorize symbolic coefficients of polynomial::>>> f = expand((x + a + 1)**3)>>> collect(f, x, factor)
x**3 + 3*x**2*(a + 1) + 3*x*(a + 1)**2 + (a + 1)**3

因式分解与展开(factor-expand)

factor() 函数可以合并代数式,也就是因式分解;而 expand() 函数可以展开代数式,比如代数式: x4+xy+8xx^4+xy+8xx4+xy+8x ,合并之后应该是 x(x3+y+8)x(x^3+y+8)x(x3+y+8),可见它们是互逆过程。我们来看具体的代码:

from sympy import *
x, y = symbols('x y')
>>> factor(x**4+x*y+8*x) #合并同类型,即因式分解
x*(x**3 + y + 8)
>>> expand(_)            #展开代数式,_ 代表上一次的输出结果
x**4 + x*y + 8*x

代数式的合并与展开,对应的数学知识就是因式分解。用 Python 学习数学专栏的目的就是要 Python 与 初高中、大学的数学学习结合起来,让数学变得更加简单生动。

expand()的参数

  • multinomial 多项式展开
    展开多项式 (x+y+...)n,n∈Z+(x + y + ...)^n,n\in \mathbb{Z}^+(x+y+...)n,n∈Z+
>>> ((x + y + z)**2).expand(multinomial=True)
x**2 + 2*x*y + 2*x*z + y**2 + 2*y*z + z**2。
  • power_exp 幂函数展开
    展开指数加为幂的乘积: ex+y→ex⋅ey,2x+y→2x×2ye^{x+y}\to e^x\cdot e^y, 2^{x+y}\to 2^x\times2^yex+y→ex⋅ey,2x+y→2x×2y
>>> exp(x + y).expand(power_exp=True)
exp(x)*exp(y)
>>> (2**(x + y)).expand(power_exp=True)
2**x*2**y
  • power_base 幂指数分解

(xy)z→xz⋅yz,(2y)z→2zyz(xy)^z\to x^z\cdot y^z, (2y)^z\to 2^zy^z(xy)z→xz⋅yz,(2y)z→2zyz

This only happens by default if assumptions allow, or if the
force meta-hint is used:

>>> ((x*y)**z).expand(power_base=True)
(x*y)**z
>>> ((x*y)**z).expand(power_base=True, force=True)
x**z*y**z
>>> ((2*y)**z).expand(power_base=True)
2**z*y**z

Note that in some cases where this expansion always holds, SymPy performs it automatically:

>>> (x*y)**2
x**2*y**2
  • log 对数函数展开

将幂指数变成系数,对数乘积变成对数加法:log⁡(x2y)→2log⁡(x)+log(y),x>0,y>0\log(x^2y)\to 2\log(x)+log(y), x>0,y>0log(x2y)→2log(x)+log(y),x>0,y>0

Note that these only work if the arguments of the log function have the proper assumptions–the arguments must be positive and the exponents must be real–or else the force hint must be True:

>>> from sympy import log, symbols
>>> log(x**2*y).expand(log=True)
log(x**2*y)
>>> log(x**2*y).expand(log=True, force=True)
2*log(x) + log(y)
>>> x, y = symbols('x,y', positive=True)
>>> log(x**2*y).expand(log=True)
2*log(x) + log(y)
  • complex 复数展开
    将复数分解为实部和虚部(real and imaginary parts).
>>> x, y = symbols('x,y')
>>> (x + y).expand(complex=True)
re(x) + re(y) + I*im(x) + I*im(y)
>>> cos(x).expand(complex=True)
-I*sin(re(x))*sinh(im(x)) + cos(re(x))*cosh(im(x))

Note that this is just a wrapper around as_real_imag(). Most objects that wish to redefine _eval_expand_complex() should consider redefining as_real_imag() instead.

  • func 函数展开 Expand other functions.
>>> from sympy import gamma
>>> gamma(x + 1).expand(func=True)
x*gamma(x)
  • trig 三角函数展开
    Do trigonometric expansions.
>>> cos(x + y).expand(trig=True)
-sin(x)*sin(y) + cos(x)*cos(y)
>>> sin(2*x).expand(trig=True)
2*sin(x)*cos(x)

Note that the forms of sin(n*x) and cos(n*x) in terms of sin(x) and cos(x) are not unique, due to the identity sin⁡2(x)+cos⁡2(x)=1\sin^2(x) + \cos^2(x)= 1sin2(x)+cos2(x)=1. The current implementation uses the form obtained from Chebyshev polynomials, but this may change. See this MathWorld article for more information.

factor()的参数

>>> from sympy import factor, sqrt, exp
>>> from sympy.abc import x, y>>> factor(2*x**5 + 2*x**4*y + 4*x**3 + 4*x**2*y + 2*x + 2*y)  # 一般多项式因式分解
2*(x + y)*(x**2 + 1)**2>>> factor(x**2 + 1)  # 有理数范围内的因式分解
x**2 + 1#The ``modulus`` meta-hint can be used to reduce the coefficients of an
#expression post-expansion::>>> factor(x**2 + 1, modulus=2)
(x + 1)**2
>>> factor(x**2 + 1, gaussian=True)  # 复数范围内的因式分解
(x - I)*(x + I)>>> factor(x**2 - 2, extension=sqrt(2)) # 指定范围
(x - sqrt(2))*(x + sqrt(2))>>> factor((x**2 - 1)/(x**2 + 4*x + 4))
(x - 1)*(x + 1)/(x + 2)**2
>>> factor((x**2 + 4*x + 4)**10000000*(x**2 + 1))
(x + 2)**20000000*(x**2 + 1)#By default, factor deals with an expression as a whole:>>> eq = 2**(x**2 + 2*x + 1)
>>> factor(eq)
2**(x**2 + 2*x + 1)#If the ``deep`` flag is True then subexpressions will be factored:>>> factor(eq, deep=True)
2**((x + 1)**2)#If the ``fraction`` flag is False then rational expressions won't be combined.
#By default it is `True`.>>> factor(5*x + 3*exp(2 - 7*x), deep=True)
(5*x*exp(7*x) + 3*exp(2))*exp(-7*x)
>>> factor(5*x + 3*exp(2 - 7*x), deep=True, fraction=False)
5*x + 3*exp(2)*exp(-7*x)

有理式的简化、分解与合并(cancel-apart-together)

  • 去除公因子用 cancel()
  • 不消除公因子(公式合并)用 tegother()

化简有理式 expr=x2+3x+2x2+xexpr=\dfrac{x^2+3x+2}{x^2+x}expr=x2+xx2+3x+2​

x,y,z = sympy.Symbol('x y z')
>>> expr = (x**2+3*x+2)/(x**2+x)
>>> cancel(expr)
(x + 2)/x
>>> together(expr)
(x**2 + 3*x + 2)/(x*(x + 1))
>>> together(1/x+1/y+1/z)
(x*y + x*z + y*z)/(x*y*z)
  • 部分分式展开(Partial Fraction Decomposition)
    用函数 sympy.apart(expr, x),它是把有理式分解成多个次数较低的有理式的和的形式;
    展开的逆运算就是代数式的合并,用 sympy.together(expr, x)
    公式展开用 apart 方法, 和 expand 区别不是很大,常用于分数(或分式)进行展开或分离;
>>> apart( 1/((x+2)*(x+1)) )
-1/(x + 2) + 1/(x + 1)
>>> (x+1)/(x-1)
(x + 1)/(x - 1)
>>> apart((x+1)/(x-1),x)
1 + 2/(x - 1)>>> together(apart((x+1)/(x-1), x), x)
(x + 1)/(x - 1)
>>> together(apart(1/( (x+2)*(x+1) ), x), x)
1/((x + 1)*(x + 2))

多种特殊代数式化简

simplify() 函数可以化简代数式。有一些代数式看起来会比较复杂,简化 (2x)3(−5xy2)(2x)^3(-5xy^2)(2x)3(−5xy2) 。

  • 多项式化简 simplify(expr)
from sympy import *
x,y = symbols('x y')
>>> expr = (2*x)**3*(-5*x*y**2)
>>> simplify(expr)
-40*x**4*y**2
  • 三角函数化简与展开 trigsimp(expr),expand_trig(expr)
from sympy import trigsimp,sin,cos
from sympy.abc import x,y
y = sin(x)/cos(x)
trigsimp(y)
tan(x)
>>> expand_trig(cos(x+y))
-sin(x)*sin(y) + cos(x)*cos(y)
>>> trigsimp(_)
cos(x + y)
>>> expand_trig(sin(x+y))
sin(x)*cos(y) + sin(y)*cos(x)
>>> trigsimp(_)
sin(x + y)
>>> trigsimp(sin(x)/cos(x))
tan(x)
>>> expand_trig(_)
tan(x)
>>> expand_trig(tan(x+y))
(tan(x) + tan(y))/(-tan(x)*tan(y) + 1)
>>> trigsimp(_)  #???
(tan(x) + tan(y))/(-tan(x)*tan(y) + 1)
  • 指数函数化简与展开 powsimp(expr),expand_power_exp()

powsimp 与 simplify 一样。除此之外,还可以根据
底数来做合并,即分别使用 expand_power_exp 函数与 expand_power_base 函数。

>>> from sympy import powsimp
>>> from sympy.abc import x,y,z
>>> powsimp(x**z*y**z*x**z)
x**(2*z)*y**z
>>> simplify(x**z*y**z*x**z)
x**(2*z)*y**z
>>> expand_power_exp(x**(y+z))
x**y*x**z
>>> expand_power_base(x**(y+z))
x**(y + z)
  • 对数函数log 展开与化简
    指数的反函数就是 log,sympy 也是有着类似的展开合并函数,expand_log,logcombine 承担了这样的角色。

ln⁡(xy)=ln⁡(x)+ln⁡(y),ln⁡(xy)=ln⁡(x)−ln⁡(y)\ln(xy) = \ln(x) + \ln(y), \ln( \dfrac{x}{y}) = \ln(x) − \ln(y)ln(xy)=ln(x)+ln(y),ln(yx​)=ln(x)−ln(y)

>>> from sympy import log,expand_log
>>> from sympy.abc import x,y,a>>> expand_log(log(x**3))
log(x**3)
#expand_log为展开log,但需要将force=True,展开才能发生
>>> expand_log(log(a**x),force=True)
x*log(a)
>>> expand_log(sympy.log(x*y), force=True)
log(x) + log(y)
>>> expand_log(sympy.log(x/y), force=True)
log(x) - log(y)
>>> expand_log(sympy.log(x/y))
log(x/y)

代数式求值(替换subs)

如果想进行变量替换,例如把 xxx 变成 yyy ,那么可以使用 substitution--subs 方法。也常用来赋值求值

#--------多项式求解--------
#定义变量
>>> x=sympy.Symbol('x')
>>> (5*x+4).subs(x,6)
34
#使用evalf函数传值
>>> (5*x+4).evalf(subs={x:6})
34.0000000000000#多元代数式
>>> y=sympy.Symbol('y')
>>> (x*x+y*y).subs({x:3,y:4})
25
>>> (x*x+y*y).evalf(subs={x:3,y:4})
25.0000000000000>>> f=1/x
>>> f.subs(x,y)
1/y
>>> f.subs(x,5)
1/5

代数方程和方程组

在初等数学中,通常都存在一元一次方程,一元二次方程等,并且在不同的域上有着不同的解。SymPy 里面的
相应函数就是 solveset,根据定义域的不同,可以获得完全不同的解。

初一学习一元一次方程组、二元一次方程、三元一次方程组,初三学习一元二次方程,使用 Sympy 的solve() 函数就能轻松解题。

解一元一次方程

函数 solve(expr,var), solveset(expr,var,domain=S.x) 用来求解一元一次方程。

x∈R:x3−1=0,x∈C:x3−1=0,x∈R:ex−x=0,x∈R:ex−1=0,x∈C:ex−1=0x ∈ \mathbb{R} : x^3 − 1 = 0,\\ x ∈ \mathbb{C} : x^3 − 1 = 0,\\ x ∈ \mathbb{R} : e^x − x = 0,\\ x ∈ \mathbb{R} : e^x − 1 = 0,\\ x ∈ \mathbb{C} : e^x − 1 = 0x∈R:x3−1=0,x∈C:x3−1=0,x∈R:ex−x=0,x∈R:ex−1=0,x∈C:ex−1=0

>>> from sympy import *
>>> from sympy.abc import x,y
>>> from sympy import solve,linsolve,Eq
>>> x = Symbol('x')
>>> solve(x**4-1,x)
[-1, 1, -I, I]
>>> solve([x+5*y-2,-3*x+6*y-15],[x,y])
{x: -3, y: 1}>>> solve(6*x+6*(x-2000)-150000,x)  #默认 expr=0
[13500]
#对一个方程求解,使用solve
>>> solve(Eq(6*x+6*(x-2000),150000),x) #Eq可以解决左右表达式,建议用默认方式
[13500]
>>> solve(Eq(2*x-1,3), x)  #2x-1=3
[2]
>>> solveset(Eq(x**3,1),x, domain=S.Reals)
FiniteSet(1)
>>> solveset(Eq(x**3,1),x, domain=S.Complexes)
FiniteSet(1, -1/2 - sqrt(3)*I/2, -1/2 + sqrt(3)*I/2)
>>> solveset(Eq(exp(x),x),x, domain=S.Complexes)
ConditionSet(x, Eq(-x + exp(x), 0), Complexes)
>>> solveset(exp(x),x)
EmptySet()
>>> solveset(exp(x)-1,x)  #缺省为Complexes
ImageSet(Lambda(_n, 2*_n*I*pi), Integers)
>>> solveset(exp(x)-1,x,domain=S.Reals)
{0}
>>> solveset(exp(x)-1,x,domain=S.Complexes)
ImageSet(Lambda(_n, 2*_n*I*pi), Integers)

在这里,Lambda 表示的是数学公式,第一个是自变量,第二个是函数,最后是自变量的定义域。

我们需要掌握Python的代码符号和数学符号之间的对应关系, 解一元一次方程就非常简单。

解多元一次方程组

在线性代数中,最常见的还是多元一次方程组。解多元一次方程组,方法同上。还可以用 linsolve([eq1,eq2,...],[x,y,z,...])

{x+y=102x+y=16\begin{cases} x+y=10\\ 2x+y=16 \end{cases}{x+y=102x+y=16​

>>> from sympy import *
>>> x,y = symbols('x y')
>>> solve([x+y-10,2*x+y-16],[x,y])
{x: 6, y: 4}   #解为 $x=6, y=4$#对多个方程求解,也可以使用linsolve。方程的解为x=-1,y=3
>>> linsolve([x+2*y-5,2*x+y-1],[x,y])
{(-1, 3)}   #解为 x=-1,y=3
>>> linsolve([x+2*y-5,2*x+y-1],(x,y))
{(-1, 3)}
>>> solve([sin(x+y),cos(x-y)],[x,y])
[(-3*pi/4, 3*pi/4), (-pi/4, pi/4), (pi/4, 3*pi/4), (3*pi/4, pi/4)]
>>> solve([sin(x-y),cos(x+y)],[x,y])
[(-pi/4, 3*pi/4), (pi/4, pi/4), (3*pi/4, 3*pi/4), (5*pi/4, pi/4)]
>>> solve([sin(x-y),cos(x-y)],[x,y])
[]
>>> solve([sin(x+y),cos(x+y)],[x,y])
[]

解三元一次方程组:
{x+y+z=12x+2y+5z=22x=4y\begin{cases} x+y+z=12\\ x+2y+5z=22\\ x=4y \end{cases}⎩⎪⎨⎪⎧​x+y+z=12x+2y+5z=22x=4y​

>>> linsolve([x+y+z-12,x+2*y+5*z-22,x-4*y],[x,y,z])
{(8, 2, 2)}  #解为x=8,y=2,z=2

解一元二次方程组

一元二次方程一般式求解:ax2+bx+c=0,a≠0ax^2+bx+c=0, a\ne0ax2+bx+c=0,a​=0.

>>> from sympy import *
>>> x,y = symbols('x y')
>>> a,b,c = symbols('a b c')
>>> solve(a*x**2+b*x+c,x)
[(-b + sqrt(-4*a*c + b**2))/(2*a), -(b + sqrt(-4*a*c + b**2))/(2*a)]

结果为 [(-b + sqrt(-4*a*c + b**2))/(2*a), -(b + sqrt(-4*a*c + b**2))/(2*a)], 二次方程有两个解,这里的格式就是一个列表。转为我们常见的数学公式即为:
−b+b2−4ac2a,−b−b2−4ac2a\dfrac{-b+\sqrt{b^2-4ac}}{2a},\dfrac{-b-\sqrt{b^2-4ac}}{2a}2a−b+b2−4ac​​,2a−b−b2−4ac​​

常记 Δ=b2−4ac\Delta=b^2-4acΔ=b2−4ac,称为判别式。则有两根为
x1=−b+Δ2a,x2=−b−Δ2ax_1=\dfrac{-b+\sqrt{\Delta}}{2a},x_2=\dfrac{-b-\sqrt{\Delta}}{2a}x1​=2a−b+Δ​​,x2​=2a−b−Δ​​

满足根与系数的关系式:x1+x2=−ba,x1⋅x2=cax_1+x_2=-\dfrac{b}{a}, x_1\cdot x_2=\dfrac{c}{a}x1​+x2​=−ab​,x1​⋅x2​=ac​

微积分Calculus

微积分是大学高等数学里非常重要的学习内容,比如求 极限、导数、微分、不定积分、定积分等都是可以使用 Sympy 来运算的。

高阶微分与偏导

可以使用 diff(代数式, 变量, 求导的次数) 函数对代数式求导,一阶微分可以省略求导次数。比如我们要对 sin⁡(x)ex\sin(x)e^xsin(x)ex 进行 xxx 求导,以及求导两次。
求导一次的结果就是 exp(x)*sin(x) + exp(x)*cos(x),也就是 exsin⁡(x)+excos⁡(x)e^x\sin(x)+e^x\cos(x)exsin(x)+excos(x) ;
求导两次的结果是 2*exp(x)*cos(x),也就是 2excos⁡(x)2e^x\cos(x)2excos(x)

代码如下:

>>> from sympy import *
>>> x,y = symbols('x y')>>> diff(sin(x)*exp(x),x)     # 初等函数
exp(x)*sin(x) + exp(x)*cos(x)
>>> diff(sin(x)*exp(x),x,2)   # 2阶导数
2*exp(x)*cos(x)
>>> diff(sin(x),x)
cos(x)
>>> diff(sin(2*x),x)
2*cos(2*x)
>>> diff(tan(2*x),x)
2*tan(2*x)**2 + 2
>>> diff(tan(x),x)
tan(x)**2 + 1

可以通过以下验证:

>>> limit((tan(x+y)-tan(x))/y, y, 0)
1 + tan(x)**2

计算高阶微分 diff(func, var, n):

>>> diff(sin(2*x), x, 1)
2*cos(2*x)
>>> diff(sin(2*x), x, 2)
-4*sin(2*x)
>>> diff(sin(2*x), x, 3)
-8*cos(2*x)

求偏导如下:

>>> diff(3*x**2*y*z,x,y)
6*x*z

求不定积分

SymPy支持 不定积分,超越函数与特殊函数的定积分。SymPy有力的扩展了 Risch-Norman 算法和模型匹配算法

Sympy是使用 integrate(代数式,变量) 来求不定积分的。

  • 初等函数
    比如我们要求∫(exsin⁡(x)+excos⁡(x))dx\int(e^x\sin{(x)} + e^x\cos{(x)})\,dx∫(exsin(x)+excos(x))dx
>>> from sympy import *
>>> x = Symbol('x')
>>> integrate(exp(x)*sin(x)+ exp(x)*cos(x),x)
exp(x)*sin(x)
>>> integrate(1/x,x)
log(x)
>>> integrate(1/x,(x,1,2))
log(2)

执行之后的结果为:exp(x)*sin(x) 转化之后为:exsin⁡(x)e^x\sin(x)exsin(x)

>>> integrate(6*x**4,x)
6*x**5/5
>>> integrate(sin(x),x)
-cos(x)
>>> integrate(log(x),x)
x*log(x) - x
>>> integrate(2*x+sinh(x),x)
x**2 + cosh(x)
  • 特殊函数
>>> integrate(exp(-x**2)*erf(x),x)
sqrt(pi)*erf(x)**2/4

求定积分

Sympy同样是使用 integrate()函数来做定积分的求解,只是语法不同:integrate(代数式,(变量,下区间,上区间)),我们来看如果求解 ∫−∞+∞sin⁡(x2)dx\int_{-\infty}^{+\infty}\sin(x^2)\mathbf{d}x∫−∞+∞​sin(x2)dx

>>> from sympy import *
>>> from sympy.abc import pi
>>> x,y = symbols('x y')
>>> expr=sin(x**2)
>>> i_expr=integrate(expr, (x, -oo, oo))
>>> print(i_expr)
>>> integrate(sin(x),(x,0,pi))
-cos(pi)+1

执行之后的结果为sqrt(2)*sqrt(pi)/2,也就是 2π2\dfrac{\sqrt{2}\sqrt{\pi}}{2}22​π​​

>>> integrate(x**3,(x,-1,1))
0
>>> integrate(sin(x),(x,0,pi/2))
1
>>> integrate(sin(x),(x,0,pi))
2
>>> integrate(cos(x),(x,-pi/2,pi/2))
2

也支持广义积分:

∫−∞0e−x2dx=π2,∫0+∞e−xdx=1,∫−∞+∞∫−∞+∞e−x2−y2dxdy=π\int_{-\infty}^0 e^{-x^2}\mathbf{d}x=\dfrac{\sqrt{\pi}}{2},\qquad \int_{0}^{+\infty}e^{-x} \mathbf{d}x=1,\qquad \int_{-\infty}^{+\infty}\int_{-\infty}^{+\infty}e^{-x^2-y^2}\mathbf{d}x\mathbf{d}y=\pi∫−∞0​e−x2dx=2π​​,∫0+∞​e−xdx=1,∫−∞+∞​∫−∞+∞​e−x2−y2dxdy=π

>>> integrate(cos(x**2),(x,-oo,oo))
sqrt(2)*sqrt(pi)/2
>>> integrate(sin(x**2),(x,-oo,oo))
sqrt(2)*sqrt(pi)/2>>> integrate(exp(-x**2),(x,-oo,0))
sqrt(pi)/2
>>> integrate(exp(-x),(x,0,oo))
1
>>> integrate(exp(-x**2-y**2),(x,-oo,+oo),(y,-oo,+oo))
pi>>> integrate(log(x),(x,0,1))
-1

求多重积分

求多重积分,先求里面的积分,再求外面的

例如:f(x)=∫0x2xdx,∫03f(x)dxf(x)=\int_0^x 2x \mathbf{d}x, \qquad\int_0^3 f(x)\mathbf{d}xf(x)=∫0x​2xdx,∫03​f(x)dx

>>> x,t=sympy.symbols('x t')
>>> f=2*t
>>> g
(x + 1)**(1/x)
>>> g=integrate(f,(t,0,x))
>>> integrate(g,(x,0,3))
9

求极限

求极限用 limit(func,x,x_0)

在sympy中极限容易求出,它们遵循极限语法 limit(function, variable, point) ,所以计算 x→0x\to0x→0 时 f(x)f(x)f(x) 的极限,即 limit(f, x, 0)

lim⁡x→0(1+x)1x=e,lim⁡x→∞(1+1x)x=e\displaystyle\lim_{x\to0}(1+x)^{\frac{1}{x}}=e,\qquad \lim_{x\to \infty}\left(1+\dfrac{1}{x}\right)^x=ex→0lim​(1+x)x1​=e,x→∞lim​(1+x1​)x=e

>>> from sympy.abc import x,f,g,h,E
>>> from sympy import limit
>>> limit(1/x,x,0,'+')  # x-->+0
oo
>>> f=sin(x)/x     # 定义函数
>>> g=(1+x)**(1/x)
>>> h=(1+1/x)**x
>>> limit(f,x,0)   # 三个参数是 函数,变量,趋向值
1
>>> limit(g,x,0)
E
>>> limit(h,x,oo)
E

求极限 Sympy 是使用limit(代数式,变量,极限值) 函数来求极限的,比如我们要求 lim⁡x→0sin(x)x\displaystyle\lim_{x\to0}\dfrac{sin(x)}{x}x→0lim​xsin(x)​ 的值。

>>> from sympy import *
>>> x = symbols('x')
>>> limit(sin(x)/x, x, 0)

执行后即可得到结果为 1。

求和

  1. 级数求和summation(function,(n,1,100)) S=∑n=11002nS=\displaystyle\sum_{n=1}^{100}{2n}S=n=1∑100​2n
>>> import sympy
>>> n=sympy.Symbol('n')  # 定义变量
>>> sympy.summation(2*n,(n,1,100)) # 前面参数放函数,后面放变量的变化范围
10100
  1. 解带有求和式子的方程
    ∑i=15x+10x=15\displaystyle\sum_{i=1}^5 x+10x=15i=1∑5​x+10x=15

解释一下,iii 可以看做是循环变量,就是 xxx 自己加五次, 先定义变量,再写出方程。

>>> x=sympy.Symbol('x')
>>> i=sympy.Symbol('i')>>> solve(summation(x,(i,1,5))+10*x-15,x)
[1]f=sympy.summation(x,(i,1,5))+10*x-15
result=sympy.solve(f,x)
print(result)

复数

>>>from sympy import Symbol, exp, I
>>>x = Symbol("x")
>>>exp(I*x).expand()
exp(I*x)
>>>exp(I*x).expand(complex=True)
I*exp(-im(x))*sin(re(x)) + cos(re(x))*exp(-im(x))
>>>x = Symbol("x", real=True)
>>>exp(I*x).expand(complex=True)
I*sin(x) + cos(x)

函数

三角函数

>>> sin(x+y).expand(trig=True)
sin(x)*cos(y) + sin(y)*cos(x)
>>> cos(x+y).expand(trig=True)
-sin(x)*sin(y) + cos(x)*cos(y)
>>> sin(I*x)
I*sinh(x)
>>> sinh(I*x)
I*sin(x)
>>> asinh(I)
I*pi/2
>>> asinh(I*x)
I*asin(x)
>>> sinh(x).series(x,0,10)
x + x**3/6 + x**5/120 + x**7/5040 + x**9/362880 + O(x**10)
>>> asin(x).series(x,0,10)
x + x**3/6 + 3*x**5/40 + 5*x**7/112 + 35*x**9/1152 + O(x**10)
>>> asinh(x).series(x,0,10)
x - x**3/6 + 3*x**5/40 - 5*x**7/112 + 35*x**9/1152 + O(x**10)

球谐函数

球谐函数建议阅读原文

球谐函数可以看作是将单位球面上的每一点(或者三维空间中的每个方向)映射到一个复数函数值.

从在物理中的来源上看, 球谐函数是 Laplace 算子角项部分的一组正交完备的解.

从数学上看, 球谐函数实际上是 SO(3) 一组不可约表示的基, 而 Laplace 算子角项部分也正好就是 SO(3) 的 Casimir 算子.

Sympy里用 Ynm(1, 0, theta, phi)

>>> from sympy.abc import theta,phi
>>> Ynm(1, 0, theta, phi)
Ynm(1, 0, theta, phi)
>>> Ynm(1, 1, theta, phi)
Ynm(1, 1, theta, phi)
>>> Ynm(2, 1, theta, phi)
Ynm(2, 1, theta, phi)

阶乘和伽马函数

>>> x = Symbol('x')
>>> y = Symbol('y', integer=True)  # 定义整数变量
>>> factorial(x)
factorial(x)
>>> factorial(y)
factorial(y)
>>> factorial(x).series(x,0,3)
1 - EulerGamma*x + x**2*(EulerGamma**2/2 + pi**2/12) + O(x**3)

Zeta函数

>>> zeta(4,x)
zeta(4, x)
>>> zeta(4,1)
pi**4/90
>>> zeta(4,2)
-1 + pi**4/90
>>> zeta(4,3)
-17/16 + pi**4/90
>>> zeta(4,4)
-1393/1296 + pi**4/90

多项式

>>> chebyshevt(2,x)
2*x**2 - 1
>>> chebyshevt(4,x)
8*x**4 - 8*x**2 + 1
>>> legendre(2,x)
3*x**2/2 - 1/2
>>> legendre(8,x)
6435*x**8/128 - 3003*x**6/32 + 3465*x**4/64 - 315*x**2/32 + 35/128
>>> assoc_legendre(2,1,x)
-3*x*sqrt(1 - x**2)
>>> assoc_legendre(2,2,x)
3 - 3*x**2
>>> hermite(3,x)
8*x**3 - 12*x

常微分ODE方程

在常微分方程(Ordinary Differential Equation)中,最常见的就是解方程,而解方程主要是靠 dsolve 函数。

求解下列常微分方程:
dfdx+f(x)=0d2fdx2+f(x)=0d3fdx3+f(x)=0\dfrac{\mathbb{d}f}{\mathbb{d}x}+f(x)=0\\ \dfrac{\mathbb{d}^2f}{\mathbb{d}x^2}+f(x)=0\\ \dfrac{\mathbb{d}^3f}{\mathbb{d}x^3}+f(x)=0dxdf​+f(x)=0dx2d2f​+f(x)=0dx3d3f​+f(x)=0

>>> f=Function('f')  #一定要声明f=Function('f')
>>> f(x).diff(x,x)+f(x)  #注意在使用输入该命令之前,f要先声明
f(x) + Derivative(f(x), (x, 2))
>>> dsolve(f(x).diff(x,x)+f(x),f(x))
Eq(f(x), C1*sin(x) + C2*cos(x))>>> f = sympy.Function('f') # 定义函数f
>>> sympy.dsolve(sympy.Derivative(f(x),x) + f(x), f(x))
Eq(f(x), C1*exp(-x))
>>> sympy.dsolve(sympy.Derivative(f(x),x,2) + f(x), f(x))
Eq(f(x), C1*sin(x) + C2*cos(x))
>>> sympy.dsolve(sympy.Derivative(f(x),x,3) + f(x), f(x))
Eq(f(x), C3*exp(-x) + (C1*sin(sqrt(3)*x/2) + C2*cos(sqrt(3)*x/2))*sqrt(exp(x)))

而常微分方程对于不同的方程类型也有着不同的解法,可以使用 classify_ode 来判断常微分方程的类型:

>>> sympy.classify_ode(sympy.Derivative(f(x),x)+f(x),f(x))
('separable', '1st_exact', '1st_linear', 'almost_linear', '1st_power_series',
'lie_group', 'nth_linear_constant_coeff_homogeneous', 'separable_Integral',
'1st_exact_Integral', '1st_linear_Integral', 'almost_linear_Integral')
>>> sympy.classify_ode(sympy.Derivative(f(x),x,2)+f(x),f(x))
('nth_linear_constant_coeff_homogeneous', '2nd_power_series_ordinary')
>>> sympy.classify_ode(sympy.Derivative(f(x),x,3)+f(x),f(x))
('nth_linear_constant_coeff_homogeneous',)

偏微分PDE方程

在偏微分方程(Partitial Differential Equation)中,同样可以直接求解和判断偏微分方程的类型,分别使用函数 pdsolve() 和 classify_pde()。假设 f=f(x,y)f=f(x,y)f=f(x,y) 是一个二元函数,分别满足以下偏微分方程:

∂f∂x+∂f∂y=0∂f∂x+∂f∂y+f=0∂f∂x+∂f∂y+f+10=0\dfrac{\partial f}{\partial x}+\dfrac{\partial f}{\partial y}=0\\ \dfrac{\partial f}{\partial x}+\dfrac{\partial f}{\partial y}+f=0\\ \dfrac{\partial f}{\partial x}+\dfrac{\partial f}{\partial y}+f+10=0∂x∂f​+∂y∂f​=0∂x∂f​+∂y∂f​+f=0∂x∂f​+∂y∂f​+f+10=0

>>> f = sympy.Function("f")(x,y)
>>> f
f(x, y)
>>> sympy.pdsolve(sympy.Derivative(f,x)+sympy.Derivative(f,y),f)
Eq(f(x, y), F(x - y))
>>> sympy.pdsolve(f.diff(x)+f.diff(y)+f,f)
Eq(f(x, y), F(x - y)*exp(-x/2 - y/2))
>>> sympy.pdsolve(f.diff(x)+f.diff(y)+f+10,f)
Eq(f(x, y), F(x - y)*exp(-x/2 - y/2) - 10)

查看类型就用 classify_pde() 函数:

>>> sympy.classify_pde(f.diff(x)+f.diff(y),f)
('1st_linear_constant_coeff_homogeneous',)
>>> sympy.classify_pde(f.diff(x)+f.diff(y)+f,f)
('1st_linear_constant_coeff_homogeneous',)
>>> sympy.classify_pde(f.diff(x)+f.diff(y)+f+10,f)
('1st_linear_constant_coeff', '1st_linear_constant_coeff_Integral')

不过目前的 PDE 解法貌似只支持一阶偏导数,二阶或者以上的偏导数就不支持了。

数论

在数论中,素数就是一个最基本的概念之一。而素数的批量计算,比较快的方法就是筛法(sieve method)。
在 sympy 中,同样有 sympy.sieve 这个工具,用于计算素数。如果想输出前100个素数:

>>> sympy.sieve._reset()
>>> sympy.sieve.extend_to_no(100)
>>> sympy.sieve._list
array('l', [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239,
241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337,
347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433,
439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631])

如果想输出一个区间内的所有素数,可以使用 primerange(a,b) 函数:

>>> [i for i in sympy.sieve.primerange(50,200)]
[53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199]

search() 函数是为了计算某个数附近是第几个素数:

>>> sympy.sieve.search(10)
(4, 5) # 10在第4个素数和第5个素数之间
>>> sympy.sieve.search(11)
(5, 5) # 5是第5个素数
>>> sympy.sieve.search(110)
(29, 30) # 110在第29和第30个素数之间
>>> sympy.sieve.search(18)
(7, 8) # 18在第7和第8个素数之间

如果只想获得第 nnn 个素数,则使用函数 sympy.ntheory.generate.prime(n) 即可。如果是希望计算 xxx 后面的下一个素数,使用 sympy.ntheory.generate.nextprime(x) 即可。判断 xxx 是否是素数,可以使用
sympy.ntheory.generate.isprime(x)

>>> sympy.ntheory.generate.prime(10)
29
>>> sympy.ntheory.generate.nextprime(10)
11
>>> sympy.ntheory.generate.nextprime(11)
13sympy-tutorial.md 2/3/2020
17 / 17
>>> sympy.ntheory.generate.isprime(11)
True
>>> sympy.ntheory.generate.isprime(12)
False

除此之外,SymPy 的数论方法还有很多,需要读者根据 SymPy 的官方文档自行探索。

线性代数

矩阵

在矩阵论中,最常见的就是单位矩阵了,而单位矩阵只与一个参数有关,那就是矩阵的大小, Sympy中用函数 eye(n,m) 创建 n×mn\times mn×m的单位矩阵。

>>> eye(4)
Matrix([
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
>>> eye(2,3)
Matrix([
[1, 0, 0],
[0, 1, 0]])

另外还有全零 zeros(n,m)全一 ones(n,m) 矩阵,意思就是矩阵中的所有值全部是 零和一

>>> ones(3,4)
Matrix([
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]])
>>> zeros(3,2)
Matrix([
[0, 0],
[0, 0],
[0, 0]])

而对角矩阵也可以使用 diag(n,m,k,...) 轻松获得:

>>> diag(1,2,3,4)
Matrix([
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]])

一般矩阵由矩阵类 Matrix([[],[]] 创建

>>>from sympy import Matrix
>>> A=Matrix([[1,0],[0,1]])
>>> B=Matrix([[1,1],[0,2]])
>>> A+B  #加
Matrix([
[2, 1],
[0, 3]])
>>> A-B  #减
Matrix([
[0, -1],
[0, -1]])
>>> A*B  #乘
Matrix([
[1, 1],
[0, 2]])
>>> A*B**-1  #逆矩阵
Matrix([
[1, -1/2],
[0,  1/2]])
>>> B**-1
Matrix([
[1, -1/2],
[0,  1/2]])
>>> A.T  #转置矩阵
Matrix([
[1, 0],
[0, 1]])
>>> B.T
Matrix([
[1, 0],
[1, 2]])
>>> A.det()  #行列式的值
1
>>> B.det()
2

不只是数值矩阵,亦可为代数矩阵,即矩阵中存在符号:

>>>x = Symbol('x')
>>>y = Symbol('y')
>>>A = Matrix([[1,x], [y,1]])
>>>A
[1, x]
[y, 1]
>>>A**2
[1 + x*y,     2*x]
[    2*y, 1 + x*y]

在某些情况下,需要对矩阵进行加上一行或者加上一列的操作,在这里就可以使用 row_insert 或者
col_insert 函数:第一个参数表示插入的位置,第二个参数就是相应的行向量或者列向量。
而在删除上就很简单了,直接使用 row_del 或者 col_del 即可.

>>> A.row_insert(1,Matrix([[10,10]]))
Matrix([
[ 1,  0],
[10, 10],
[ 0,  1]])
>>> A.col_insert(0,Matrix([3,5]))
Matrix([
[3, 1, 0],
[5, 0, 1]])
>>> A.row_del(0)
>>> A
Matrix([[0, 1]])
>>> A.col_del(1)
>>> A
Matrix([[0]])

在对角化方面,同样可以使用 eigenvals(),eigenvects(), diagonalize() 函数

>>> A=sympy.Matrix([[1,1],[0,2]])
>>> A
Matrix([
[1, 1],
[0, 2]])
>>> A.eigenvals() # 特征值
{1: 1, 2: 1}
>>> A.eigenvects() # 特征向量
[(1, 1, [Matrix([
[1],
[0]])]), (2, 1, [Matrix([
[1],
[1]])])]
>>> A.diagonalize() # 对角化
(Matrix([
[1, 1],
[0, 1]]), Matrix([
[1, 0],
[0, 2]]))

eigenvals() 返回的结果中,第一个表示特征值,第二个表示该特征值的重数。在特征向量 eigenvects()
中,第一个表示特征值,第二个表示特征值的重数,第三个表示特征向量。
在对角化 diagonalize() 中,第一个矩阵表示 PPP,第二个矩阵表示 D,A=P×D×P−1D, A=P\times D\times P^{-1}D,A=P×D×P−1。
在矩阵中,最常见的还是多元一次方程的解。如果要求 Ax=bAx=bAx=b 的解,可以有以下方案:

>>> A
Matrix([
[1, 1],
[0, 2]])
>>> b = sympy.Matrix([3,5])
>>> b
Matrix([
[3],
[5]])
>>> A**-1*b
Matrix([
[1/2],
[5/2]])
>>> sympy.linsolve((A,b))
FiniteSet((1/2, 5/2))
>>> sympy.linsolve((A,b),[x,y])
FiniteSet((1/2, 5/2))

集合

集合论可以说是数学的基础,在任何数学的方向上都能够看到集合论的身影。在 SymPy 里面,有一个类叫做
sympy.sets。在集合论里面,常见的就是 边界,补集,包含,并集,交集 等常见的操作。但是感觉 SymPy 中的集合论操作主要集中在实数域或者复数域上。

定义闭区间和开区间(Interval(s,e),Interval.open(s,e))

对于闭区间 I=[0,1]I=[0,1]I=[0,1] 和开区间 J=(0,1)J=(0,1)J=(0,1) 而言,在 SymPy 中使用以下方法来表示:

>>> I = sympy.Interval(0,1)
>>> I
Interval(0, 1)
>>> J = sympy.Interval.open(0,1)
>>> J
Interval.open(0, 1)
>>> K = sympy.Interval(0.5,2)
>>> K
Interval(0.500000000000000, 2)
>>> K.start
0.500000000000000
>>> K.end
2

长度用 .measure方法来表示

>>> K.measure
1.50000000000000

其闭包用 .closure方法来表示

>>> K.closure
Interval(0.500000000000000, 2)

其内点用 .interior方法来表示

>>> K.interior
Interval.open(0.500000000000000, 2)

判断其边界条件可以使用 left_open 或者 right_open 来做

>>> K.left_open
False
>>> K.right_open
False
>>> J.left_open
True

两个集合之间的操作

#Interval(start, end, left_open=False, right_open=False)
#- Only real end points are supported
#| - Interval(a, b) with a > b will return the empty set
#| - Use the evalf() method to turn an Interval into an mpmath
#| 'mpi' interval instance
>>> I = sympy.Interval(0,1) # I =[0,1]
>>> K = sympy.Interval(0.5,2) # K=[0.5,2]
>>> I.intersect(K)
Interval(0.500000000000000, 1)
>>> I.union(K)
Interval(0, 2)
>>> I - K
Interval.Ropen(0, 0.500000000000000) # [0,0.5)
>>> K - I
Interval.Lopen(1, 2) #(1,2]
>>> I.symmetric_difference(K)
Union(Interval.Ropen(0, 0.500000000000000), Interval.Lopen(1, 2))

实数集 R\mathbb{R}R 在 SymPy 中用 sympy.S.Reals 来表示,自然数 N\mathbb{N}N 使用 sympy.S.Naturals,非负整数用 sympy.S.Naturals0,整数 Z\mathbb{Z}Z用 sympy.S.Integers 来表示。补集的计算可以用 减号,也可以使用
complement 函数。

>>> sympy.S.Reals
Reals>>> sympy.S.Reals - I
Union(Interval.open(-oo, 0), Interval.open(1, oo))
>>> I.complement(sympy.S.Reals)
Union(Interval.open(-oo, 0), Interval.open(1, oo))
>>> sympy.S.Reals.complement(I)
EmptySet
>>> I.complement(K)
Interval.Lopen(1, 2)

逻辑

在逻辑运算中,我们可以使用 A,B,CA,B,CA,B,C 来代表元素。&, |, ~, >> 分别表示 AND,OR,NOT,imply。而逻辑
运算同样可以使用 sympy.simplify_logic 简化。

>>> A,B,C=sympy.symbols('A B C')
>>> sympy.simplify_logic(A|(A&B))
A
>>> sympy.simplify_logic((A>>B) & (B>>A))
(A & B) | (~A & ~B)
>>> A >> B
Implies(A, B)

级数

级数展开

高数中Taylor Series 有泰勒展开式,拉格朗日展开式

对于常见函数的 Taylor Series,SymPy 也是有非常简便的方法,那就是 series 函数。其参数包括 expr,x,x0,n,direxpr, x, x_0 ,n, direxpr,x,x0​,n,dir,分别对应着表达式 expr,函数的自变量 xxx,Taylor Series 的中心点 x0x_0x0​,nnn 表示阶数,dirdirdir 表示方向,包括 “±”,"-","+",分别表示 x→x0,x→x0−,x→x0+x\to x_0,x\to x_0^-, x\to x_0^+x→x0​,x→x0−​,x→x0+​。

ex=1+x+x22!+x33!+x44!+...+xnn!+o(xn)e^x=1+x+\dfrac{x^2}{2!}+\dfrac{x^3}{3!}+\dfrac{x^4}{4!}+...+\dfrac{x^n}{n!}+o(x^n)ex=1+x+2!x2​+3!x3​+4!x4​+...+n!xn​+o(xn)
比如当 n=3n=3n=3 时,
ex=1+x+x22+o(x3)e^x=1+x+\dfrac{x^2}{2}+o(x^3)ex=1+x+2x2​+o(x3)

这里实现的方法是:sympy 代数式.series(变量, 0, n)func.series(var,point, order)

>>> from sympy import *
>>> from sympy.abc import x,y,z,a,b,c,u,v,w,t,h,k,A,B,C,D,E,F>>> exp(x).series(x,0,6)
1 + x + x**2/2 + x**3/6 + x**4/24 + x**5/120 + O(x**6)
>>> (1/cos(x)).series(x,0,10)
1 + x**2/2 + 5*x**4/24 + 61*x**6/720 + 277*x**8/8064 + O(x**10)
>>> (sin(x)).series(x,0,10)
x - x**3/6 + x**5/120 - x**7/5040 + x**9/362880 + O(x**10)
>>> (cos(x)).series(x,0,10)
1 - x**2/2 + x**4/24 - x**6/720 + x**8/40320 + O(x**10)
>>> exp(I*x).series(x,0,10)
1 + I*x - x**2/2 - I*x**3/6 + x**4/24 + I*x**5/120 - x**6/720 - I*x**7/5040 + x**8/40320 + I*x**9/362880 + O(x**10)

以上可以看出 eix=cos⁡(x)+isin⁡(x),ex=∑n=0∞xnn!\displaystyle e^{ix}=\cos(x)+i \sin(x), \;e^x=\sum_{n=0}^{\infty}\dfrac{x^n}{n!}eix=cos(x)+isin(x),ex=n=0∑∞​n!xn​

级数收敛

计算某个级数是发散的,还是收敛的,就可以使用 is_convergent() 函数。

>>> n = sympy.Symbol("n", integer =True)
>>> n
n
>>> sympy.Sum(1/n,(n,1,sympy.oo)).is_convergent()
False
>>> sympy.Sum(1/n**2,(n,1,sympy.oo)).is_convergent()
True

级数求和

如果想计算出收敛级数的值,加上 doit() 函数即可;如果想计算有效数字,加上 evalf() 函数即可。

>>> sympy.Sum(1/n**2, (n,1,sympy.oo)).evalf()
1.64493406684823
>>> sympy.Sum(1/n**2, (n,1,sympy.oo)).doit()
pi**2/6
>>> sympy.Sum(1/n**3, (n,1,sympy.oo)).evalf()
1.20205690315959
>>> sympy.Sum(1/n**3, (n,1,sympy.oo)).doit()
zeta(3)

级数连乘

除了加法之外,SymPy 也支持连乘,其符号是 sympy.Product

>>> sympy.Product(n/(n+1), (n,1,sympy.oo)).is_convergent()
False
>>> sympy.Product(sympy.cos(sympy.pi/n), (n,1,sympy.oo)).is_convergent()
True
>>> sympy.Product(sympy.cos(sympy.pi/n), (n,1,sympy.oo)).doit()
Product(cos(pi/n), (n, 1, oo))
>>> sympy.Product(sympy.cos(sympy.pi/n), (n,1,sympy.oo)).evalf()
Product(cos(pi/n), (n, 1, oo))

求代数式的浮点数 .evalf(n)方法

evalf() 函数可以用求出代数式的浮点数。

>>> (1/x).evalf(subs={x: 3.0}, n=21)
0.333333333333333333333
rather than
>>> (1/x).subs({x: 3.0}).evalf(21)
0.333333333333333314830
>>> E.evalf(10)
2.718281828
>>> pi.evalf(15)
3.14159265358979
>>> sqrt(2).evalf()  #查看实数的有效数字,缺省15
1.41421 35623 7310
>>> sqrt(3).evalf()
1.73205080756888

SymPy的范畴论工具

SymPy 还支持 范畴论(Category Theory)的一些计算方法,在这里简要地列举一下。

>>> A = sympy.categories.Object("A")
>>> B = sympy.categories.Object("B")
>>> f = sympy.categories.NamedMorphism(A,B,"f")
>>> f.domain
Object("A")
>>> f.codomain
Object("B")

由于范畴论是数学的“黑话”,因此其余方法留给范畴论的科研人员自行翻阅

系数匹配

使用 .match()方法,引用Wild类,来执行表达式的匹配。该方法会返回一个字典。 帮助文档可以访问 help(Wild)

>>>from sympy import *
>>>x = Symbol('x')
>>>p = Wild('p')
>>>(5*x**2).match(p*x**2)
{p_: 5}
>>>q = Wild('q')
>>>(x**2).match(p*x**q)
{p_: 1, q_: 2}>>> from sympy import Wild, WildFunction, cos, pi
>>> from sympy.abc import x, y, z
>>> a = Wild('a')
>>> x.match(a)
{a_: x}
>>> pi.match(a)
{a_: pi}
>>> (3*x**2).match(a*x)
{a_: 3*x}
>>> cos(x).match(a)
{a_: cos(x)}
>>> b = Wild('b', exclude=[x])
>>> (3*x**2).match(b*x)
>>> b.match(a)
{a_: b_}
>>> A = WildFunction('A')
>>> A.match(a)
{a_: A_}

如果匹配不成功,则返回None:

>>>print (x+1).match(p**x)
None

可以使用Wild类的exclude参数(排除参数),排除不需要和无意义的匹配结果,来保证结论中的显示是唯一的:

>>>x = Symbol('x')
>>>p = Wild('p', exclude=[1,x])
>>>print (x+1).match(x+p) # 1 is excluded
None
>>>print (x+1).match(p+1) # x is excluded
None
>>>print (x+1).match(x+2+p) # -1 is not excluded
{p_: -1}

打印输出

有一个打印的有效模块,sympy.printing。用这个模块实现其他的打印。
可以各种方式打印输出,如 pprint, print, latex, python, mathml,...

标准 print

str(expression) 返回如下:

>>> from sympy import Integral
>>> from sympy.abc import x
>>> print(x**2)
x**2
>>> str(x**2)
'x**2'
>>> print(1/x)
1/x
>>> print(Integral(x**2, x))
Integral(x**2, x)

字符艺术打印(Pretty Printing) pprint

pretty(expr), pretty_print(expr), pprint(expr): 分别返回或者输出,,表达式的漂亮描述。

个人觉得这个打印不是很能接受,仅仅只是 ASCII 艺术模仿 LaTeX 输出。看起来很不是滋味,故不推荐。

pprint 函数可以输出不错的 ascii 艺术:

>>>from sympy import Integral, pprint
>>>from sympy.abc import x
>>>pprint(x**2) #doctest: +NORMALIZE_WHITESPACE2x
>>>pprint(1/x)1-x
>>>pprint(Integral(x**2, x))/||  2| x  dx|/

在 python 解释器中,为使 pretty printing 为默认输出,使用:

>>> import sys
>>> sys.displayhook = pprint
>>> var("x")x
>>> x**3/33x--3
>>> Integral(x**2, x) #doctest: +NORMALIZE_WHITESPACE/||  2| x  dx|/

Python字符串打印成一行 Python printing


>>> from sympy.printing.python import python
>>> from sympy import Integral
>>> from sympy.abc import x
>>> print(python(x**2))
x = Symbol('x')
e = x**2
>>> python(x**2)
"x = Symbol('x')\ne = x**2"
>>> print(python(1/x))
x = Symbol('x')
e = 1/x
>>> python(1/x)
"x = Symbol('x')\ne = 1/x"
>>> print(python(Integral(x**2, x)))
x = Symbol('x')
e = Integral(x**2, x)
>>> python(Integral(x**2,x))
"x = Symbol('x')\ne = Integral(x**2, x)"

输出成LaTeX形式 LaTeX printing

latex(expr), print_latex(expr):分别返回或者输出,LaTex描写的表达式。

个人推荐此种 LaTeX 打印输出方式,方便与LaTeX对接。

>>>from sympy import Integral, latex
>>>from sympy.abc import x
>>> latex(x**2)
'x^{2}'
>>> latex(x**2+y**2)
'x^{2} + y^{2}'
>>> latex(1/x)
'\\frac{1}{x}'
>>> print(latex(1/x))
\frac{1}{x}
>>> print(latex(Integral(x**2, x)))
\int x^{2}\,dx
>>> latex(Integral(x**2,x))
'\\int x^{2}\\, dx'

输出成MathML形式 MathML

mathml(expr), print_mathml(expr): 分别返回或者输出,MathML描写的表达式.

>>>from sympy.printing.mathml import mathml
>>>from sympy import Integral, latex
>>>from sympy.abc import x
>>>print(mathml(x**2))
<apply><power/><ci>x</ci><cn>2</cn></apply>
>>> mathml(x**2)
'<apply><power/><ci>x</ci><cn>2</cn></apply>'
>>> print(mathml(1/x))
<apply><power/><ci>x</ci><cn>-1</cn></apply>

数学符号

常用数学符合列表如下:

sympy.I  #虚数单位i
sympy.E  #自然对数低e
sympy.oo #无穷大
sympy.pi #圆周率
sympy.root(8,3)    #求n次方根
sympy.log(1024,2)  #求对数
sympy.factorial(4) #求阶乘
sympy.sin(sympy.pi)  #三角函数
sympy.tan(sympy.pi/4)
sympy.cos(sympy.pi/2)
pi.evalf(10)  #查看否点数的小数值
(pi+exp(1)).evalf()
>>> E**(I*pi)+1  #欧拉公式 e^{i\pi}+1=0
0

本文是本人学习过程中,总结了官方教程中的部分内容,目的是方便快速查找需要的内容。主要为一些复杂的符号运算提供机器运算结果,并验证自己的计算结果。后续会提供部分实际应用案例。

相关参考链接

  • Sympy源码库
  • 用Python学数学
  • SymPy库常用函数
  • Sympy’s documentation

Sympy代数符号运算库相关推荐

  1. python @符号_用Python学数学之Sympy代数符号运算

    在我们初.高中和大学近10年的学习时间里,数学一直占据着非常大的分量,但是回忆过去可以发现,我们把大量的时间都花在反复解题.不断运算上,计算方法.运算技巧.笔算能力以及数学公式的记忆仿佛成了我们学习数 ...

  2. 用Python学数学之Sympy代数符号运算

    在我们初.高中和大学近10年的学习时间里,数学一直占据着非常大的分量,但是回忆过去可以发现,我们把大量的时间都花在反复解题.不断运算上,计算方法.运算技巧.笔算能力以及数学公式的记忆仿佛成了我们学习数 ...

  3. python符号计算_用Python学数学之Sympy代数符号运算

    在我们初.高中和大学近10年的学习时间里,数学一直占据着非常大的分量,但是回忆过去可以发现,我们把大量的时间都花在反复解题.不断运算上,计算方法.运算技巧.笔算能力以及数学公式的记忆仿佛成了我们学习数 ...

  4. python sympy库实现代数符号运算及表达式推导

    matlab是工程和科研人员必备的工具利器, 其一大功能就是可以实现代数符号运算,以及表达式推导,或者复杂表达式的化简工作, 是广大粗心而没有耐心计算人员的福音. clc close all clea ...

  5. python中符号计算输出数学_Python科学计算与数据处理—符号运算库.doc

    Python 科学计算与数据处理 - 符号运算库 符号运算库目录从示例开始欧拉恒等式球体体积数学表达 式符号数值运算符和函数符号运算表达式转换和简化方程目录微分 方程积分其他函数符号运算库. 它的目标 ...

  6. oracle日期虚数0去掉,第 14 章 使用复数运算库

    第 14 章 使用复数运算库 复数是由实部和虚部组成的数.例如: 3.2 + 4i 1 + 3i 1 + 2.3i 在特例情况下,如 0 + 3i 是纯虚数,通常写为 3i:5 + 0i 是纯实数,通 ...

  7. 认知NumPy数学运算库

    机器学习用到的数学运算离不开数学运算库.数学运算库可以让我们摆脱诸如向量运算.矩阵运算.基本统计运算等复杂的数学运算,无需为这些复杂的数学运算编写运算代码,而是把精力用到科学研究上. NumPy是Py ...

  8. 备忘: MIRACL 大数运算库使用手册

    <MIRACL 大数运算库使用手册> 作者: 游贵荣 中文使用手册: http://blog.csdn.net/shuilan0066/article/details/8520337htt ...

  9. SM2椭圆曲线公钥密码算法的C语言实现(基于Miracl大数运算库)

    SM2椭圆曲线公钥密码算法的C语言实现(基于Miracl大数运算库) 实验环境 预备知识 FpF_pFp​ 及椭圆曲线 素域 FpF_pFp​ FpF_pFp​ 上的椭圆曲线 FpF_pFp​ 上椭圆 ...

最新文章

  1. python绘制3维图-1、2、3维图见过,用Python画出来的六维图见过么?
  2. JDK8 Stream 效率如何?
  3. (JavaWeb)JSP,JSTL
  4. 从Bayesian Deep Learning到Adversarial Robustness新范式
  5. Java中最早期的集合Vector
  6. 【Linux】一步一步学Linux——echo命令(203)
  7. 已知三角形三点坐标求角度_细心研磨椭圆焦点三角形,这肯定是最全的解释。...
  8. python按条件删除行_python – 根据条件删除行组
  9. H3C 重置cons 密码,清空配置
  10. HiWork发布1.7.0新版本——可开启频道公开链接,增加HiWork客服功能及集成应用麦客
  11. 使用PHP的http请求客户端guzzle如何添加请求头
  12. k8s中部署prometheus监控告警系统-prometheus系列文章第一篇
  13. python语言中、复数类型中实数部分_python学习03.02:Python数值类型(整形、浮点型和复数)及其用法...
  14. Vue如何将baes64格式的图片转成普通格式
  15. pygame开发2048游戏(附源代码)
  16. 市值高达67亿的1元“壳股”海润光伏 谁敢接盘?
  17. SecureCRT修改字体和字体高亮显示
  18. ext.net 后台方法调用
  19. Buck开关调整器拓扑
  20. Mathematica9.0中文版软件下载详细图文安装步骤!

热门文章

  1. oracle mrp全称,【简答题】MRP和MRP2的中文和英文全称分别是什么? (20.0分)
  2. 【Kotlin基础系列】第2章 基本语法(1)
  3. Spring Cloud Alibaba 版本对照详情
  4. 面面俱到:项目七个线条的管理办法
  5. DDD领域驱动开发概念介绍及简单示例
  6. 2020 软件测试 Postman高级使用——Tests 断言校验返回结果
  7. 写一篇计算机软硬件维护的实习日记内容丰富点
  8. 蒂姆首次获得大师赛冠军,网友:新一代网球王子啊
  9. TNS-12535: TNS:operation timed out
  10. PMP 认证考试流程