expand()
的参数factor()
的参数.evalf(n)
方法人的一生中学习数学很多时候都浪费在反复解题、不断运算上。现在计算机普及,手机流行,很多计算方法、运算技巧、笔算能力以及数学公式都可以方便获取。笔算与解题在人工智能AI、图形图像、数据分析等上被软件所取代。
APP中无数的数学计算器,常见的是 加减乘除 四则运算,有了它,我们就可以摆脱 笔算和心算 的痛苦。
数学的应用应该生活化、普及化,而不是只属于天才的专利,计算器帮我们改变了这一切。
计算器还可以做 科学运算,比如 乘方、开方、指数、对数、三角函数 等,尽管这些知识在我们初中时代,通过纸笔也是能运算起来的,但是也仅限于一些极其常用和简单的运算,一旦复杂起来,通过纸笔来运算就是一项复杂的工程了。所以说,计算器可以让我们离数学的应用更近。
但是学生时代所学的数学可远不止这些,尤其是 高等数学(微积分)、线性代数、概率统计 等数学知识应用非常广泛,但是由于其运算非常复杂,我们即便掌握了这些知识,想要应用它又谈何容易,那有没有 微积分、线性代数、概率统计 等的计算器呢?
答案是有的,它们就是计算机代数系统Computer Algebra System,简称CAS,Python的 Sympy
库也支持带有数学符号的微积分、线性代数等进行运算。
有了计算器,我们才能真正脱离数学复杂的解题本身,把精力花在对数学原理和应用的学习上,而这才是(在工作方面)数学学习的意义。
Python语言在 专业数学(数学、数据科学等)领域,由于其拥有非常多而且强大的第三方库,譬如Numpy,构成了一个极其完善的生态链。
Sympy 是基于 Python之上的数学库,可以实现数学符号的运算,用它来进行数学代数式的符号推导和验算,处理带有数学符号的导数、极限、微积分、方程组、矩阵等,就像科学计算器一样简单,可以完成 计算机代数系统CAS的绝大部分功能。
如果之前是学数学相关专业了解计算机代数系统CAS,就会对数学符号的运算比较熟悉,而如果之前是程序员,可能会有点不太明白,下面我们就来了解一下。
我们先来看一下Sympy库和Python内置的 Math 函数对数值计算的处理有什么不同。为了让代码可执行,下面的代码都是基于Python3的完整代码。
import sympy,math
print(math.sqrt(8))
print(sympy.sqrt(8))
执行之后,结果显示为:
2.8284271247461903
2*sqrt(2)
math 模块是直接求解出一个浮点值,而 Sympy 则是用数学符号表示出结果,结合LaTex的语法就可以得出我们在课本里最熟悉的的: 2 2 2\sqrt{2} 22
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
SymPy 有三个内建的数值类型:实数,有理数和整数。有理数类用 两个整数 来表示一个有理数。分子与分母,所以 Rational(1,2)
代表 1/2
,Rational(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}
构造抽象函数 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 , h x,y,z,u,v,w,f,g,h x,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 ∗ z a*x**m + b*y**n + c*z a∗x∗∗m+b∗y∗∗n+c∗z,转化为 LaTex 表示法之后结果为 a x m + b y n + c z ax^m+by^n+cz axm+byn+cz,输出的结果就带有 x , y , z , a , b , c x, y, z, a,b,c x,y,z,a,b,c 等符号变量。
当个变量替换用 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()
函数可以展开代数式,比如代数式: x 4 + x y + 8 x x^4+xy+8x x4+xy+8x ,合并之后应该是 x ( x 3 + 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()
的参数>>> ((x + y + z)**2).expand(multinomial=True)
x**2 + 2*x*y + 2*x*z + y**2 + 2*y*z + z**2。
>>> exp(x + y).expand(power_exp=True)
exp(x)*exp(y)
>>> (2**(x + y)).expand(power_exp=True)
2**x*2**y
( x y ) z → x z ⋅ y z , ( 2 y ) z → 2 z y z (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 ( x 2 y ) → 2 log ( x ) + l o g ( y ) , x > 0 , y > 0 \log(x^2y)\to 2\log(x)+log(y), x>0,y>0 log(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)
>>> 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.
>>> from sympy import gamma
>>> gamma(x + 1).expand(func=True)
x*gamma(x)
>>> 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)= 1 sin2(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()
tegother()
化简有理式 e x p r = x 2 + 3 x + 2 x 2 + x expr=\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)
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()
函数可以化简代数式。有一些代数式看起来会比较复杂,简化 ( 2 x ) 3 ( − 5 x y 2 ) (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)
expand_log,logcombine
承担了这样的角色。ln ( x y ) = ln ( x ) + ln ( y ) , ln ( x y ) = 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)
如果想进行变量替换,例如把 x x x 变成 y y y ,那么可以使用 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 : x 3 − 1 = 0 , x ∈ C : x 3 − 1 = 0 , x ∈ R : e x − x = 0 , x ∈ R : e x − 1 = 0 , x ∈ C : e x − 1 = 0 x ∈ \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 = 0 x∈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 = 10 2 x + 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 = 12 x + 2 y + 5 z = 22 x = 4 y \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
一元二次方程一般式求解: a x 2 + b x + c = 0 , a ≠ 0 ax^2+bx+c=0, a\ne0 ax2+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 + b 2 − 4 a c 2 a , − b − b 2 − 4 a c 2 a \dfrac{-b+\sqrt{b^2-4ac}}{2a},\dfrac{-b-\sqrt{b^2-4ac}}{2a} 2a−b+b2−4ac,2a−b−b2−4ac
常记 Δ = b 2 − 4 a c \Delta=b^2-4ac Δ=b2−4ac,称为判别式。则有两根为
x 1 = − b + Δ 2 a , x 2 = − b − Δ 2 a x_1=\dfrac{-b+\sqrt{\Delta}}{2a},x_2=\dfrac{-b-\sqrt{\Delta}}{2a} x1=2a−b+Δ,x2=2a−b−Δ
满足根与系数的关系式: x 1 + x 2 = − b a , x 1 ⋅ x 2 = c a x_1+x_2=-\dfrac{b}{a}, x_1\cdot x_2=\dfrac{c}{a} x1+x2=−ab,x1⋅x2=ac
微积分是大学高等数学里非常重要的学习内容,比如求 极限、导数、微分、不定积分、定积分等都是可以使用 Sympy 来运算的。
可以使用 diff(代数式, 变量, 求导的次数)
函数对代数式求导,一阶微分可以省略求导次数。比如我们要对 sin ( x ) e x \sin(x)e^x sin(x)ex 进行 x x x 求导,以及求导两次。
求导一次的结果就是 exp(x)*sin(x) + exp(x)*cos(x)
,也就是 e x sin ( x ) + e x cos ( x ) e^x\sin(x)+e^x\cos(x) exsin(x)+excos(x) ;
求导两次的结果是 2*exp(x)*cos(x)
,也就是 2 e x cos ( 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(代数式,变量)
来求不定积分的。
>>> 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)
转化之后为: e x sin ( 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 ( x 2 ) d x \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
也支持广义积分:
∫ − ∞ 0 e − x 2 d x = π 2 , ∫ 0 + ∞ e − x d x = 1 , ∫ − ∞ + ∞ ∫ − ∞ + ∞ e − x 2 − y 2 d x d y = π \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 ) = ∫ 0 x 2 x d x , ∫ 0 3 f ( x ) d x f(x)=\int_0^x 2x \mathbf{d}x, \qquad\int_0^3 f(x)\mathbf{d}x f(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 → 0 x\to0 x→0 时 f ( x ) f(x) f(x) 的极限,即 limit(f, x, 0)
:
lim x → 0 ( 1 + x ) 1 x = e , lim x → ∞ ( 1 + 1 x ) x = e \displaystyle\lim_{x\to0}(1+x)^{\frac{1}{x}}=e,\qquad \lim_{x\to \infty}\left(1+\dfrac{1}{x}\right)^x=e x→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 → 0 s i n ( 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 = 1 100 2 n S=\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 i i 可以看做是循环变量,就是 x x x 自己加五次, 先定义变量,再写出方程。
>>> 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(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
在常微分方程(Ordinary Differential Equation)中,最常见的就是解方程,而解方程主要是靠 dsolve
函数。
求解下列常微分方程:
d f d x + f ( x ) = 0 d 2 f d x 2 + f ( x ) = 0 d 3 f d x 3 + 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)=0 dxdf+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',)
在偏微分方程(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个素数之间
如果只想获得第 n n n 个素数,则使用函数 sympy.ntheory.generate.prime(n)
即可。如果是希望计算 x x x 后面的下一个素数,使用 sympy.ntheory.generate.nextprime(x)
即可。判断 x x x 是否是素数,可以使用
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 × m n\times m n×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()
中,第一个矩阵表示 P P P,第二个矩阵表示 D , A = P × D × P − 1 D, A=P\times D\times P^{-1} D,A=P×D×P−1。
在矩阵中,最常见的还是多元一次方程的解。如果要求 A x = b Ax=b Ax=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 中的集合论操作主要集中在实数域或者复数域上。
对于闭区间 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
>>> K.measure
1.50000000000000
>>> K.closure
Interval(0.500000000000000, 2)
>>> K.interior
Interval.open(0.500000000000000, 2)
>>> 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 , C A,B,C A,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
函数。其参数包括 e x p r , x , x 0 , n , d i r expr, x, x_0 ,n, dir expr,x,x0,n,dir,分别对应着表达式 expr,函数的自变量 x x x,Taylor Series 的中心点 x 0 x_0 x0, n n n 表示阶数, d i r dir dir 表示方向,包括 “±”,"-","+",分别表示 x → x 0 , x → x 0 − , x → x 0 + x\to x_0,x\to x_0^-, x\to x_0^+ x→x0,x→x0−,x→x0+。
e x = 1 + x + x 2 2 ! + x 3 3 ! + x 4 4 ! + . . . + x n n ! + o ( x n ) 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 = 3 n=3 n=3 时,
e x = 1 + x + x 2 2 + o ( x 3 ) 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)
以上可以看出 e i x = cos ( x ) + i sin ( x ) , e x = ∑ n = 0 ∞ x n n ! \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 还支持 范畴论(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,...
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(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_WHITESPACE
2
x
>>>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/3
3
x
--
3
>>> Integral(x**2, x) #doctest: +NORMALIZE_WHITESPACE
/
|
| 2
| x dx
|
/
>>> 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(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(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)
'x 2 '
>>> 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
本文是本人学习过程中,总结了官方教程中的部分内容,目的是方便快速查找需要的内容。主要为一些复杂的符号运算提供机器运算结果,并验证自己的计算结果。后续会提供部分实际应用案例。