Python之Sympy代数符号运算库 计算器与数学计算机代数系统 CASSympy符号运算的基本使用指南 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) pprintPython字符串打印成一行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,mathprint(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 + 1x + 1>>> x,y,z=symbols('x y z')>>> crazy = symbols('unrelated')>>> crazy + 1unrelated + 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/2
,Rational(5,2)
代表5/2
,等等。
>>>from sympy import *>>>a = Rational(1,2)>>>a1/2>>>a*21>>>Rational(2)**50/Rational(10)**501/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)**2x**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 theforce
hint must beTrue
:
>>> 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 aroundas_real_imag()
. Most objects that wish to redefine_eval_expand_complex()
should consider redefiningas_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 ofsin(n*x)
andcos(n*x)
in terms ofsin(x)
andcos(x)
are not unique, due to the identity sin2(x)+cos2(x)=1\sin^2(x) + \cos^2(x)= 1sin2(x)+cos2(x)=1. The current implementation uses the form obtained fromChebyshevpolynomials, 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,cosfrom sympy.abc import x,yy = 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=plexes)FiniteSet(1, -1/2 - sqrt(3)*I/2, -1/2 + sqrt(3)*I/2)>>> solveset(Eq(exp(x),x),x, domain=plexes)ConditionSet(x, Eq(-x + exp(x), 0), Complexes)>>> solveset(exp(x),x)EmptySet()>>> solveset(exp(x)-1,x) #缺省为ComplexesImageSet(Lambda(_n, 2*_n*I*pi), Integers)>>> solveset(exp(x)-1,x,domain=S.Reals){0}>>> solveset(exp(x)-1,x,domain=plexes)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∫−∞0e−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)=∫0x2xdx,∫03f(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)
:
limx→0(1+x)1x=e,limx→∞(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-->+0oo>>> 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(代数式,变量,极限值)
函数来求极限的,比如我们要求 limx→0sin(x)x\displaystyle\lim_{x\to0}\dfrac{sin(x)}{x}x→0limxsin(x) 的值。
>>> from sympy import *>>> x = symbols('x')>>> limit(sin(x)/x, x, 0)
执行后即可得到结果为 1。
求和
级数求和summation(function,(n,1,100))
S=∑n=11002nS=\displaystyle\sum_{n=1}^{100}{2n}S=n=1∑1002n>>> import sympy>>> n=sympy.Symbol('n') # 定义变量>>> sympy.summation(2*n,(n,1,100)) # 前面参数放函数,后面放变量的变化范围10100
解带有求和式子的方程
∑i=15x+10x=15\displaystyle\sum_{i=1}^5 x+10x=15i=1∑5x+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-15result=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)>>> ff(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._listarray('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/20 / 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**-1Matrix([[1, -1/2],[0, 1/2]])>>> A.T #转置矩阵Matrix([[1, 0],[0, 1]])>>> B.TMatrix([[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)>>> AMatrix([[0, 1]])>>> A.col_del(1)>>> AMatrix([[0]])
在对角化方面,同样可以使用eigenvals(),eigenvects(), diagonalize()
函数
>>> A=sympy.Matrix([[1,1],[0,2]])>>> AMatrix([[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 的解,可以有以下方案:
>>> AMatrix([[1, 1],[0, 2]])>>> b = sympy.Matrix([3,5])>>> bMatrix([[3],[5]])>>> A**-1*bMatrix([[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)>>> IInterval(0, 1)>>> J = sympy.Interval.open(0,1)>>> JInterval.open(0, 1)>>> K = sympy.Interval(0.5,2)>>> KInterval(0.500000000000000, 2)>>> K.start0.500000000000000>>> K.end2
长度用 .measure方法来表示
>>> K.measure1.50000000000000
其闭包用 .closure方法来表示
>>> K.closureInterval(0.500000000000000, 2)
其内点用 .interior方法来表示
>>> K.interiorInterval.open(0.500000000000000, 2)
判断其边界条件可以使用 left_open 或者 right_open 来做
>>> K.left_openFalse>>> K.right_openFalse>>> J.left_openTrue
两个集合之间的操作
#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 - KInterval.Ropen(0, 0.500000000000000) # [0,0.5)>>> K - IInterval.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.RealsReals>>> sympy.S.Reals - IUnion(Interval.open(-oo, 0), Interval.open(1, oo))>>> plement(sympy.S.Reals)Union(Interval.open(-oo, 0), Interval.open(1, oo))>>> sympy.plement(I)EmptySet>>> plement(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 >> BImplies(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)>>> nn>>> 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.5690315959>>> 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.333333333333333333333rather than>>> (1/x).subs({x: 3.0}).evalf(21)0.333333333333333314830>>> E.evalf(10)2.718281828>>> pi.evalf(15)3.14159265358979>>> sqrt(2).evalf() #查看实数的有效数字,缺省151.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.domainObject("A")>>> f.codomainObject("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 excludedNone>>>print (x+1).match(p+1) # x is excludedNone>>>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 #虚数单位isympy.E #自然对数低esympy.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=00
本文是本人学习过程中,总结了官方教程中的部分内容,目的是方便快速查找需要的内容。主要为一些复杂的符号运算提供机器运算结果,并验证自己的计算结果。后续会提供部分实际应用案例。