模块的基本功能#

介绍#

本教程试图概述symphy中有关多项式的功能。所有代码示例假定:

>>> from sympy import *
>>> x, y, z = symbols('x,y,z')
>>> init_printing(use_unicode=False, wrap_line=False)

基本概念#

多项式#

给一个家庭 \((x_i)\) 对于符号或其他合适的对象,包括数字,通过反复的加法、减法和乘法得到的表达式称为 生成元中的多项式表达式 \(x_i\) .

根据分配定律,在加减法之前可以进行乘法运算。由此得到的发电机产品称为 单项式 . 它们通常是用表格写的 \(x_1^{{\nu_1}}x_2^{{\nu_2}}\cdots x_n^{{\nu_n}}\) 其中指数 \(\nu_i\) 是非负整数。这通常是方便的写这简短的作为 \(x^\nu\) 在哪里? \(x = (x_1, x_2, \ldots, x_n)\) 表示生成器和 \(\nu = (\nu_1, \nu_2, \ldots, \nu_n)\) 是指数族。

当具有相同指数的所有单项式被组合时,多项式表达式成为乘积之和 \(c_\nu x^\nu\) ,称为 条款 多项式的,其中 系数 \(c_\nu\) 是整数。如果 \(x_i\) 是显式数,它们包含在系数中,不被视为生成元。这些系数通常是有理数、实数或复数。一些符号数字,例如。, pi ,可以是系数或生成器。

多项式表达式是不同单项式的项之和,由其系数族唯一确定 \((c_\nu)\) . 这种表达习惯上称为 多项式的 不过,更确切地说,一旦给定了生成器,这个名称确实代表了系数族。SymPy默认将多项式作为字典实现,单项式作为键,系数作为值。另一个实现由嵌套的系数列表组成。

The set of all polynomials with integer coefficients in the generators \(x_i\) is a ring, i.e., the sums, differences and products of its elements are again polynomials in the same generators. This ring is denoted \(\mathbb{Z}[x_1, x_2, \ldots, x_n]\), or \(\mathbb{Z}[(x_i)]\), and called the ring of polynomials in the \(x_i\) with integer coefficients.

更一般地说,多项式的系数可以是任何交换环的元素 \(A\) ,然后表示相应的多项式环 \(A[x_1, x_2, \dots, x_n]\) . 戒指 \(A\) 也可以是多项式环。在SymPy中,系数环被称为 domain 它可以作为一个关键字参数给出。默认情况下,它由多项式参数的系数决定。

该方法可以将多项式表达式转化为多项式 sympy.core.expr.Expr.as_poly ::

>>> e = (x + y)*(y - 2*z)
>>> e.as_poly()
Poly(x*y - 2*x*z + y**2 - 2*y*z, x, y, z, domain='ZZ')

如果一个多项式表达式包含不是整数的数,则将它们视为系数,并相应地扩展系数环。尤其是,被整数除得到有理系数:

>>> e = (3*x/2 + y)*(z - 1)
>>> e.as_poly()
Poly(3/2*x*z - 3/2*x + y*z - y, x, y, z, domain='QQ')

符号数被认为是生成器,除非它们被明确排除在外,在这种情况下,它们与系数环相邻:

>>> e = (x + 2*pi)*y
>>> e.as_poly()
Poly(x*y + 2*y*pi, x, y, pi, domain='ZZ')
>>> e.as_poly(x, y)
Poly(x*y + 2*pi*y, x, y, domain='ZZ[pi]')

或者,可以通过关键字参数指定系数域:

>>> e = (x + 2*pi)*y
>>> e.as_poly(domain=ZZ[pi])
Poly(x*y + 2*pi*y, x, y, domain='ZZ[pi]')

注意戒指 \(\mathbb{{Z}}[\pi][x, y]\) 多项式的 \(x\)\(y\) 系数为 \(\mathbb{{Z}}[\pi]\) 在数学上等价于 \(\mathbb{{Z}}[\pi, x, y]\) ,只是它们的实现不同。

如果表达式包含生成器的函数,而不是它们的正整数幂,则这些函数将被解释为新的生成器:

>>> e = x*sin(y) - y
>>> e.as_poly()
Poly(x*(sin(y)) - y, x, y, sin(y), domain='ZZ')

自从 \(y\)\(\sin(y)\) 它们在代数上是独立的,它们都可以作为生成元出现在多项式中。然而, 多项式表达式不能包含生成器的负幂 ::

>>> e = x - 1/x
>>> e.as_poly()
Poly(x - (1/x), x, 1/x, domain='ZZ')

重要的是要认识到发电机 \(x\)\(1/x = x^{{-1}}\) 作为代数自变量处理。尤其是他们的乘积不等于1。因此 分母中的生成器应该避免,即使它们在当前的实现中没有引起错误 . 这种行为是不可取的,将来可能会改变。发电机的合理功率也会出现类似的问题。比如说, \(x\)\(\sqrt x = x^{{1/2}}\) 不被认为是代数依赖的。

如果表达式中有代数数,可以通过设置关键字将它们与系数环相连 extension ::

>>> e = x + sqrt(2)
>>> e.as_poly()
Poly(x + (sqrt(2)), x, sqrt(2), domain='ZZ')
>>> e.as_poly(extension=True)
Poly(x + sqrt(2), x, domain='QQ<sqrt(2)>')

使用默认设置 extension=False ,两者都是 \(x\)\(\sqrt 2\) 被错误地认为是代数独立变量。其系数在扩展域中 \(\mathbb{Q}(\sqrt 2)\) 平方根被恰当地当作一个代数数来对待。设置 extension=True 无论何时涉及到代数数字,都绝对推荐使用,即使在当前实现中没有强制使用。

可分性#

第四个有理运算,除法,或倒数乘法,在环中通常是不可能的。如果 \(a\)\(b\) 是环的两个元素 \(A\) ,则可能存在第三个元素 \(q\) 在里面 \(A\) 这样的话 \(a = bq\) . 事实上,可能存在几个这样的因素。

如果还有 \(a = bq'\) 对某些人来说 \(q'\) 在里面 \(A\) 然后 \(b(q - q') = 0\) . 因此 \(b\)\(q - q'\) 是零,或者两者都是 零除数 ,其乘积为零的非零元素。

积分域#

没有零因子的交换环称为 积分域 . 大多数常见的环、整数环、域环和整域上的多项式环都是积分域。

现在假设 \(A\) 是一个积分域,并且考虑集合 \(P\) 在乘法下闭合的非零元素。如果 \(a\)\(b\)\(P\) ,并且存在一个元素 \(q\) 在里面 \(P\) 这样的话 \(a = bq\) 然后 \(q\) 是唯一的,叫做 \(a/b\)\(a\) 通过 \(b\) . 而且,据说

  • \(a\)可除尽的 通过 \(b\)

  • \(b\) 是一个 除数 属于 \(a\)

  • \(a\) 是一个 倍数 属于 \(b\)

  • \(b\) 是一个 因素 属于 \(a\) .

元素 \(a\) 属于 \(P\) 是的除数 \(1\) 如果且仅当它是 可逆的 在里面 \(A\) ,反之亦然 \(a^{{-1}} = 1/a\) . 这些元素被称为 单位 . 整数环的单位是 \(1\)\(-1\) . 域上多项式环中的可逆元素是非零常数多项式。

如果两个元素 \(P\)\(a\)\(b\) ,可被彼此整除,则商 \(a/b\) 与逆是可逆的 \(b/a\) ,或等效, \(b = ua\) 在哪里? \(u\) 是一个单位。据说这些元素是 相关 与,或 联系 彼此的。整数的关联 \(n\)\(n\)\(-n\) . 在域上的多项式环中,多项式的关联是它的常数倍数。

每个元素 \(P\) 可以被它的同伙和单位瓜分。元素是 不可约 如果它没有其他除数并且不是一个单位。整数环中的不可约元素是素数 \(p\) 以及它们的对立面 \(-p\) . 在一个域中,每个非零元素都是可逆的,并且没有不可约的元素。

阶乘域#

在整数环中,每个非零元素都可以表示为不可约元素的乘积,也可以是一个单位 \(\pm 1\) . 此外,任何两个这样的乘积具有相同数量的不可约因子,它们以适当的顺序相互关联。具有此属性的整型域称为 因式分解唯一因子分解域 . 除了整数环外,域上的所有多项式环都是阶乘的,因此在任何阶乘域上更一般的多项式环也是阶乘环。字段是普通的阶乘,因为只有单位。阶乘域的不可约元素通常称为 素数 .

一个整数族只有有限个公约数,其中最大的公约数可被所有公约数整除。更一般地说,给定一个非零元素族 \((a_i)\) 在积分域中,公约数 \(d\) 的元素称为 最大公约数 ,缩写 gcd ,如果它是所有公约数的倍数。一个最大公约数,如果存在的话,通常不是唯一的;它的所有关联都有相同的性质。它表示为 \(d = \gcd(a_1,\ldots,a_n)\) 如果没有混淆的危险。A 最小公倍数lcm ,一个家庭的 \((a_i)\) 被类似地定义为公共倍数 \(m\) 除以所有公倍数。它表示为 \(m = \operatorname{{lcm}}(a_1,\dots,a_n)\) .

在阶乘域中,最大公约数总是存在的。至少在原则上,可以通过将族中的每个元素分解为素数幂和可选单位的乘积,并对每个素数取因子分解中出现的最小幂。这些素数幂的乘积就是最大公约数。最小公倍数可以从与每个素数的最大幂乘积相同的因式分解中获得。

欧几里德域#

计算最大公约数的实用算法可以在 欧几里德域 . 它们是可以赋予函数的积分域 \(w\) 为域的每个非零元素分配一个非负整数,并具有以下属性:

如果 \(a\)\(b\) 不是零,有 \(q\)\(r\) 满足 部门标识

\(a = qb + r\)

也就是说 \(r = 0\)\(w(r) < w(b)\) .

域上的整数环和所有一元多项式环都是具有 \(w(a) = |a|\) RESP \(w(a) = \deg(a)\) .

整数的除法标识在Python中作为内置函数实现 divmod 也可以应用于SymPy整数:

>>> divmod(Integer(53), Integer(7))
(7, 4)

对于多项式,除法恒等式是由函数在symmy中给出的 div() ::

>>> f = 5*x**2 + 10*x + 3
>>> g = 2*x + 2

>>> q, r = div(f, g, domain='QQ')
>>> q
5*x   5
--- + -
 2    2
>>> r
-2
>>> (q*g + r).expand()
   2
5*x  + 10*x + 3

除法恒等式可用于确定欧氏域中元素的可除性。如果 \(r = 0\) 在部门的身份,那么 \(a\) 可分为 \(b\) . 相反,如果 \(a = cb\) 对于某些元素 \(c\) 然后 \((c - q)b = r\) . 因此 \(c = q\)\(r = 0\) 如果 \(w\) 具有附加属性:

如果 \(a\)\(b\) 那么不是零 \(w(ab) \ge w(b)\) .

上述函数可满足这一要求。(而且总是可以重新定义 \(w(a)\) 取最小值 \(w(xa)\) 对于 \(x \ne 0\)

除法恒等式的主要应用是利用 Euclidean algorithm . 它适用于欧几里德域的两个元素。通过迭代可以得到多个元素的gcd。

在SymPy中计算整数的最大公约数的函数是 igcd() ::

>>> igcd(2, 4)
2
>>> igcd(5, 10, 15)
5

对于域上的一元多项式,函数有它的通用名 gcd() ,返回的多项式是monic::

>>> f = 4*x**2 - 1
>>> g = 8*x**3 + 1
>>> gcd(f, g, domain=QQ)
x + 1/2

多项式的可除性#

戒指 \(A = \mathbb{{Z}}[x]\) 整数环上的一元多项式不是欧几里德的,但它仍然是阶乘的。要了解这一点,请考虑 \(A\) .

\(f\)\(g\) 是两个非零多项式 \(A\) .如果 \(f\) 可分为 \(g\) 在里面 \(A\) ,那么它在环中也是可分的 \(B = \mathbb{{Q}}[x]\) 具有有理系数的多项式。因为 \(B\) 是欧几里德的,这可以通过划分恒等式来确定。

相反地,假设 \(f = gh\) 对于某个多项式 \(h\) 在里面 \(B\) . 然后 \(f\) 可分为 \(g\) 在里面 \(A\) 当且仅当 \(h\) 是整数。要想知道什么时候是真的,有必要考虑系数的整除性。

对于多项式 \(f\) 在里面 \(A\) ,让 \(c\) 是其系数的最大公约数。那么 \(f\) 可被常数多项式整除 \(c\) 在里面 \(A\) ,以及商 \(f/c= p\) 除了一个多项式的系数之外,它的系数是没有公约数的。这种多项式叫做 原始的 . 有理系数多项式也可以写成 \(f = cp\) 在哪里 \(c\) 是一个有理数,并且 \(p\) 是一个本原多项式。常数 \(c\) 被称为 内容 属于 \(f\)\(p\) 是吗? 原始部分 . 这些成分可以通过该方法找到 sympy.core.expr.Expr.as_content_primitive ::

>>> f = 6*x**2 - 3*x + 9
>>> c, p = f.as_content_primitive()
>>> c, p
       2
(3, 2*x  - x + 3)
>>> f = x**2/3 - x/2 + 1
>>> c, p = f.as_content_primitive()
>>> c, p
         2
(1/6, 2*x  - 3*x + 6)

\(f\), \(f'\) be polynomials with contents \(c\), \(c'\) and primitive parts \(p\), \(p'\). Then \(ff' = (cc')(pp')\) where the product \(pp'\) is primitive by Gauss's lemma . 因此

多项式乘积的内容是其内容的乘积,乘积的原始部分是原始部分的乘积。

回到环中的可除性 \(\mathbb{{Z}}[x]\) ,假设 \(f\)\(g\) 是两个整系数多项式,其除法恒等式 \(\mathbb{{Q}}[x]\) 产生相等 \(f = gh\) 对于某个多项式 \(h\) 有理性的系数。那么 \(f\) 等于 \(g\) 乘以 \(h\) . AS \(h\) 具有整数系数当且仅当其内容为整数时,我们得到以下条件:

\(f\) 可分为 \(g\) 在拳击场上 \(\mathbb{{Z}}[x]\) 当且仅当

  1. \(f\) 可分为 \(g\) 在里面 \(\mathbb{{Q}}[x]\)

  2. 内容 \(f\) 可被…的内容整除 \(g\) 在里面 \(\mathbb{{Z}}\) .

如果 \(f = cp\)\(\mathbb{{Z}}[x]\) ,或者 \(c\)\(p\) 必须是一个单位。如果 \(p\) 不是一个单位,它必须是不可约的也在 \(\mathbb{{Q}}[x]\) . 因为如果它是两个多项式的乘积,那么它也是它们的原始部分的乘积,其中一个必须是一个单位。因此有两种不可约元素 \(\mathbb{{Z}}[x]\)

  1. 质数 \(\mathbb{{Z}}\)

  2. 不可约的本原多项式 \(\mathbb{{Q}}[x]\) .

因此每个多项式 \(\mathbb{{Z}}[x]\) 是不可约元素的产物。它只需将其内容和原始部分分开考虑。这些产品本质上是独一无二的;因此 \(\mathbb{{Z}}[x]\) 也是阶乘的。

另一个重要的结果是 \(\mathbb{{Z}}[x]\) 将欧几里德算法分别应用于欧几里德域中的内容和原始部分,可以有效地找到它们 \(\mathbb{{Z}}\)\(\mathbb{{Q}}[x]\) . 这也在SymPy中实现:

>>> f = 4*x**2 - 1
>>> g = 8*x**3 + 1
>>> gcd(f, g)
2*x + 1
>>> gcd(6*f, 3*g)
6*x + 3

基本功能#

这些函数提供了处理多项式的不同算法,如符号、和等。

除法#

The function div() provides division of polynomials with remainder. That is, for polynomials f and g, it computes q and r, such that \(f = g \cdot q + r\) and \(\deg(r) < \deg(q)\). For polynomials in one variables with coefficients in a field, say, the rational numbers, q and r are uniquely defined this way:

>>> f = 5*x**2 + 10*x + 3
>>> g = 2*x + 2

>>> q, r = div(f, g, domain='QQ')
>>> q
5*x   5
--- + -
 2    2
>>> r
-2
>>> (q*g + r).expand()
   2
5*x  + 10*x + 3

正如你所看到的, q 具有非整数系数。如果只想在整系数多项式环中进行除法,可以指定一个附加参数:

>>> q, r = div(f, g, domain='ZZ')
>>> q
0
>>> r
   2
5*x  + 10*x + 3

但要注意的是,这个环不再是欧几里德环,余数的阶数不必小于 f . 因为2不能除以5, \(2 x\) 不会分裂 \(5 x^2\) ,即使度数较小。但是:

>>> g = 5*x + 1

>>> q, r = div(f, g, domain='ZZ')
>>> q
x
>>> r
9*x + 3
>>> (q*g + r).expand()
   2
5*x  + 10*x + 3

这也适用于具有多个变量的多项式:

>>> f = x*y + y*z
>>> g = 3*x + 3*z

>>> q, r = div(f, g, domain='QQ')
>>> q
y
-
3
>>> r
0

在最后的例子中,所有三个变量 xyz 假设是多项式的变量。但是如果有一些不相关的常数作为系数,可以显式地指定变量:

>>> a, b, c = symbols('a,b,c')
>>> f = a*x**2 + b*x + c
>>> g = 3*x + 2
>>> q, r = div(f, g, domain='QQ')
>>> q
a*x   2*a   b
--- - --- + -
 3     9    3

>>> r
4*a   2*b
--- - --- + c
 9     3

GCD和LCM#

除法还需要计算最大公约数和最小公倍数。

当多项式具有整系数时,还考虑内容的gcd::

>>> f = (12*x + 12)*x
>>> g = 16*x**2
>>> gcd(f, g)
4*x

但是如果多项式有有理系数,那么返回的多项式是monic::

>>> f = 3*x**2/2
>>> g = 9*x/4
>>> gcd(f, g)
x

它也适用于多个变量。在这种情况下,变量是按字母顺序排列的,默认情况下,这会影响前导系数:

>>> f = x*y/2 + y**2
>>> g = 3*x + 6*y

>>> gcd(f, g)
x + 2*y

lcm与gcd相连,其中一个可以使用另一个进行计算:

>>> f = x*y**2 + x**2*y
>>> g = x**2*y**2
>>> gcd(f, g)
x*y
>>> lcm(f, g)
 3  2    2  3
x *y  + x *y
>>> (f*g).expand()
 4  3    3  4
x *y  + x *y
>>> (gcd(f, g, x, y)*lcm(f, g, x, y)).expand()
 4  3    3  4
x *y  + x *y

无平方因式分解#

一元多项式的无平方因式分解是1次、2次等所有因子(不一定不可约)的乘积:

>>> f = 2*x**2 + 5*x**3 + 4*x**4 + x**5

>>> sqf_list(f)
                   2
(1, [(x + 2, 1), (x  + x, 2)])

>>> sqf(f)
                2
        / 2    \
(x + 2)*\x  + x/

因式分解#

此函数提供有理系数的一元多项式和多元多项式的因式分解:

>>> factor(x**4/2 + 5*x**3/12 - x**2/3)
 2
x *(2*x - 1)*(3*x + 4)
----------------------
          12

>>> factor(x**2 + 4*x*y + 4*y**2)
         2
(x + 2*y)

格罗伯纳基地#

实现了Buchberger算法,支持各种单项式:

>>> groebner([x**2 + 1, y**4*x + x**3], x, y, order='lex')
             /[ 2       4    ]                            \
GroebnerBasis\[x  + 1, y  - 1], x, y, domain=ZZ, order=lex/


>>> groebner([x**2 + 1, y**4*x + x**3, x*y*z**3], x, y, z, order='grevlex')
             /[ 4       3   2    ]                                   \
GroebnerBasis\[y  - 1, z , x  + 1], x, y, z, domain=ZZ, order=grevlex/

解方程#

我们有(不完全的)方法来求多项式的复根甚至符号根,以及解一些多项式方程组:

>>> from sympy import roots, solve_poly_system

>>> solve(x**3 + 2*x + 3, x)
           ____          ____
     1   \/ 11 *I  1   \/ 11 *I
[-1, - - --------, - + --------]
     2      2      2      2

>>> p = Symbol('p')
>>> q = Symbol('q')

>>> solve(x**2 + p*x + q, x)
          __________           __________
         /  2                 /  2
   p   \/  p  - 4*q     p   \/  p  - 4*q
[- - - -------------, - - + -------------]
   2         2          2         2

>>> solve_poly_system([y - x, x - 5], x, y)
[(5, 5)]

>>> solve_poly_system([y**2 - x**3 + 1, y*x], x, y)
                                   ___                 ___
                             1   \/ 3 *I         1   \/ 3 *I
[(0, -I), (0, I), (1, 0), (- - - -------, 0), (- - + -------, 0)]
                             2      2            2      2