【SymPy】(五)简化

【SymPy】(一)SymPy简介
【SymPy】(二)使用SymPy需要避开的坑
【SymPy】(三)基本操作(四)打印

简化

In [1]: from sympy import *

In [2]: x, y, z = symbols('x y z')

In [3]: init_printing(use_unicode=True)

1 simplify

符号操作系统最有用的特性之一是简化数学表达式。SymPy有几十个函数来执行各种简化。还有一个名为simplify()的通用函数,它通过智能的方式应用所有简化函数然后得出最简单的表达形式。
例如:

In [7]: simplify(sin(x)**2 + cos(x)**2)
Out[7]: 1

In [8]: simplify((x**3 + x**2 - x - 1)/(x**2 + 2*x + 1))
Out[8]: x - 1

In [9]: simplify(gamma(x)/gamma(x - 2))
Out[9]: (x - 2)(x - 1)

这里,gamma(x)是gamma函数Γ(x)
实数域上:
Γ ( x ) = ∫ 0 + ∞ t x − 1 e − t   d t ( x > 0 ) \Gamma(x)=\int_{0}^{+\infty} t^{x-1} e^{-t} \mathrm{~d} t(x>0) Γ(x)=0+tx1et dt(x>0)

simplify()应用SymPy中所有主要的简化操作,并使用启发式算法来确定最简单的结果,但所谓的“最简单”并不是明确的。
例如,我们想“简化” x 2 + 2 x + 1 x^{2}+2 x+1 x2+2x+1 ( x + 1 ) 2 (x+1)^{2} (x+1)2

In [10]: simplify(x**2 + 2*x + 1)
Out[10]: 
 2
x  + 2⋅x + 1

可以看到结果不是我们想要的。

simplify()的另一个缺陷是它寻找最简表达式会非常慢,因为它在选择最佳的简化方法之前会尝试多种简化方法。如果你已经确切地知道您要进行哪种简化,那么最好选择特定的简化函数。

应用特定的简化函数还有一个优点,即特定函数对其输出的形式有一定的保证。这些将在后面讨论。
例如,当对有理系数多项式调用factor()时,可以保证将多项式分解为不可约因子。但simplify()没有保证,因为它完全是启发式的。

如果你只想将表达式缩减为更简单的形式,simplify()会是个不错的选择。在看到simplify()返回的结果后,可以选择应用特定的函数,以获得更精确的结果。当你不知道表达式将采用什么形式,并且需要简化它时,simplify()也很有用。

2 多项式/有理函数简化

2.1 expand

expand()是SymPy中最常见的简化函数之一。可用于展开多项式表达式。

例如:

In [11]: expand((x + 1)**2)
Out[11]: 
 2
x  + 2⋅x + 1

In [12]: expand((x + 2)*(x - 3))
Out[12]: 
 2
x  - x - 6

给定一个多项式,expand()将把它转换成一个单项式和的标准形式。

expand()听起来可能不像一个简化函数。毕竟,就其名称而言,它使表达式变长,而不是变短,但通常一个表达式在调用expand()时会因为相消而变小。

In [13]: expand((x + 1)*(x - 2) - (x - 1)*x)
Out[13]: -2

2.2 factor

factor()将多项式分解为不可约的有理数因子。
例如:

In [14]: factor(x**3 - x**2 + x - 1)
Out[14]:2(x - 1)⋅⎝x  + 1⎠

In [15]: factor(x**2*z + 4*x*y*z + 4*y**2*z)
Out[15]: 
           2
z⋅(x + 2⋅y)

对于多项式来说,factor()expand()相反。factor()在有理数上使用一个完整的多元因式分解算法,这意味着factor()返回的每个因子保证是不能再化简的。

如果你对因子本身感兴趣,factor_list会返回一个更结构化的输出。

In [16]: factor_list(x**2*z + 4*x*y*z + 4*y**2*z)
Out[16]: (1, [(z, 1), (x + 2⋅y, 2)])

注意,factorexpand的输入不必是严格意义上的多项式:

In [17]: expand((cos(x) + sin(x))**2)
Out[17]: 
   2                           2
sin (x) + 2⋅sin(x)⋅cos(x) + cos (x)

In [18]: factor(cos(x)**2 + 2*cos(x)*sin(x) + sin(x)**2)
Out[18]: 
                 2
(sin(x) + cos(x))

2.2.3 collect

collect()收集表达式中某个项的公共幂。例如

In [19]: expr = x*y + x - 3 + 2*x**2 - z*x**2 + x**3

In [20]: expr
Out[20]: 
 3    2        2
x  - x ⋅z + 2⋅x  + x⋅y + x - 3

In [21]: collected_expr = collect(expr, x)

In [22]: collected_expr
Out[22]: 
 3    2
x  + x ⋅(-z + 2) + x⋅(y + 1) - 3

collect().coeff()方法结合使用特别有用。表达式系数(x,n)给出了x**n在表达式中的系数:

In [23]: collected_expr.coeff(x, 2)
Out[23]: -z + 2

2.2.4 cancel

cancel()将任意有理函数转换为标准规范形式 p q \frac{p}{q} qp,其中 p p p q q q是无公因式的展开多项式, p p p q q q的前导系数没有分母(即为整数)。

In [24]: cancel((x**2 + 2*x + 1)/(x**2 + x))
Out[24]: 
x + 1
─────
  x
In [25]: expr = 1/x + (3*x/2 - 2)/(x - 4)

In [26]:  expr
Out[26]: 
3⋅x
─── - 2
 2        1
─────── + ─
 x - 4    x

In [27]: cancel(expr)
Out[27]: 
   2
3⋅x  - 2⋅x - 8
──────────────
     2
  2⋅x  - 8⋅x

In [28]: expr = (x*y**2 - 2*x*y*z + x*z**2 + y**2 - 2*y*z + z**2)/(x**2 - 1)

In [29]: expr
Out[29]: 
   2                2    2            2
x⋅y  - 2⋅x⋅y⋅z + x⋅z  + y  - 2⋅y⋅z + z
───────────────────────────────────────
                  2
                 x  - 1

In [30]: cancel(expr)
Out[30]: 
 2            2
y  - 2⋅y⋅z + z
───────────────
     x - 1

请注意,由于factor()将完全分解表达式的分子和分母,因此它也可以用于执行相同的操作:

In [31]:  factor(expr)
Out[31]: 
       2
(y - z)
────────
 x - 1

但是,如果您只想确保表达式是分子分母相消形式,那么cancel()factor()更有效。

2.2.5 apart

apart()对有理函数执行部分分式分解。

In [35]: expr = (4*x**3 + 21*x**2 + 10*x + 12)/(x**4 + 5*x**3 + 5*x**2 + 4*x)

In [36]: expr
Out[36]: 
   3       2
4⋅x  + 21⋅x  + 10⋅x + 12
────────────────────────
  4      3      2
 x  + 5⋅x  + 5⋅x  + 4⋅x

In [37]: apart(expr)
Out[37]: 
 2⋅x - 1       1     3
────────── - ───── +2           x + 4   x
x  + x + 1

3 三角化简Trigonometric Simplification

sympy遵循Python对反三角函数的命名约定,在函数名的前面加上一个a
例如,反余弦或弧余弦称为acos()

In [38]: acos(x)
Out[38]: acos(x)

In [39]: cos(acos(x))
Out[39]: x

In [40]: asin(1)
Out[40]: 
π
─
2

3.1 trigsimp

要用三角恒等式简化表达式,则使用trigsimp()

In [42]: trigsimp(sin(x)**2 + cos(x)**2)
Out[42]: 1

In [43]: trigsimp(sin(x)**4 - 2*cos(x)**2*sin(x)**2 + cos(x)**4)
Out[43]: 
cos(4⋅x)   1
──────── +2       2

In [44]: trigsimp(sin(x)*tan(x)/sec(x))
Out[44]: 
   2
sin (x)

trigsimp()也适用于双曲三角函数。

In [45]: trigsimp(cosh(x)**2 + sinh(x)**2)
Out[45]: cosh(2⋅x)

In [46]: trigsimp(sinh(x)/tanh(x))
Out[46]: cosh(x)

simplify()非常相似,trigsimp()将各种三角恒等式应用于输入表达式,然后启发式地返回“最佳”恒等式。

3.2 expand_trig

要展开三角函数,即应用三角函数和角公式,则使用expand_trig()

In [47]: expand_trig(sin(x + y))
Out[47]: sin(x)⋅cos(y) + sin(y)⋅cos(x)

In [48]: expand_trig(tan(2*x))
Out[48]: 
   2⋅tan(x)
─────────────
     2
- tan (x) + 1

因为expand_trig()倾向于使三角表达式变大,而trigsimp()倾向于使它们变小,所以可以使用trigsimp()反向应用这些恒等式

In [49]: trigsimp(sin(x)*cos(y) + sin(y)*cos(x))
Out[49]: sin(x + y)

4 幂( Power)简化函数

在我们引入幂简化函数之前,先从数学上讨论幂所具有的三种等式:
1 、 x a x b = x a + b 1、x^{a} x^{b}=x^{a+b} 1xaxb=xa+b
2 、 x a y a = ( x y ) a 2、x^{a} y^{a}=(x y)^{a} 2xaya=(xy)a
3 、 ( x a ) b = x a b 3、\left(x^{a}\right)^{b}=x^{a b} 3(xa)b=xab

等式1总是正确的
等式2不一定是正确的。例如,如果 x = y = − 1 x=y=-1 x=y=1 a = 1 2 a=\frac{1}{2} a=21 x a y a = − 1 − 1 = i ⋅ i = − 1 x^{a} y^{a}=\sqrt{-1} \sqrt{-1}=i\cdot i=-1 xaya=1 1 =ii=1,而 ( x y ) a = − 1 ⋅ − 1 = 1 = 1 (x y)^{a}=\sqrt{-1 \cdot-1}=\sqrt{1}=1 (xy)a=11 =1 =1。只有当 x x x y y y是非负的, a a a是实数时,恒等式2才是正确的。不满足条件的话可能导致: x y ≠ x y \sqrt{x} \sqrt{y} \neq \sqrt{x y} x y =xy

等式3也不一定是正确的。例如:如果 x = − 1 , a = 2 , b = 1 2 x=-1,a=2,b=\frac{1}{2} x=1,a=2b=21,那么 ( x a ) b = ( ( − 1 ) 2 ) 1 / 2 = 1 = 1 \left(x^{a}\right)^{b}=\left((-1)^{2}\right)^{1 / 2}=\sqrt{1}=1 (xa)b=((1)2)1/2=1 =1,而 x a b = ( − 1 ) 2 ⋅ 1 / 2 = ( − 1 ) 1 = − 1 x^{a b}=(-1)^{2 \cdot 1 / 2}=(-1)^{1}=-1 xab=(1)21/2=(1)1=1,只有当 b b b为整数等式3才成立。
不满足条件的话可能导致: x 2 ≠ x \sqrt{x^{2}} \neq x x2 =x 1 x ≠ 1 x \sqrt{\frac{1}{x}} \neq \frac{1}{\sqrt{x}} x1 =x 1

记住以上内容很重要,因为默认情况下,SymPy不会执行不正确的简化

使用SymPy进行简化,涉及到只有在某些假设下才成立的特性时,我们需要对符号进行假设。我们稍后将对假设系统进行全面讨论,但目前,我们只需要知道以下内容。

  • 默认情况下,SymPy符号被认为是复数。也就是说,除非对复数适用,否则简化不会应用于给定符号的表达式
  • 通过将假设传递给Symbols(),可以为符号提供不同的假设。在本节的其余部分,我们将假设xy是正数,ab是实数的。我们将把ztc作为任意的复数符号。
In [53]:  x, y = symbols('x y', positive=True)

In [54]: a, b = symbols('a b', real=True)

In [55]: z, t, c = symbols('z t c')

注:在SymPy中,sqrt(x)x**Rational(1,2)是同一对象

In [51]: sqrt(x) == x**Rational(1, 2)
Out[51]: True

4.1 powsimp

powsimp()从左到右应用等式1和等式2。

In [56]: powsimp(x**a*x**b)
Out[56]: 
 a + b
x

In [57]:  powsimp(x**a*y**a)
Out[57]: 
     a
(x⋅y)

请注意,如果powsimp()无效,它将拒绝进行简化。

In [58]: powsimp(t**c*z**c)
Out[58]: 
 c  c
t ⋅z

可以传递force=True标志进行强制简化,而不考虑假设。

In [59]: powsimp(t**c*z**c, force=True)
Out[59]: 
     c
(t⋅z)

请注意,在某些情况下,特别是当指数是整数或有理数且等式2成立时,它将自动按等式从右到左拆分:

In [60]:  (z*t)**2
Out[60]: 
 2  2
t ⋅z

In [61]:  sqrt(x*y)
Out[61]: √x⋅√y

这意味着不可能用powsimp()撤消此特性,因为它们会再次自动拆分。

In [62]: powsimp(z**2*t**2)
Out[62]: 
 2  2
t ⋅z

In [63]: powsimp(sqrt(x)*sqrt(y))
Out[63]: √x⋅√y

4.2 expand_power_exp / expand_power_base

expand_power_exp()expand_power_base() 分别从右到左应用等式1和等式2的公式。

In [64]: expand_power_exp(x**(a + b))
Out[64]: 
 a  b
x ⋅x

In [65]: expand_power_base((x*y)**a)
Out[65]: 
 a  a
x ⋅y

powsimp()一样,如果等式2无效,则不应用它。

In [66]: expand_power_base((z*t)**c)
Out[66]: 
     c
(t⋅z)

也可以强制转换

In [67]: expand_power_base((z*t)**c, force=True)
Out[67]: 
 c  c
t ⋅z

如果幂是数字,则等式1将自动应用,并且不能使用 expand_power_exp()撤消。

In [68]: x**2*x**3
Out[68]: 
 5
x

In [69]: expand_power_exp(x**5)
Out[69]: 
 5
x

4.3 powdenest

powdenest()从左到右应用等式3。

In [70]: powdenest((x**a)**b)
Out[70]: 
 a⋅b
x

如前所述,如果在给定的假设下不成立,则不应用该恒等式。

In [71]: powdenest((z**a)**b)
Out[71]: 
    b
⎛ a⎞
⎝z ⎠

同样可以强制转换:

In [72]: powdenest((z**a)**b, force=True)
Out[72]: 
 a⋅b
z

5 指数和对数( Exponentials and logarithms)

注意:在SymPy中,与Python和大多数编程语言一样,log是自然对数,也称为ln。SymPy会自动提供一个别名log,log=ln

In [73]: ln(x)
Out[73]: log(x)

对数和幂有相似,主要有两种特性
 1.  log ⁡ ( x y ) = log ⁡ ( x ) + log ⁡ ( y ) \text { 1. } \log (x y)=\log (x)+\log (y)  1. log(xy)=log(x)+log(y)
 2.  log ⁡ ( x n ) = n log ⁡ ( x ) \text { 2. } \log \left(x^{n}\right)=n \log (x)  2. log(xn)=nlog(x)

等式成立的充分条件是xy为正数,n为实数。

In [74]: x, y = symbols('x y', positive=True)

In [75]: n = symbols('n', real=True)

跟前面一样,zt将是没有额外假设的Symbols。

5.1 expand_log

要从左到右应用特性1和特性2,请使用expand_log()。而且,除非这些标识是有效的,否则不会应用它们

In [76]: expand_log(log(x*y))
Out[76]: log(x) + log(y)

In [77]: expand_log(log(x/y))
Out[77]: log(x) - log(y)

In [78]: expand_log(log(x**2))
Out[78]: 2⋅log(x)

In [79]: expand_log(log(x**n))
Out[79]: n⋅log(x)

In [80]: expand_log(log(z*t))
Out[80]: log(t⋅z)

同样可以强制展开:

In [82]: expand_log(log(z**2))
Out[82]:2⎞
log⎝z ⎠

In [83]: expand_log(log(z**2), force=True)
Out[83]: 2⋅log(z)

5.2 logcombine

使用logcombine(),从右向左应用特性1和特性2:

In [84]: logcombine(log(x) + log(y))
Out[84]: log(x⋅y)

In [85]: logcombine(n*log(x))
Out[85]: 
   ⎛ n⎞
log⎝x ⎠

In [86]: logcombine(n*log(z))
Out[86]: n⋅log(z)

可强制执行:

In [87]: logcombine(n*log(z), force=True)
Out[87]: 
   ⎛ n⎞
log⎝z ⎠

6 特殊的函数

SymPy实现了几十个特殊函数,从组合数学中的函数到数学物理。

让我们介绍一下SymPy中的一些特殊函数。

In [88]: x, y, z = symbols('x y z')

In [89]: k, m, n = symbols('k m n')

factorial是阶乘函数。 factorial(n)表示 n ! = 1 ⋅ 2 ⋯ ( n − 1 ) ⋅ n n !=1 \cdot 2 \cdots(n-1) \cdot n n!=12(n1)n n ! n! n!表示 n n n个不同项的排列。

In [90]: factorial(n)
Out[90]: n!

二项式系数函数是binomial。binomial(n, k)表示 ( n k ) \left(\begin{array}{l}n \\k\end{array}\right) (nk),从一组n个不同项的项目中选择k个项的方法数,即组合数。也写成 C n k C_n^k Cnk

In [91]:  binomial(n, k)
Out[91]: 

⎛n⎞
⎜ ⎟
⎝k⎠

gamma函数
Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t \Gamma(z)=\int_{0}^{\infty} t^{z-1} e^{-t} d t Γ(z)=0tz1etdt

In [92]: gamma(z)
Out[92]: Γ(z)

广义超几何函数( generalized hypergeometric function)是hyper:hyper([a_1, …, a_p], [b_1, …,b_q], z) ,表示
r F q ( a 1 , ⋯   , a p b 1 , ⋯   , b q ∣ z ) { }_{r} F_{q}\left(\begin{array}{l}a_{1}, \cdots, a_{p} \\b_{1}, \cdots, b_{q}\end{array} \mid z\right) rFq(a1,,apb1,,bqz)
最常见的情况是 2 F 1 _2F^1 2F1,它通常被称为普通的超几何函数。

In [93]: hyper([1, 2], [3], z)
Out[93]: 

 ┌─  ⎛1, 2 │  ⎞
 ├─  ⎜     │ z⎟
213   │  ⎠

6.1 rewrite

处理特殊函数的一种常见方法是根据其他函数重写它们。这适用于SymPy中的任何函数,而不仅仅是特殊函数。使用:expr.rewrite(function)

In [94]: tan(x).rewrite(sin)
Out[94]: 
     2
2⋅sin (x)
─────────
 sin(2⋅x)

In [95]: factorial(x).rewrite(gamma)
Out[95]: Γ(x + 1)

6.2 expand_func

在某些方面扩展特殊函数,使用expand_func().

In [96]: expand_func(gamma(x + 3))
Out[96]: x⋅(x + 1)(x + 2)⋅Γ(x)

6.3 hyperexpand

用更标准的函数重写hyper,使用hyperexpand().

In [97]: hyperexpand(hyper([1, 1], [2], z))
Out[97]: 
-log(-z + 1)
─────────────
      z

hyperexpand()也适用于更一般的Meijer G函数

In [98]: expr = meijerg([[1],[1]], [[1],[]], -z)

In [99]: expr
Out[99]: 
╭─╮1, 11  1 │   ⎞
│╶┐     ⎜     │ -z⎟
╰─╯2, 11    │   ⎠

In [100]: hyperexpand(expr)
Out[100]: 
 1
 ─
 z
ℯ

6.4 combsimp

简化组合表达式,使用combsimp().

In [102]: n, k = symbols('n k', integer=True)

In [103]: combsimp(factorial(n)/factorial(n - 3))
Out[103]: n⋅(n - 2)(n - 1)

未完待续:

【SymPy】(六)微积分

【SymPy】(七)方程求解

【SymPy】(八)矩阵

【SymPy】(九)高级表达式操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二进制人工智能

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值