1.1.3. 化简

参考:Simplification

simplify 是通用的简化方式

from sympy import *

x, y, z = symbols('x:z')

simplify 可以简化表达式:

simplify(sin(x)**2 + cos(x)**2)
\[\displaystyle 1\]
simplify((x**3 + x**2 - x - 1)/(x**2 + 2*x + 1))
\[\displaystyle x - 1\]
simplify(gamma(x)/gamma(x - 2))
\[\displaystyle \left(x - 2\right) \left(x - 1\right)\]

这里 gamma(x) 指的是:\(\Gamma(x)\)

注意:simplify 仅仅是简化,不能做到因式分解:

simplify(x**2 + 2*x + 1)
\[\displaystyle x^{2} + 2 x + 1\]

factor() 保证将多项式分解为不可约因子。

factor(x**2 + 2*x + 1)
\[\displaystyle \left(x + 1\right)^{2}\]

多项式/有理函数化简

expand 展开多项式

expand((x + 1)**2)
\[\displaystyle x^{2} + 2 x + 1\]
expand((x + 2)*(x - 3))
\[\displaystyle x^{2} - x - 6\]

给定一个多项式,expand() 将把它变成单项式和的规范形式。

expand() 听起来可能不像一个简化函数。毕竟,就其名称而言,它使表达式更大,而不是更小。通常是这种情况,但由于 cancellation,表达式在调用 expand() 时通常会变小。

expand((x + 1)*(x - 2) - (x - 1)*x)
\[\displaystyle -2\]

factor

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

factor(x**3 - x**2 + x - 1)
\[\displaystyle \left(x - 1\right) \left(x^{2} + 1\right)\]
factor(x**2*z + 4*x*y*z + 4*y**2*z)
\[\displaystyle z \left(x + 2 y\right)^{2}\]

对于多项式,factor()expand() 相反。factor() 对有理数使用完整的多元因子分解算法,这意味着 factor() 返回的每个因子都保证是不可约的。如果您对因子本身感兴趣,factor_list 会返回一个更结构化的输出。

factor_list(x**2*z + 4*x*y*z + 4*y**2*z)
(1, [(z, 1), (x + 2*y, 2)])

请注意,factorexpand 的输入不必是严格意义上的多项式。他们将智能地分解或扩展任何类型的表达式(但请注意,如果输入不再是有理数上的多项式,则这些因子可能不是不可约的)。

expand((cos(x) + sin(x))**2)
\[\displaystyle \sin^{2}{\left(x \right)} + 2 \sin{\left(x \right)} \cos{\left(x \right)} + \cos^{2}{\left(x \right)}\]
factor(cos(x)**2 + 2*cos(x)*sin(x) + sin(x)**2)
\[\displaystyle \left(\sin{\left(x \right)} + \cos{\left(x \right)}\right)^{2}\]

collect

collect() 收集表达式中项的公共幂。

expr = x*y + x - 3 + 2*x**2 - z*x**2 + x**3
expr
\[\displaystyle x^{3} - x^{2} z + 2 x^{2} + x y + x - 3\]
collected_expr = collect(expr, x)
collected_expr
\[\displaystyle x^{3} + x^{2} \left(2 - z\right) + x \left(y + 1\right) - 3\]

collect().coeff() 方法结合使用特别有用。expr.coeff(x, n) 给出 expr\(x^n\) 的系数:

collected_expr.coeff(x, 2)
\[\displaystyle 2 - z\]

cancel 约分

cancel() 将采用任何有理函数并将其放入标准规范形式 \({\frac p q}\) 中,其中 \(p\)\(q\) 是没有公因子的扩展多项式,并且 \(p\)\(q\) 的前导系数没有分母(即整数)。

cancel((x**2 + 2*x + 1)/(x**2 + x))
\[\displaystyle \frac{x + 1}{x}\]
expr = 1/x + (3*x/2 - 2)/(x - 4)
expr
\[\displaystyle \frac{\frac{3 x}{2} - 2}{x - 4} + \frac{1}{x}\]
cancel(expr)
\[\displaystyle \frac{3 x^{2} - 2 x - 8}{2 x^{2} - 8 x}\]
expr = (x*y**2 - 2*x*y*z + x*z**2 + y**2 - 2*y*z + z**2)/(x**2 - 1)
expr
\[\displaystyle \frac{x y^{2} - 2 x y z + x z^{2} + y^{2} - 2 y z + z^{2}}{x^{2} - 1}\]
cancel(expr)
\[\displaystyle \frac{y^{2} - 2 y z + z^{2}}{x - 1}\]

请注意,由于 factor() 将完全分解表达式的分子和分母,因此它也可以用于做同样的事情:

factor(expr)
\[\displaystyle \frac{\left(y - z\right)^{2}}{x - 1}\]

但是,如果您只想确保表达式处于 cancel 形式,cancel()factor() 更有效。

apart()

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

expr = (4*x**3 + 21*x**2 + 10*x + 12)/(x**4 + 5*x**3 + 5*x**2 + 4*x)
expr
\[\displaystyle \frac{4 x^{3} + 21 x^{2} + 10 x + 12}{x^{4} + 5 x^{3} + 5 x^{2} + 4 x}\]
apart(expr)
\[\displaystyle \frac{2 x - 1}{x^{2} + x + 1} - \frac{1}{x + 4} + \frac{3}{x}\]

三角函数简化

trigsimp

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

trigsimp(sin(x)**2 + cos(x)**2)
\[\displaystyle 1\]
trigsimp(sin(x)**4 - 2*cos(x)**2*sin(x)**2 + cos(x)**4)
\[\displaystyle \frac{\cos{\left(4 x \right)}}{2} + \frac{1}{2}\]
trigsimp(sin(x)*tan(x)/sec(x))
\[\displaystyle \sin^{2}{\left(x \right)}\]

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

trigsimp(cosh(x)**2 + sinh(x)**2)
\[\displaystyle \cosh{\left(2 x \right)}\]
trigsimp(sinh(x)/tanh(x))
\[\displaystyle \cosh{\left(x \right)}\]

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

expand_trig

要扩展三角函数,即应用和或双角恒等式,请使用 expand_trig()

expand_trig(sin(x + y))
\[\displaystyle \sin{\left(x \right)} \cos{\left(y \right)} + \sin{\left(y \right)} \cos{\left(x \right)}\]
expand_trig(tan(2*x))
\[\displaystyle \frac{2 \tan{\left(x \right)}}{1 - \tan^{2}{\left(x \right)}}\]

由于 expand_trig() 倾向于使三角函数表达式更大,而 trigsimp() 倾向于使它们更小,因此可以使用 trigsimp() 反向应用这些恒等式。

trigsimp(sin(x)*cos(y) + sin(y)*cos(x))
\[\displaystyle \sin{\left(x + y \right)}\]

幂运算

在我们介绍简化幂函数之前,有必要先对幂的恒等式进行数学讨论。指数满足三种恒等式:

  1. \(x^ax^b = x^{a + b}\)

  2. \(x^ay^a = (xy)^a\),其中 \(x, y \geq 0, a \in \mathbb{R}\)

  3. \((x^a)^b = x^{ab}\) 其中 \(b \in \mathbb{Z}\)

注解

  1. 默认情况下,SymPy 符号被假定为复数(\mathbb{C} 的元素)。也就是说,除非它适用于所有复数,否则不会将简化应用于具有给定 Symbol 的表达式。

  2. 通过将假设传递给 symbols(),可以为符号提供不同的假设。

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

注意:sqrt(x) x**Rational(1, 2) 的简写:

sqrt(x) == x**Rational(1, 2)
True

powsimp

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

powsimp(x**a*x**b)
\[\displaystyle x^{a + b}\]
powsimp(x**a*y**a)
\[\displaystyle \left(x y\right)^{a}\]

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

powsimp(t**c*z**c)
\[\displaystyle t^{c} z^{c}\]

如果您知道要应用这种简化,但又不想弄乱假设,则可以传递 force=True 标志。无论假设如何,这都将强制进行简化。

powsimp(t**c*z**c, force=True)
\[\displaystyle \left(t z\right)^{c}\]

请注意,在某些情况下,特别是当指数是整数或有理数且恒等式 2 成立时,它将自动应用。

(z*t)**2
\[\displaystyle t^{2} z^{2}\]
sqrt(x*y)
\[\displaystyle \sqrt{x} \sqrt{y}\]

这意味着无法使用 powsimp() 撤消此等式,因为即使 powsimp() 将基底放在一起,它们也会自动再次分开。

powsimp(z**2*t**2)
\[\displaystyle t^{2} z^{2}\]

expand_power_exp / expand_power_base

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

expand_power_exp(x**(a + b))
\[\displaystyle x^{a} x^{b}\]
expand_power_base((x*y)**a)
\[\displaystyle x^{a} y^{a}\]

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

expand_power_base((z*t)**c)
\[\displaystyle \left(t z\right)^{c}\]

powsimp() 一样,您可以使用 force=True 强制扩展发生,而无需摆弄假设。

expand_power_base((z*t)**c, force=True)
\[\displaystyle t^{c} z^{c}\]

与等式 2 一样,如果幂是数字,则等式 1 会自动应用,因此无法使用 expand_power_exp() 撤消。

x**2*x**3
\[\displaystyle x^{5}\]
expand_power_exp(x**5)
\[\displaystyle x^{5}\]

powdenest

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

powdenest((x**a)**b)
\[\displaystyle x^{a b}\]

和以前一样,如果在给定的假设下不正确,则不应用该等式。

powdenest((z**a)**b)
\[\displaystyle \left(z^{a}\right)^{b}\]

和以前一样,这可以用 force=True 手动覆盖。

powdenest((z**a)**b, force=True)
\[\displaystyle z^{a b}\]

指数和对数

expand_log

要从左到右应用等式 1 和 2,请使用 expand_log()。 与往常一样,除非有效,否则不会应用等式。

x, y = symbols('x y', positive=True)
n = symbols('n', real=True)
expand_log(log(x*y))
\[\displaystyle \log{\left(x \right)} + \log{\left(y \right)}\]
expand_log(log(x/y))
\[\displaystyle \log{\left(x \right)} - \log{\left(y \right)}\]
expand_log(log(x**2))
\[\displaystyle 2 \log{\left(x \right)}\]
expand_log(log(x**n))
\[\displaystyle n \log{\left(x \right)}\]
expand_log(log(z*t))
\[\displaystyle \log{\left(t z \right)}\]

powsimp()powdenest() 一样, expand_log() 有一个强制选项,可用于忽略假设。

expand_log(log(z**2))
\[\displaystyle \log{\left(z^{2} \right)}\]
expand_log(log(z**2), force=True)
\[\displaystyle 2 \log{\left(z \right)}\]

logcombine

要从右到左应用等式 1 和 2,请使用 logcombine()

logcombine(log(x) + log(y))
\[\displaystyle \log{\left(x y \right)}\]
logcombine(n*log(x))
\[\displaystyle \log{\left(x^{n} \right)}\]
logcombine(n*log(z))
\[\displaystyle n \log{\left(z \right)}\]

logcombine() 也有一个 force 选项,可用于忽略假设。

logcombine(n*log(z), force=True)
\[\displaystyle \log{\left(z^{n} \right)}\]

特殊函数

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

SymPy 中包含的特殊函数及其文档的详细列表位于函数模块页面。

x, y, z = symbols('x y z')
k, m, n = symbols('k m n')

\(n!= 1\cdot2\cdots(n - 1)\cdot n\)

factorial(n)
\[\displaystyle n!\]

\(\binom{n}{k}\)

binomial(n, k)
\[\displaystyle {\binom{n}{k}}\]

\(\Gamma(z) = \int_0^\infty t^{z - 1}e^{-t}\,dt\)

gamma(z)
\[\displaystyle \Gamma\left(z\right)\]

\({}_pF_q\left(\begin{matrix} a_1, \cdots, a_p \\ b_1, \cdots, b_q \end{matrix} \middle| z \right)\)

hyper([1, 2], [3], z)
\[\begin{split}\displaystyle {{}_{2}F_{1}\left(\begin{matrix} 1, 2 \\ 3 \end{matrix}\middle| {z} \right)}\end{split}\]

rewrite

处理特殊函数的一种常见方法是将它们相互重写。这适用于 SymPy 中的任何函数,而不仅仅是特殊函数。要根据函数重写表达式,请使用 expr.rewrite(function)。例如,

tan(x).rewrite(sin)
\[\displaystyle \frac{2 \sin^{2}{\left(x \right)}}{\sin{\left(2 x \right)}}\]
factorial(x).rewrite(gamma)
\[\displaystyle \Gamma\left(x + 1\right)\]

expand_func

要根据某些等式扩展特殊功能,请使用 expand_func()。例如

expand_func(gamma(x + 3))
\[\displaystyle x \left(x + 1\right) \left(x + 2\right) \Gamma\left(x\right)\]

hyperexpand

要根据更标准的函数重写 hyper,请使用 hyperexpand()

hyperexpand(hyper([1, 1], [2], z))
\[\displaystyle - \frac{\log{\left(1 - z \right)}}{z}\]

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

expr = meijerg([[1],[1]], [[1],[]], -z)
expr
\[\begin{split}\displaystyle {G_{2, 1}^{1, 1}\left(\begin{matrix} 1 & 1 \\1 & \end{matrix} \middle| {- z} \right)}\end{split}\]
hyperexpand(expr)
\[\displaystyle e^{\frac{1}{z}}\]

combsimp

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

n, k = symbols('n k', integer = True)
combsimp(factorial(n)/factorial(n - 3))
\[\displaystyle n \left(n - 2\right) \left(n - 1\right)\]
combsimp(binomial(n+1, k+1)/binomial(n, k))
\[\displaystyle \frac{n + 1}{k + 1}\]

gammasimp

要使用具有非整数参数的 gamma 函数或组合函数来简化表达式,请使用 gammasimp()

gammasimp(gamma(x)*gamma(1 - x))
\[\displaystyle \frac{\pi}{\sin{\left(\pi x \right)}}\]

示例:连续分数

让我们使用 SymPy 来探索连分数。连分数是以下形式的表达式

\[ a_0 + \cfrac{1}{a_1 + \cfrac{1}{a_2 + \cfrac{1}{ \ddots + \cfrac{1}{a_n} }}} \]
def list_to_frac(l):
    expr = Integer(0)
    for i in reversed(l[1:]):
        expr += i
        expr = 1/expr
    return l[0] + expr

list_to_frac([x, y, z])
\[\displaystyle x + \frac{1}{y + \frac{1}{z}}\]
list_to_frac([1, 2, 3, 4])
\[\displaystyle \frac{43}{30}\]
syms = symbols('a0:5')
syms
(a0, a1, a2, a3, a4)
frac = list_to_frac(syms)
frac
\[\displaystyle a_{0} + \frac{1}{a_{1} + \frac{1}{a_{2} + \frac{1}{a_{3} + \frac{1}{a_{4}}}}}\]
frac = cancel(frac)
frac
\[\displaystyle \frac{a_{0} a_{1} a_{2} a_{3} a_{4} + a_{0} a_{1} a_{2} + a_{0} a_{1} a_{4} + a_{0} a_{3} a_{4} + a_{0} + a_{2} a_{3} a_{4} + a_{2} + a_{4}}{a_{1} a_{2} a_{3} a_{4} + a_{1} a_{2} + a_{1} a_{4} + a_{3} a_{4} + 1}\]