数字域

介绍

与代数数论中的许多其他计算一样,有理素数的分裂只能通过 有理 方法来处理。如果考虑通过自动计算机器进行计算,这一事实非常重要。只需要知道不可约多项式 \(f(x)\),其零点生成所讨论的域。

—奥尔加·陶斯基,1953年

诸如数域和代数数等概念对于我们理解代数数论至关重要,但对于计算机而言,这个主题完全是关于多项式的:环 \(\mathbb{Q}[x]\) 在不可约多项式 \(f(x) \in \mathbb{Q}[x]\) 下的模约简。因此,它在 SymPy 的 polys 模块下找到了自然的归属。

不同的作者(如 Taussky、Zimmer、Pohst 和 Zassenhaus,或 Cohen)以不同的方式阐述了计算代数数论的主要目标,但这些列表的核心始终围绕着一组基本的任务。作为 SymPy 中 numberfields 模块的目标,我们可以根据 [Cohen93],第 4.9.3 节,设定以下列表。

对于一个数域 \(K = \mathbb{Q}(\theta)\),其代数整数环记作 \(\mathbb{Z}_K\),计算:

  1. \(\mathbb{Z}_K\) 的整基

  2. \(\mathbb{Z}_K\) 中有理素数的分解

  3. 理想和元素的\(\mathfrak{p}\)-进赋值

  4. 伽罗瓦群的伽罗瓦闭包 \(K\)

  5. 一个基本单位为 \(K\) 的系统

  6. 调节器 \(R(K)\)

  7. 类编号

  8. 类群 \(Cl(K)\) 的结构

  9. 确定给定的理想是否是主理想,如果是,则计算一个生成元。

作为基础,为了支持我们定义和处理数域及代数数的基本能力,我们按照 [Cohen93] ,第4.5节,设置了以下问题。

  1. 给定一个代数数——通过根式和有理运算表示,或甚至作为某个超越函数的特殊值——确定其在 \(\mathbb{Q}\) 上的最小多项式。

  2. 子域问题:给定两个数域 \(\mathbb{Q}(\alpha)\)\(\mathbb{Q}(\beta)\),通过它们的生成元 \(\alpha\)\(\beta\) 的最小多项式,判断其中一个域是否同构于另一个域的子域,如果是,则展示一个嵌入。

  3. 域成员问题:给定两个代数数 \(\alpha\), \(\beta\),判断 \(\alpha \in \mathbb{Q}(\beta)\) 是否成立,如果成立则写出 \(\alpha = f(\beta)\) 对于某些 \(f(x) \in \mathbb{Q}[x]\)

  4. 原始元素问题:给定若干代数数 \(\alpha_1, \ldots, \alpha_m\),计算一个代数数 \(\theta\),使得 \(\mathbb{Q}(\alpha_1, \ldots, \alpha_m) = \mathbb{Q}(\theta)\)

目前,SymPy 仅支持上述列举任务的一部分,如果你有兴趣扩展支持,欢迎贡献!一个优秀的资源,提供了所有剩余问题(以及已解决的问题)的解决方案,是 [Cohen93]

在撰写本文时,上述问题的现有解决方案可以在以下位置找到:

任务

实现

  1. 积分基

round_two()

  1. 质因数分解

prime_decomp()

  1. \(\mathfrak{p}\)进赋值

prime_valuation()

  1. 伽罗瓦群

galois_group()

  1. 找到最小多项式

minimal_polynomial()

  1. 子领域

field_isomorphism()

  1. 字段成员资格

to_number_field()

  1. 原始元素

primitive_element()

解决主要问题

积分基底

sympy.polys.numberfields.basis.round_two(T, radicals=None)[源代码][源代码]

Zassenhaus 的“第二轮”算法。

参数:
TPoly, AlgebraicField

要么 (1) 定义数域的不可约多项式在 ZZQQ 上,要么 (2) 一个表示数域本身的 AlgebraicField

部首dict, 可选

这是一种让任何 \(p\)-根(如果计算了)通过引用返回的方式。如果需要,可以传递一个空字典。如果算法运行到计算整数环 \(Z_K\)\(p\)-幂零根模 \(p\) 的阶段,那么这个理想的 \(\mathbb{F}_p\)-基将被存储在这个字典中,键为 p。这对于其他算法(如素数分解)可能很有用。

返回:
(ZK, dK),其中:

ZK 是一个 Submodule ,表示最大阶。

dK 是域 \(K = \mathbb{Q}[x]/(T(x))\) 的判别式。

参考文献

[1]

Cohen, H. 计算代数数论课程.

示例

通过代数域工作:

>>> from sympy import Poly, QQ
>>> from sympy.abc import x
>>> T = Poly(x ** 3 + x ** 2 - 2 * x + 8)
>>> K = QQ.alg_field_from_poly(T, "theta")
>>> print(K.maximal_order())
Submodule[[2, 0, 0], [0, 2, 0], [0, 1, 1]]/2
>>> print(K.discriminant())
-503
>>> print(K.integral_basis(fmt='sympy'))
[1, theta, theta/2 + theta**2/2]

直接调用:

>>> from sympy import Poly
>>> from sympy.abc import x
>>> from sympy.polys.numberfields.basis import round_two
>>> T = Poly(x ** 3 + x ** 2 - 2 * x + 8)
>>> print(round_two(T))
(Submodule[[2, 0, 0], [0, 2, 0], [0, 1, 1]]/2, -503)

在第二轮算法中有时计算的模 \(p\) 的零化子可能在进一步的计算中很有用。通过 \(radicals\) 传递一个字典来接收这些:

>>> T = Poly(x**3 + 3*x**2 + 5)
>>> rad = {}
>>> ZK, dK = round_two(T, radicals=rad)
>>> print(rad)
{3: Submodule[[-1, 1, 0], [-1, 0, 1]]}

质因数分解

sympy.polys.numberfields.primes.prime_decomp(
p,
T=None,
ZK=None,
dK=None,
radical=None,
)[源代码][源代码]

计算有理素数 p 在数域中的分解。

参数:
p整数

所需分解的有理素数。

T : Poly, 可选Poly, 可选

定义数域 \(K\) 的不可约多项式。注意:至少需要提供 TZK 中的一个。

ZK : 子模块, 可选子模块,可选

如果已知,\(K\) 的最大阶数。注意:TZK 中至少有一个必须提供。

dKint, 可选

\(K\) 的判别式,如果已经知道的话。

radical : Submodule, 可选子模块,可选

\(K\) 的整数中的模 p 的零化子,如果已经知道的话。

返回:
列表 PrimeIdeal 实例。

参考文献

[1]

Cohen, H. 计算代数数论课程. (参见算法6.2.9.)

示例

>>> from sympy import Poly, QQ
>>> from sympy.abc import x, theta
>>> T = Poly(x ** 3 + x ** 2 - 2 * x + 8)
>>> K = QQ.algebraic_field((T, theta))
>>> print(K.primes_above(2))
[[ (2, x**2 + 1) e=1, f=1 ], [ (2, (x**2 + 3*x + 2)/2) e=1, f=1 ],
 [ (2, (3*x**2 + 3*x)/2) e=1, f=1 ]]
class sympy.polys.numberfields.primes.PrimeIdeal(ZK, p, alpha, f, e=None)[源代码][源代码]

环中代数整数的一个素理想。

属性:
is_inert

判断我们除以的有理素数是否为惰性,即

方法

as_submodule()

将这个素理想表示为一个 子模

reduce_ANP(a)

ANP 减少到这个素理想模下的“小代表”。

reduce_alg_num(a)

将一个 AlgebraicNumber 减少到这个素理想的“小代表”模。

reduce_element(elt)

PowerBasisElement 减少到此素理想模下的“小代表”。

repr([field_gen, just_gens])

打印这个素理想的表示。

test_factor()

计算此素理想的测试因子。

valuation(I)

计算整理想 I 在这个素理想上的 $mathfrak{p}$-adic 赋值。

__init__(ZK, p, alpha, f, e=None)[源代码][源代码]
参数:
ZK子模块

这个理想存在的最大阶数。

p整数

这个理想所整除的有理素数。

alphaPowerBasisElement

使得理想值等于 p*ZK + alpha*ZK

f整数

惯性度。

e : int, None, 可选整数

分支指数,如果已经知道的话。如果为 None ,我们将在这里计算它。

__add__(other)[源代码][源代码]

转换为 Submodule 并添加到另一个 Submodule

参见

as_submodule
__mul__(other)[源代码][源代码]

转换为 Submodule 并乘以另一个 Submodule 或一个有理数。

参见

as_submodule
as_submodule()[源代码][源代码]

将这个素理想表示为一个 子模

返回:
Submodule

将等于 self.p * self.ZK + self.alpha * self.ZK

参见

__add__
__mul__

示例

>>> from sympy import Poly, cyclotomic_poly, prime_decomp
>>> T = Poly(cyclotomic_poly(7))
>>> P0 = prime_decomp(7, T)[0]
>>> print(P0**6 == 7*P0.ZK)
True

注意,在上面的等式两边,我们都有一个 Submodule。在下一个等式中,我们回顾了添加理想值会得到它们的GCD。这次,我们需要在右边进行有意的转换为 Submodule

>>> print(P0 + 7*P0.ZK == P0.as_submodule())
True
property is_inert

判断我们除以的有理素数是否是惰性的,即在我们整数环中保持素数。

reduce_ANP(a)[源代码][源代码]

ANP 减少到这个素理想模下的“小代表”。

参数:
eltANP

要减少的元素。

返回:
ANP

简化后的元素。

reduce_alg_num(a)[源代码][源代码]

将一个 AlgebraicNumber 减少到这个素理想的“小代表”模。

参数:
elt : 代数数代数数

要减少的元素。

返回:
AlgebraicNumber

简化后的元素。

reduce_element(elt)[源代码][源代码]

PowerBasisElement 减少到此素理想模下的“小代表”。

参数:
eltPowerBasisElement

要减少的元素。

返回:
PowerBasisElement

简化后的元素。

repr(field_gen=None, just_gens=False)[源代码][源代码]

打印这个素理想的表示。

参数:
field_gen : Symbol, None, 可选 (默认=None)符号, 无, 可选 (默认=无)

用于字段生成器的符号。这将出现在我们对 self.alpha 的表示中。如果为 None,我们使用 self.ZK 的定义多项式的变量。

just_gensbool, 可选 (默认=False)

如果 True,则只打印“(p, alpha)”部分,显示素理想“仅生成元”。否则,打印形式为“[ (p, alpha) e=…, f=… ]”的字符串,给出分歧指数和惯性度,以及生成元。

示例

>>> from sympy import cyclotomic_poly, QQ
>>> from sympy.abc import x, zeta
>>> T = cyclotomic_poly(7, x)
>>> K = QQ.algebraic_field((T, zeta))
>>> P = K.primes_above(11)
>>> print(P[0].repr())
[ (11, x**3 + 5*x**2 + 4*x - 1) e=1, f=3 ]
>>> print(P[0].repr(field_gen=zeta))
[ (11, zeta**3 + 5*zeta**2 + 4*zeta - 1) e=1, f=3 ]
>>> print(P[0].repr(field_gen=zeta, just_gens=True))
(11, zeta**3 + 5*zeta**2 + 4*zeta - 1)
test_factor()[源代码][源代码]

计算此素理想的测试因子。

valuation(I)[源代码][源代码]

计算整理想 I 在这个素理想上的 \(\mathfrak{p}\)-adic 赋值。

参数:
: Submodule子模块

p-adic 赋值

sympy.polys.numberfields.primes.prime_valuation(I, P)[源代码][源代码]

计算整理想数 IP-adic 赋值。

参数:
: Submodule子模块

一个期望求其赋值的整理想法。

P素理想

计算估值的质数。

返回:
整数

参考文献

[1]

Cohen, H. 计算代数数论课程. (参见算法4.8.17.)

示例

>>> from sympy import QQ
>>> from sympy.polys.numberfields import prime_valuation
>>> K = QQ.cyclotomic_field(5)
>>> P = K.primes_above(5)
>>> ZK = K.maximal_order()
>>> print(prime_valuation(25*ZK, P[0]))
8

伽罗瓦群

sympy.polys.numberfields.galoisgroups.galois_group(
f,
*gens,
by_name=False,
max_tries=30,
randomize=False,
**args,
)[源代码][源代码]

计算次数不超过6的多项式 f 的伽罗瓦群。

参数:
f表达式

ZZQQ 上的不可约多项式,其伽罗瓦群待确定。

生成可选的符号列表

用于将 f 转换为 Poly,并将传递给 poly_from_expr() 函数。

按名称bool, 默认 False

如果 True,伽罗瓦群将按名称返回。否则,它将作为 PermutationGroup 返回。

max_triesint, 默认 30

在这些涉及生成Tschirnhausen变换的步骤中,最多进行这么多次尝试。

随机化bool, 默认 False

如果 True ,则在生成Tschirnhausen变换时使用随机系数。否则,尝试按固定顺序进行变换。两种方法都从小系数和度数开始,并向上工作。

参数可选的

用于将 f 转换为 Poly,并将传递给 poly_from_expr() 函数。

返回:
(G, alt)

第一个元素 G 表示伽罗瓦群。如果 by_nameTrue,它是 sympy.combinatorics.galois.S1TransitiveSubgroups sympy.combinatorics.galois.S2TransitiveSubgroups 等枚举类的一个实例;如果为 False,则是一个 PermutationGroup

第二个元素是一个布尔值,表示该组是否包含在交错群 \(A_n\) 中(\(n\)T 的度数)。

Raises:
ValueError

如果 f 的次数不被支持。

MaxTriesException

如果在那些涉及生成Tschirnhausen变换的步骤中,在超过*max_tries*之前无法完成。

示例

>>> from sympy import galois_group
>>> from sympy.abc import x
>>> f = x**4 + 1
>>> G, alt = galois_group(f)
>>> print(G)
PermutationGroup([
(0 1)(2 3),
(0 2)(1 3)])

该群组与一个布尔值一起返回,该布尔值指示它是否包含在交替群 \(A_n\) 中,其中 \(n\)T 的度数。与其他群组属性一起,这可以帮助确定它是哪个群组:

>>> alt
True
>>> G.order()
4

或者,可以通过名称返回组:

>>> G_name, _ = galois_group(f, by_name=True)
>>> print(G_name)
S4TransitiveSubgroups.V

然后可以通过调用名称的 get_perm_group() 方法来获取该组:

>>> G_name.get_perm_group()
PermutationGroup([
(0 1)(2 3),
(0 2)(1 3)])

组名是枚举类 sympy.combinatorics.galois.S1TransitiveSubgroupssympy.combinatorics.galois.S2TransitiveSubgroups 等的值。

寻找最小多项式

sympy.polys.numberfields.minpoly.minimal_polynomial(
ex,
x=None,
compose=True,
polys=False,
domain=None,
)[源代码][源代码]

计算代数元素的最小多项式。

参数:
示例表达式

要计算其最小多项式的元素或表达式。

x符号, 可选

最小多项式的自变量

组合布尔值,可选(默认=True)

用于计算最小多项式的方法。如果 compose=True``(默认),则使用 ``_minpoly_compose,如果 compose=False,则使用 Groebner 基。

多边形布尔值,可选(默认=False)

如果 True 返回一个 Poly 对象,否则返回一个 Expr 对象。

领域域, 可选

基础领域

注释

默认情况下 compose=True,会计算 ex 子表达式的最小多项式,然后使用结果和因式分解对它们进行算术运算。如果 compose=False,则使用 groebner 的底向上算法。默认算法停滞频率较低。

如果没有指定地面域,它将根据表达式自动生成。

示例

>>> from sympy import minimal_polynomial, sqrt, solve, QQ
>>> from sympy.abc import x, y
>>> minimal_polynomial(sqrt(2), x)
x**2 - 2
>>> minimal_polynomial(sqrt(2), x, domain=QQ.algebraic_field(sqrt(2)))
x - sqrt(2)
>>> minimal_polynomial(sqrt(2) + sqrt(3), x)
x**4 - 10*x**2 + 1
>>> minimal_polynomial(solve(x**3 + x + 3)[0], x)
x**3 + x + 3
>>> minimal_polynomial(sqrt(y), x)
x**2 - y
sympy.polys.numberfields.minpoly.minpoly(
ex,
x=None,
compose=True,
polys=False,
domain=None,
)[源代码][源代码]

这是 minimal_polynomial() 的同义词。

子域问题

polys.numberfields.subfield 中的函数解决了代数数域中的“子域问题”及其相关问题。

根据Cohen(参见 [Cohen93] 第4.5节),我们可以将主要问题定义如下:

  • 子域问题:

    给定两个数域 \(\mathbb{Q}(\alpha)\)\(\mathbb{Q}(\beta)\),通过它们的生成元 \(\alpha\)\(\beta\) 的最小多项式,判断其中一个域是否同构于另一个域的子域。

从解决这个问题中,也流出了以下问题的解决方案:

  • 原始元素问题:

    给定几个代数数 \(\alpha_1, \ldots, \alpha_m\),计算一个代数数 \(\theta\) 使得 \(\mathbb{Q}(\alpha_1, \ldots, \alpha_m) = \mathbb{Q}(\theta)\)

  • 域同构问题:

    确定两个数域 \(\mathbb{Q}(\alpha)\), \(\mathbb{Q}(\beta)\) 是否同构。

  • 字段成员问题:

    给定两个代数数 \(\alpha\), \(\beta\),判断 \(\alpha \in \mathbb{Q}(\beta)\) 是否成立,如果成立则写出 \(\alpha = f(\beta)\) 对于某些 \(f(x) \in \mathbb{Q}[x]\)

sympy.polys.numberfields.subfield.field_isomorphism(a, b, *, fast=True)[源代码][源代码]

找到一个数域到另一个数域的嵌入。

参数:
a表达式

任何表示代数数的表达式。

b表达式

任何表示代数数的表达式。

快速布尔值,可选(默认=True)

如果 True,我们首先尝试一种可能更快的计算同构的方法,如果失败则回退到一种较慢的方法。如果 False,我们直接使用较慢的方法,该方法保证返回结果。

返回:
有理数列表,或 None

如果 \(\mathbb{Q}(a)\)\(\mathbb{Q}(b)\) 的某个子域不同构,则返回 None。否则,返回一个有理数列表,表示 \(\mathbb{Q}(b)\) 中的一个元素,该元素可以映射 \(a\),以定义一个单态,即从 \(\mathbb{Q}(a)\)\(\mathbb{Q}(b)\) 的某个子域的同构。列表中的元素是 \(b\) 的降幂的系数。

示例

>>> from sympy import sqrt, field_isomorphism, I
>>> print(field_isomorphism(3, sqrt(2)))  
[3]
>>> print(field_isomorphism( I*sqrt(3), I*sqrt(3)/2))  
[2, 0]
sympy.polys.numberfields.subfield.primitive_element(
extension,
x=None,
*,
ex=False,
polys=False,
)[源代码][源代码]

在给定多个生成元的情况下,找到一个数域的单一生成元。

参数:
扩展 : Expr 的列表列表

每个表达式必须表示一个代数数 \(\alpha_i\)

x : Symbol, 可选 (默认=None)符号, 可选 (默认=None)

期望在原始元素 \(\theta\) 的计算最小多项式中出现的符号。如果为 None,我们使用一个虚拟符号。

示例布尔值,可选(默认=False)

当且仅当为``True``时,将每个\(\alpha_i\)表示为\(\theta\)的幂次的\(\mathbb{Q}\)-线性组合。

多边形布尔值,可选(默认=False)

如果 True,返回最小多项式作为 Poly。否则返回它作为 Expr

返回:
配对 (f, coeffs) 或三元组 (f, coeffs, reps),其中:

f 是本原元素的最小多项式。coeffs 给出了本原元素作为给定生成元的线性组合。reps 仅在传递参数 ex=True 时存在,并且是一个有理数列表的列表。每个列表给出了本原元素的下降幂的系数,以恢复原始的给定生成元之一。

示例

>>> from sympy import primitive_element, sqrt, S, minpoly, simplify
>>> from sympy.abc import x
>>> f, lincomb, reps = primitive_element([sqrt(2), sqrt(3)], x, ex=True)

然后 lincomb 告诉我们基元元素作为给定生成元 sqrt(2)sqrt(3) 的线性组合。

>>> print(lincomb)
[1, 1]

这意味着原始元素是 \(\sqrt{2} + \sqrt{3}\)。同时,f 是这个原始元素的最小多项式。

>>> print(f)
x**4 - 10*x**2 + 1
>>> print(minpoly(sqrt(2) + sqrt(3), x))
x**4 - 10*x**2 + 1

最后,reps``(仅因为我们设置了关键字参数 ``ex=True 才返回)告诉我们如何将每个生成元 \(\sqrt{2}\)\(\sqrt{3}\) 恢复为原始元素 \(\sqrt{2} + \sqrt{3}\) 的幂次的 \(\mathbb{Q}\)-线性组合。

>>> print([S(r) for r in reps[0]])
[1/2, 0, -9/2, 0]
>>> theta = sqrt(2) + sqrt(3)
>>> print(simplify(theta**3/2 - 9*theta/2))
sqrt(2)
>>> print([S(r) for r in reps[1]])
[-1/2, 0, 11/2, 0]
>>> print(simplify(-theta**3/2 + 11*theta/2))
sqrt(3)
sympy.polys.numberfields.subfield.to_number_field(
extension,
theta=None,
*,
gen=None,
alias=None,
)[源代码][源代码]

在由另一个代数数生成的域中表示一个代数数。

参数:
扩展 : ExprExpr 列表Expr 或 Expr 列表

要么是要在另一个域中表示的代数数,要么是一个代数数列表,其本原元素要在另一个域中表示。

theta : Expr, None, 可选 (默认=None)Expr, None, 可选 (默认=None)

如果是一个表示代数数的 Expr ,其行为如 解释 部分所述。如果是 None ,则此函数简化为对 extension 调用 primitive_element() 并将计算出的原始元素转换为 AlgebraicNumber 的简写。

gen : Symbol, None, 可选 (默认=None)符号, 无, 可选 (默认=无)

如果提供,这将作为返回的 AlgebraicNumber 中极小多项式的生成元符号。

别名 : str, Symbol, None, 可选 (默认=None)str, Symbol, None, optional (default=None)

如果提供,这将用作返回的 AlgebraicNumber 的别名符号。

返回:
代数数

属于 \(\mathbb{Q}(\theta)\) 且等于 \(\eta\)

Raises:
同构失败

如果 \(\eta \not\in \mathbb{Q}(\theta)\)

示例

>>> from sympy import sqrt, to_number_field
>>> eta = sqrt(2)
>>> theta = sqrt(2) + sqrt(3)
>>> a = to_number_field(eta, theta)
>>> print(type(a))
<class 'sympy.core.numbers.AlgebraicNumber'>
>>> a.root
sqrt(2) + sqrt(3)
>>> print(a)
sqrt(2)
>>> a.coeffs()
[1/2, 0, -9/2, 0]

我们得到一个 AlgebraicNumber,其 .root\(\theta\),其值是 \(\eta\),而其 .coeffs() 展示了如何将 \(\eta\) 写成 \(\theta\) 的降幂的 \(\mathbb{Q}\)-线性组合。

内部机制

代数数域

代数数域在SymPy中由 AlgebraicField 类表示,它是 多项式域系统 的一部分。

表示代数数

表示代数数有几种不同的方法,不同的形式可能适用于不同的计算任务。参见 [Cohen93],第 4.2 节。

作为数字字段元素

在 SymPy 中,一方面,数字和表达式类定义在 sympy.core.numbers 模块中,另一方面,域和域元素定义在 polys 模块中。这方面的更多细节在 这里 有详细解释。

说到代数数,sympy.core.numbers 模块提供了 AlgebraicNumber 类,而 polys 模块提供了 ANP 类。这是属于 AlgebraicField 域的元素类型。

作为有限生成模的元素

在计算代数数论中,有限生成的 \(\mathbb{Z}\)-模是至关重要的。例如,每个序_和每个理想_都是这样的模。

特别是,数域中的最大阶——或称`整数环`_——是一个有限生成的\(\mathbb{Z}\)-模,其生成元构成该域的`整基`_。

允许我们表示这些模块及其元素的类在 modules 模块中提供。在这里,ModuleElement 类提供了另一种表示代数数的方式。

有限生成的模

数域中的模。

这里定义的类允许我们处理有限生成的自由模,其生成元是代数数。

有一个名为 Module 的抽象基类,它有两个具体子类,分别是 PowerBasisSubmodule

每个模块由其基础或生成器集合定义:

  • 对于 PowerBasis ,生成器是代数整数 \(\theta\) 的前 \(n\) 次幂(从第零次开始),其中 \(\theta\) 的次数为 \(n\)PowerBasis 是通过传递 \(\theta\) 的最小多项式,或者一个以 \(\theta\) 为其原始元素的 AlgebraicField 来构造的。

  • 对于一个 Submodule,生成元是一组另一个模的生成元的 \(\mathbb{Q}\)-线性组合。那个另一个模就是 Submodule 的“父模”。\(\mathbb{Q}\)-线性组合的系数可以由一个整数矩阵和一个正整数分母给出。矩阵的每一列定义了一个生成元。

>>> from sympy.polys import Poly, cyclotomic_poly, ZZ
>>> from sympy.abc import x
>>> from sympy.polys.matrices import DomainMatrix, DM
>>> from sympy.polys.numberfields.modules import PowerBasis
>>> T = Poly(cyclotomic_poly(5, x))
>>> A = PowerBasis(T)
>>> print(A)
PowerBasis(x**4 + x**3 + x**2 + x + 1)
>>> B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ), denom=3)
>>> print(B)
Submodule[[2, 0, 0, 0], [0, 2, 0, 0], [0, 0, 2, 0], [0, 0, 0, 2]]/3
>>> print(B.parent)
PowerBasis(x**4 + x**3 + x**2 + x + 1)

因此,每个模块要么是一个 PowerBasis,要么是一个 Submodule,其某个祖先是一个 PowerBasis。(如果 S 是一个 Submodule,那么它的祖先是 S.parentS.parent.parent,依此类推)。

ModuleElement 类表示任意模块的生成元的线性组合。关键在于,这个线性组合的系数不受限于整数,可以是任何有理数。这是必要的,以便从原始元素 \(\theta\) 的幂基开始,表示任何和所有代数整数。例如,在二次域 \(\mathbb{Q}(\sqrt{d})\) 中,当 \(d \equiv 1 \mod{4}\) 时,需要一个分母为 \(2\) 的系数。

一个 ModuleElement 可以从一个整数列向量和一个分母构造:

>>> U = Poly(x**2 - 5)
>>> M = PowerBasis(U)
>>> e = M(DM([[1], [1]], ZZ), denom=2)
>>> print(e)
[1, 1]/2
>>> print(e.module)
PowerBasis(x**2 - 5)

The PowerBasisElement 类是 ModuleElement 的子类,表示 PowerBasis 的元素,并增加了与直接表示在原始元素 \(\theta\) 的幂上的元素相关的功能。

模元素的算术

虽然 ModuleElement 表示某个模块生成元上的线性组合,但请记住,每个模块要么是 PowerBasis,要么是其沿着一系列 Submodule 对象的派生,因此实际上每个 ModuleElement 表示某个域 \(\mathbb{Q}(\theta)\) 中的代数数,其中 \(\theta\) 是某个 PowerBasis 的定义元素。因此,讨论给定 ModuleElement 所属的数域是有意义的。

这意味着任何两个 ModuleElement 实例都可以相加、相减、相乘或相除,前提是它们属于同一个数域。同样,由于 \(\mathbb{Q}\) 是每个数域的子域,任何 ModuleElement 都可以与任何有理数相加、相乘等。

>>> from sympy import QQ
>>> from sympy.polys.numberfields.modules import to_col
>>> T = Poly(cyclotomic_poly(5))
>>> A = PowerBasis(T)
>>> C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
>>> e = A(to_col([0, 2, 0, 0]), denom=3)
>>> f = A(to_col([0, 0, 0, 7]), denom=5)
>>> g = C(to_col([1, 1, 1, 1]))
>>> e + f
[0, 10, 0, 21]/15
>>> e - f
[0, 10, 0, -21]/15
>>> e - g
[-9, -7, -9, -9]/3
>>> e + QQ(7, 10)
[21, 20, 0, 0]/30
>>> e * f
[-14, -14, -14, -14]/15
>>> e ** 2
[0, 0, 4, 0]/9
>>> f // g
[7, 7, 7, 7]/15
>>> f * QQ(2, 3)
[0, 0, 0, 14]/15

然而,在对 ModuleElement 进行算术运算时必须小心,因为结果所属的模块 \(C\) 将是两个操作数所属模块 \(A\)\(B\) 的最近共同祖先(NCA),而 \(C\) 可能与 \(A\)\(B\) 中的任何一个或两者都不同。

>>> A = PowerBasis(T)
>>> B = A.submodule_from_matrix(2 * DomainMatrix.eye(4, ZZ))
>>> C = A.submodule_from_matrix(3 * DomainMatrix.eye(4, ZZ))
>>> print((B(0) * C(0)).module == A)
True

在执行算术运算之前,两个操作数的副本会自动转换为NCA的元素(操作数本身不会被修改)。沿着祖先链的这种向上转换很简单:它只需要依次乘以每个 Submodule 的定义矩阵。

相反地,向下转换,即在子模块中表示给定的 ModuleElement,也是支持的——具体通过 represent() 方法——但并不保证在一般情况下成功,因为给定的元素可能不属于该子模块。这种情况主要在乘法时出现,因为虽然模块在加法下是封闭的,但在乘法下未必是封闭的。

乘法

一般来说,一个模不需要在乘法下封闭,即不需要形成一个环。然而,我们在数域的背景下使用的许多模实际上是环,并且我们的类确实支持乘法。

具体来说,任何 Module 都可以尝试计算其自身的乘法表,但除非尝试将属于它的两个 ModuleElement 实例相乘,否则不会发生这种情况。

>>> A = PowerBasis(T)
>>> print(A._mult_tab is None)
True
>>> a = A(0)*A(1)
>>> print(A._mult_tab is None)
False

每个 PowerBasis 本质上在其乘法下是封闭的,因此 PowerBasis 的实例总是能够成功计算其乘法表。

当一个 Submodule 尝试计算其乘法表时,它将其每个生成元转换为其父模块的元素,在那里进行所有可能的配对乘法,然后尝试将结果表示为其自身的一部分,即作为其自身生成元的 \(\mathbb{Z}\)-线性组合。只有当子模块在乘法下封闭时,这一过程才会成功。

模同态

许多重要的数论算法需要计算一个或多个模同态的核。因此,我们提供了几个轻量级类,ModuleHomomorphismModuleEndomorphismInnerEndomorphismEndomorphismRing,它们提供了支持这一点所需的最小必要机制。

类参考

class sympy.polys.numberfields.modules.Module[源代码][源代码]

通用有限生成的模块。

这是一个抽象基类,不应直接实例化。两个具体的子类是 PowerBasisSubmodule

每个 Submodule 都源自另一个模块,通过其 parent 属性引用。如果 S 是一个子模块,那么我们将 S.parentS.parent.parent 等称为 S 的“祖先”。因此,每个 Module 要么是 PowerBasis,要么是 Submodule,其某个祖先是 PowerBasis

属性:
n

此模块的生成器数量。

number_field

返回相关的 AlgebraicField,如果有的话。

parent

该模块的父模块(如果有)。

方法

__call__(spec[, denom])

生成一个属于此模块的 ModuleElement

ancestors([include_self])

返回此模块的祖先模块列表,从基础的 PowerBasis 向下,可选地包括 self

basis_elements()

获取作为此模块生成器的 ModuleElement 列表。

element_from_rational(a)

返回一个表示有理数的 ModuleElement

endomorphism_ring()

形成此模块的 EndomorphismRing

is_compat_col(col)

判断 col 是否为本模块的合适列向量。

mult_tab()

获取此模块的乘法表(如果它在乘法下是封闭的)。

nearest_common_ancestor(other)

定位此模块与另一个模块的最近共同祖先。

one()

返回一个 ModuleElement 表示单位元,并且属于此模块的第一个祖先(包括自身),该祖先从单位元开始。

power_basis_ancestor()

返回作为此模块祖先的 PowerBasis

represent(elt)

将模块元素表示为该模块生成元的整数线性组合。

starts_with_unity()

判断模块的第一个生成器是否等于一。

submodule_from_gens(gens[, hnf, hnf_modulus])

从属于此模块的 ModuleElement 列表生成的子模块。

submodule_from_matrix(B[, denom])

通过矩阵的列所指示的该模块的元素生成子模块,带有可选的分母。

whole_submodule()

返回一个等于此整个模块的子模块。

zero()

返回一个表示零的 ModuleElement

__call__(spec, denom=1)[源代码][源代码]

生成一个属于此模块的 ModuleElement

参数:
specDomainMatrix, int

指定 ModuleElement 系数中的分子。可以是 ZZ 上的列向量,其长度必须等于该模块的生成元数量 \(n\),或者是一个整数 j\(0 \leq j < n\),这是 \(n \times n\) 单位矩阵 \(I_n\) 中第 \(j\) 列的简写。

denomint, 可选 (默认=1)

系数分母为 ModuleElement

返回:
ModuleElement

系数是 spec 向量的元素,除以 denom

示例

>>> from sympy.polys import Poly, cyclotomic_poly
>>> from sympy.polys.numberfields.modules import PowerBasis, to_col
>>> T = Poly(cyclotomic_poly(5))
>>> A = PowerBasis(T)
>>> e = A(to_col([1, 2, 3, 4]), denom=3)
>>> print(e)  
[1, 2, 3, 4]/3
>>> f = A(2)
>>> print(f)  
[0, 0, 1, 0]
ancestors(include_self=False)[源代码][源代码]

返回此模块的祖先模块列表,从基础的 PowerBasis 向下,可选地包括 self

参见

Module
basis_elements()[源代码][源代码]

获取作为此模块生成器的 ModuleElement 列表。

element_from_rational(a)[源代码][源代码]

返回一个表示有理数的 ModuleElement

参数:
a整数
返回:
ModuleElement

示例

>>> from sympy.polys import Poly, cyclotomic_poly, QQ
>>> from sympy.polys.numberfields.modules import PowerBasis
>>> T = Poly(cyclotomic_poly(5))
>>> A = PowerBasis(T)
>>> a = A.element_from_rational(QQ(2, 3))
>>> print(a)  
[2, 0, 0, 0]/3
endomorphism_ring()[源代码][源代码]

形成此模块的 EndomorphismRing

is_compat_col(col)[源代码][源代码]

判断 col 是否为本模块的合适列向量。

mult_tab()[源代码][源代码]

获取此模块的乘法表(如果它在乘法下是封闭的)。

返回:
字典的字典的列表
Raises:
ClosureFailure

如果该模块在乘法下不封闭。

示例

>>> from sympy.polys import Poly, cyclotomic_poly
>>> from sympy.polys.numberfields.modules import PowerBasis
>>> T = Poly(cyclotomic_poly(5))
>>> A = PowerBasis(T)
>>> print(A.mult_tab())  
{0: {0: [1, 0, 0, 0], 1: [0, 1, 0, 0], 2: [0, 0, 1, 0],     3: [0, 0, 0, 1]},
                  1: {1: [0, 0, 1, 0], 2: [0, 0, 0, 1],     3: [-1, -1, -1, -1]},
                                   2: {2: [-1, -1, -1, -1], 3: [1, 0, 0, 0]},
                                                        3: {3: [0, 1, 0, 0]}}
property n

此模块的生成器数量。

nearest_common_ancestor(other)[源代码][源代码]

定位此模块与另一个模块的最近共同祖先。

返回:
Module, None

参见

Module
property number_field

返回相关的 AlgebraicField,如果有的话。

返回:
AlgebraicField, None
one()[源代码][源代码]

返回一个 ModuleElement 表示单位元,并且属于此模块的第一个祖先(包括自身),该祖先从单位元开始。

property parent

该模块的父模块(如果有)。

返回:
Module, None

参见

Module
power_basis_ancestor()[源代码][源代码]

返回作为此模块祖先的 PowerBasis

参见

Module
represent(elt)[源代码][源代码]

将模块元素表示为该模块生成元的整数线性组合。

参数:
elt模块元素

要表示的模块元素。必须属于此模块的某个祖先模块(包括此模块本身)。

返回:
DomainMatrixZZ

这将是一个列向量,表示该模块生成元的线性组合的系数,该组合等于给定的元素。

Raises:
ClosureFailure

如果给定的元素不能表示为该模块上的 ZZ-线性组合。

示例

>>> from sympy import Poly, cyclotomic_poly
>>> from sympy.polys.numberfields.modules import PowerBasis, to_col
>>> from sympy.abc import zeta
>>> T = Poly(cyclotomic_poly(5))
>>> A = PowerBasis(T)
>>> a = A(to_col([2, 4, 6, 8]))

这个 ModuleElement a 具有所有偶数系数。如果我们在子模块 B = 2*A 中表示 a,列向量中的系数将减半:

>>> B = A.submodule_from_gens([2*A(i) for i in range(4)])
>>> b = B.represent(a)
>>> print(b.transpose())  
DomainMatrix([[1, 2, 3, 4]], (1, 4), ZZ)

然而,这样定义的 B 元素仍然代表相同的代数数:

>>> print(a.poly(zeta).as_expr())
8*zeta**3 + 6*zeta**2 + 4*zeta + 2
>>> print(B(b).over_power_basis().poly(zeta).as_expr())
8*zeta**3 + 6*zeta**2 + 4*zeta + 2
starts_with_unity()[源代码][源代码]

判断模块的第一个生成器是否等于一。

submodule_from_gens(
gens,
hnf=True,
hnf_modulus=None,
)[源代码][源代码]

从属于此模块的 ModuleElement 列表生成的子模块。

参数:
gens : 属于此模块的 ModuleElement 列表。列表
hnf布尔值,可选(默认=True)

如果为真,我们将在形成 Submodule 之前将矩阵简化为 Hermite 正规形式。

hnf_modulusint, None, 可选 (默认=None)

在 HNF 约简算法中使用的模数。参见 hermite_normal_form()

返回:
Submodule

示例

>>> from sympy.polys import Poly, cyclotomic_poly
>>> from sympy.polys.numberfields.modules import PowerBasis
>>> T = Poly(cyclotomic_poly(5))
>>> A = PowerBasis(T)
>>> gens = [A(0), 2*A(1), 3*A(2), 4*A(3)//5]
>>> B = A.submodule_from_gens(gens)
>>> print(B)  
Submodule[[5, 0, 0, 0], [0, 10, 0, 0], [0, 0, 15, 0], [0, 0, 0, 4]]/5
submodule_from_matrix(B, denom=1)[源代码][源代码]

通过矩阵的列所指示的该模块的元素生成子模块,带有可选的分母。

参数:
B : DomainMatrixZZDomainMatrix 在 ZZ 上

每一列给出了子模块的一个生成元的系数的分子。因此,B 的行数必须等于当前模块的生成元数。

denomint, 可选 (默认=1)

所有子模块生成器的共同点。

返回:
Submodule
Raises:
ValueError

如果给定的矩阵 B 不在 ZZ 上,或者其行数不等于当前模块的生成器数。

示例

>>> from sympy.polys import Poly, cyclotomic_poly, ZZ
>>> from sympy.polys.matrices import DM
>>> from sympy.polys.numberfields.modules import PowerBasis
>>> T = Poly(cyclotomic_poly(5))
>>> A = PowerBasis(T)
>>> B = A.submodule_from_matrix(DM([
...     [0, 10, 0, 0],
...     [0,  0, 7, 0],
... ], ZZ).transpose(), denom=15)
>>> print(B)  
Submodule[[0, 10, 0, 0], [0, 0, 7, 0]]/15
whole_submodule()[源代码][源代码]

返回一个等于此整个模块的子模块。

zero()[源代码][源代码]

返回一个表示零的 ModuleElement

class sympy.polys.numberfields.modules.PowerBasis(T)[源代码][源代码]

由代数整数的幂生成的模块。

属性:
n

此模块的生成器数量。

number_field

返回相关的 AlgebraicField,如果有的话。

parent

该模块的父模块(如果有)。

方法

__call__(spec[, denom])

生成一个属于此模块的 ModuleElement

ancestors([include_self])

返回此模块的祖先模块列表,从基础的 PowerBasis 向下,可选地包括 self

basis_elements()

获取作为此模块生成器的 ModuleElement 列表。

element_from_ANP(a)

将一个 ANP 转换为 PowerBasisElement。

element_from_alg_num(a)

将一个 AlgebraicNumber 转换为 PowerBasisElement。

element_from_poly(f)

生成此模块的一个元素,表示 f 在约化模我们定义的最小多项式之后的值。

element_from_rational(a)

endomorphism_ring()

形成此模块的 EndomorphismRing

is_compat_col(col)

判断 col 是否为本模块的合适列向量。

mult_tab()

nearest_common_ancestor(other)

定位此模块与另一个模块的最近共同祖先。

one()

返回一个 ModuleElement 表示单位元,并且属于此模块的第一个祖先(包括自身),该祖先从单位元开始。

power_basis_ancestor()

返回作为此模块祖先的 PowerBasis

represent(elt)

将模块元素表示为该模块生成元的整数线性组合。

starts_with_unity()

submodule_from_gens(gens[, hnf, hnf_modulus])

从属于此模块的 ModuleElement 列表生成的子模块。

submodule_from_matrix(B[, denom])

通过矩阵的列所指示的该模块的元素生成子模块,带有可选的分母。

whole_submodule()

返回一个等于此整个模块的子模块。

zero()

返回一个表示零的 ModuleElement

compute_mult_tab

__init__(T)[源代码][源代码]
参数:
TPoly, AlgebraicField

要么 (1) 是 ZZ 上的单项、不可约、单变量多项式,其根是幂基的生成元,要么 (2) 是一个 AlgebraicField,其原始元素是幂基的生成元。

element_from_ANP(a)[源代码][源代码]

将一个 ANP 转换为 PowerBasisElement。

element_from_alg_num(a)[源代码][源代码]

将一个 AlgebraicNumber 转换为 PowerBasisElement。

element_from_poly(f)[源代码][源代码]

生成此模块的一个元素,表示 f 在约化模我们定义的最小多项式之后的值。

参数:
f : PolyZZ 上,变量与我们的定义多项式相同。在ZZ上与我们的定义多项式相同变量的多项式。
返回:
PowerBasisElement
represent(elt)[源代码][源代码]

将模块元素表示为该模块生成元的整数线性组合。

class sympy.polys.numberfields.modules.Submodule(parent, matrix, denom=1, mult_tab=None)[源代码][源代码]

另一个模块的子模块。

属性:
QQ_matrix

DomainMatrixQQ 上,等于

系数
denom
矩阵
n

此模块的生成器数量。

number_field

返回相关的 AlgebraicField,如果有的话。

parent

该模块的父模块(如果有)。

方法

__call__(spec[, denom])

生成一个属于此模块的 ModuleElement

add(other[, hnf, hnf_modulus])

将此 Submodule 添加到另一个中。

ancestors([include_self])

返回此模块的祖先模块列表,从基础的 PowerBasis 向下,可选地包括 self

basis_element_pullbacks()

返回此子模块的基元素列表,作为子模块父模块的元素。

basis_elements()

获取作为此模块生成器的 ModuleElement 列表。

discard_before(r)

通过丢弃给定索引 r 之前的所有生成器来生成一个新模块。

element_from_rational(a)

endomorphism_ring()

形成此模块的 EndomorphismRing

is_compat_col(col)

判断 col 是否为本模块的合适列向量。

mul(other[, hnf, hnf_modulus])

将这个 Submodule 乘以一个有理数、一个 ModuleElement 或另一个 Submodule

mult_tab()

nearest_common_ancestor(other)

定位此模块与另一个模块的最近共同祖先。

one()

返回一个 ModuleElement 表示单位元,并且属于此模块的第一个祖先(包括自身),该祖先从单位元开始。

power_basis_ancestor()

返回作为此模块祖先的 PowerBasis

reduce_element(elt)

如果子模 $B$ 在方阵、最大秩的 Hermite 标准形式下具有定义矩阵 $W$,那么,给定父模 $A$ 中的元素 $x$,我们生成一个元素 $y in A$,使得 $x - y in B$,并且 $y$ 的第 $i$ 个坐标满足 $0 leq y_i < w_{i,i}$。

reduced()

生成此子模块的简化版本。

represent(elt)

将模块元素表示为该模块生成元的整数线性组合。

starts_with_unity()

submodule_from_gens(gens[, hnf, hnf_modulus])

从属于此模块的 ModuleElement 列表生成的子模块。

submodule_from_matrix(B[, denom])

通过矩阵的列所指示的该模块的元素生成子模块,带有可选的分母。

whole_submodule()

返回一个等于此整个模块的子模块。

zero()

返回一个表示零的 ModuleElement

compute_mult_tab

is_compat_submodule

is_power_basis_submodule

is_sq_maxrank_HNF

__init__(
parent,
matrix,
denom=1,
mult_tab=None,
)[源代码][源代码]
参数:
父级 : Module模块

从中派生出此模块的模块。

矩阵 : DomainMatrixZZDomainMatrix 在 ZZ 上

定义此子模块生成器的矩阵,其列是父生成器上的线性组合。

denomint, 可选 (默认=1)

矩阵给出的系数的分母。

mult_tab : dict, None, 可选字典,

如果已知,可以提供此模块的乘法表。

property QQ_matrix

DomainMatrixQQ 上,等于 self.matrix / self.denom,并保证是密集的。

返回:
DomainMatrixQQ

示例

>>> from sympy.polys import Poly, cyclotomic_poly, ZZ
>>> from sympy.abc import x
>>> from sympy.polys.matrices import DomainMatrix
>>> from sympy.polys.numberfields.modules import PowerBasis
>>> T = Poly(cyclotomic_poly(5, x))
>>> A = PowerBasis(T)
>>> B = A.submodule_from_matrix(3*DomainMatrix.eye(4, ZZ), denom=6)
>>> C = A.submodule_from_matrix(DomainMatrix.eye(4, ZZ), denom=2)
>>> print(B.QQ_matrix == C.QQ_matrix)
True
add(other, hnf=True, hnf_modulus=None)[源代码][源代码]

将此 Submodule 添加到另一个中。

参数:
其他 : 子模块子模块
hnf布尔值,可选(默认=True)

如果 True ,将组合模块的矩阵简化为它的 Hermite 正规形式。

hnf_modulus : ZZ, None, 可选ZZ, 无, 可选

如果提供了一个正整数,将其用作 HNF 约简中的模数。参见 hermite_normal_form()

返回:
Submodule
basis_element_pullbacks()[源代码][源代码]

返回此子模块的基元素列表,作为子模块父模块的元素。

discard_before(r)[源代码][源代码]

通过丢弃给定索引 r 之前的所有生成器来生成一个新模块。

mul(other, hnf=True, hnf_modulus=None)[源代码][源代码]

将这个 Submodule 乘以一个有理数、一个 ModuleElement 或另一个 Submodule

参数:
其他 : int, ZZ, QQ, ModuleElement, Submodule整数
hnf布尔值,可选(默认=True)

如果 True ,将乘积模块的矩阵简化为 Hermite 正规形式。

hnf_modulus : ZZ, None, 可选ZZ, 无, 可选

如果提供了一个正整数,将其用作 HNF 约简中的模数。参见 hermite_normal_form()

返回:
Submodule
reduce_element(elt)[源代码][源代码]

如果子模 \(B\) 在方阵、最大秩的 Hermite 标准形式下具有定义矩阵 \(W\),那么,给定父模 \(A\) 中的一个元素 \(x\),我们生成一个元素 \(y \in A\),使得 \(x - y \in B\),并且 \(y\) 的第 \(i\) 个坐标满足 \(0 \leq y_i < w_{i,i}\)。这个代表 \(y\) 是唯一的,意思是说,陪集 \(x + B\) 中的每个元素在此过程中都会归约到它。

参数:
elt模块元素

此子模块的父模块的一个元素。

返回:
elt模块元素

此子模块的父模块的一个元素。

Raises:
NotImplementedError

如果给定的 ModuleElement 不属于此子模块的父模块。

StructureError

如果此子模块的定义矩阵不是方阵,最大秩的Hermite标准形式。

参考文献

[Cohen00]

Cohen, H. 计算数论中的高级主题.

示例

>>> from sympy import QQ, Poly, symbols
>>> t = symbols('t')
>>> k = QQ.alg_field_from_poly(Poly(t**3 + t**2 - 2*t + 8))
>>> Zk = k.maximal_order()
>>> A = Zk.parent
>>> B = (A(2) - 3*A(0))*Zk
>>> B.reduce_element(A(2))
[3, 0, 0]
reduced()[源代码][源代码]

生成此子模块的简化版本。

返回:
Submodule
represent(elt)[源代码][源代码]

将模块元素表示为该模块生成元的整数线性组合。

class sympy.polys.numberfields.modules.ModuleElement(module, col, denom=1)[源代码][源代码]

表示 Module 的一个元素。

注意:不应直接构造。请使用 __call__() 方法或 make_mod_elt() 工厂函数代替。

属性:
QQ_col

DomainMatrixQQ 上,等于

系数
n

此元素列的长度。

方法

column([domain])

获取此元素的列副本,可选择转换为域。

equiv(other)

一个 ModuleElement 可以测试为与一个有理数或其他 ModuleElement 等价,如果它们表示相同的代数数。

from_int_list(module, coeffs[, denom])

从整数列表(而不是列向量)创建一个 ModuleElement

is_compat(other)

测试其他是否是具有相同模块的另一个 ModuleElement

over_power_basis()

转换为我们的 PowerBasis 祖先上的 PowerBasisElement

reduced()

生成此 ModuleElement 的简化版本,即分母与所有分子系数的最大公约数为 1 的版本。

reduced_mod_p(p)

生成一个 ModuleElement 的版本,其中所有分子系数都已对 p 取模。

to_ancestor(anc)

转换为属于此元素模块的给定祖先的 ModuleElement

to_parent()

转换为属于此元素模块的父级的 ModuleElement

unify(other)

尝试创建一对兼容的 ModuleElement,一个等同于此,另一个等同于另一个。

__init__(module, col, denom=1)[源代码][源代码]
参数:
模块 : Module模块

此元素所属的模块。

col : DomainMatrixZZDomainMatrix 在 ZZ 上

给出此元素系数分子的列向量。

denomint, 可选 (默认=1)

此元素系数的分母。

__add__(other)[源代码][源代码]

一个 ModuleElement 可以被添加到一个有理数,或者另一个 ModuleElement

__mul__(other)[源代码][源代码]

一个 ModuleElement 可以乘以一个有理数,或者乘以另一个 ModuleElement

__mod__(m)[源代码][源代码]

将这个 ModuleElement 模一个 Submodule

参数:
m整数

如果是一个 Submodule ,则相对于此减少 self 。如果是一个整数或有理数,则相对于我们自己的模块乘以此常数得到的 Submodule 进行减少。

property QQ_col

DomainMatrixQQ 上,等于 self.col / self.denom,并且保证是稠密的。

column(domain=None)[源代码][源代码]

获取此元素的列副本,可选择转换为域。

equiv(other)[源代码][源代码]

一个 ModuleElement 可以测试为与一个有理数或其他 ModuleElement 等价,如果它们表示相同的代数数。

参数:
其他 : int, ZZ, QQ, ModuleElement整数
返回:
布尔
Raises:
统一失败

如果 selfother 没有共享一个共同的 PowerBasis 祖先。

classmethod from_int_list(
module,
coeffs,
denom=1,
)[源代码][源代码]

从整数列表(而不是列向量)创建一个 ModuleElement

is_compat(other)[源代码][源代码]

测试其他是否是具有相同模块的另一个 ModuleElement

property n

此元素列的长度。

over_power_basis()[源代码][源代码]

转换为我们的 PowerBasis 祖先上的 PowerBasisElement

reduced()[源代码][源代码]

生成此 ModuleElement 的简化版本,即分母与所有分子系数的最大公约数为 1 的版本。

reduced_mod_p(p)[源代码][源代码]

生成一个 ModuleElement 的版本,其中所有分子系数都已对 p 取模。

to_ancestor(anc)[源代码][源代码]

转换为属于此元素模块的给定祖先的 ModuleElement

参数:
anc模块
to_parent()[源代码][源代码]

转换为属于此元素模块的父级的 ModuleElement

unify(other)[源代码][源代码]

尝试创建一对兼容的 ModuleElement,一个等同于此,另一个等同于另一个。

返回:
配对 (e1, e2)

每个 ei 是一个 ModuleElement,它们属于同一个 Modulee1 等同于 self,而 e2 等同于 other

Raises:
统一失败

如果 selfother 没有共同的祖先模块。

class sympy.polys.numberfields.modules.PowerBasisElement(module, col, denom=1)[源代码][源代码]

用于 ModuleElement 实例的子类,其模块是 PowerBasis

属性:
QQ_col

DomainMatrixQQ 上,等于

T

访问 PowerBasis 的定义多项式。

系数
generator

返回一个 Symbol ,用于在将此元素表示为多项式时使用。

is_rational

判断此元素是否表示一个有理数。

n

此元素列的长度。

方法

as_expr([x])

self 创建一个基本表达式。

column([domain])

获取此元素的列副本,可选择转换为域。

equiv(other)

一个 ModuleElement 可以测试为与一个有理数或其他 ModuleElement 等价,如果它们表示相同的代数数。

from_int_list(module, coeffs[, denom])

从整数列表(而不是列向量)创建一个 ModuleElement

is_compat(other)

测试其他是否是具有相同模块的另一个 ModuleElement

norm([T])

计算这个数的范数。

numerator([x])

将分子作为多项式从 ZZ 中获取。

over_power_basis()

转换为我们的 PowerBasis 祖先上的 PowerBasisElement

poly([x])

将数字作为 QQ 上的多项式获取。

reduced()

生成此 ModuleElement 的简化版本,即分母与所有分子系数的最大公约数为 1 的版本。

reduced_mod_p(p)

生成一个 ModuleElement 的版本,其中所有分子系数都已对 p 取模。

to_ANP()

转换为等效的 ANP

to_alg_num()

尝试转换为等价的 AlgebraicNumber

to_ancestor(anc)

转换为属于此元素模块的给定祖先的 ModuleElement

to_parent()

转换为属于此元素模块的父级的 ModuleElement

unify(other)

尝试创建一对兼容的 ModuleElement,一个等同于此,另一个等同于另一个。

反向

property T

访问 PowerBasis 的定义多项式。

as_expr(x=None)[源代码][源代码]

self 创建一个基本表达式。

property generator

返回一个 Symbol ,用于在将此元素表示为多项式时使用。

如果我们有一个关联的 AlgebraicField,其原始元素有一个别名符号,我们使用该符号。否则,我们使用定义我们所属的幂基的最小多项式的变量。

property is_rational

判断此元素是否表示一个有理数。

norm(T=None)[源代码][源代码]

计算这个数的范数。

numerator(x=None)[源代码][源代码]

将分子作为多项式从 ZZ 中获取。

poly(x=None)[源代码][源代码]

将数字作为 QQ 上的多项式获取。

to_ANP()[源代码][源代码]

转换为等效的 ANP

to_alg_num()[源代码][源代码]

尝试转换为等价的 AlgebraicNumber

返回:
AlgebraicNumber
Raises:
StructureError

如果这个元素所属的 PowerBasis 没有关联的 AlgebraicField

sympy.polys.numberfields.modules.make_mod_elt(module, col, denom=1)[源代码][源代码]

构建 ModuleElement 的工厂函数,但如果模块是 PowerBasis,则确保它是 PowerBasisElement

class sympy.polys.numberfields.modules.ModuleHomomorphism(domain, codomain, mapping)[源代码][源代码]

从一个模块到另一个模块的同态。

方法

kernel([modulus])

计算一个表示此同态核的子模块。

matrix([modulus])

计算这个同态的矩阵。

__init__(
domain,
codomain,
mapping,
)[源代码][源代码]
参数:
: Module模块

映射的域。

值域 : Module模块

映射的陪域。

映射可调用

接受任意可调用对象,但应选择以表示实际的模块同态。特别是,应接受 domain 的元素并返回 codomain 的元素。

示例

>>> from sympy import Poly, cyclotomic_poly
>>> from sympy.polys.numberfields.modules import PowerBasis, ModuleHomomorphism
>>> T = Poly(cyclotomic_poly(5))
>>> A = PowerBasis(T)
>>> B = A.submodule_from_gens([2*A(j) for j in range(4)])
>>> phi = ModuleHomomorphism(A, B, lambda x: 6*x)
>>> print(phi.matrix())  
DomainMatrix([[3, 0, 0, 0], [0, 3, 0, 0], [0, 0, 3, 0], [0, 0, 0, 3]], (4, 4), ZZ)
kernel(modulus=None)[源代码][源代码]

计算一个表示此同态核的子模块。

参数:
模数int, 可选

一个正素数 \(p\),如果核应该在模 \(p\) 下计算。

返回:
Submodule

这个子模块的生成器跨越了这个同态在 ZZ 上的核,或者如果给出了模数,则在 GF(p) 上。

matrix(modulus=None)[源代码][源代码]

计算这个同态的矩阵。

参数:
模数int, 可选

一个正素数 \(p\),如果矩阵应该被模 \(p\) 化简。

返回:
DomainMatrix

矩阵在 ZZ 上,或者如果给定了模数,则在 GF(p) 上。

class sympy.polys.numberfields.modules.ModuleEndomorphism(domain, mapping)[源代码][源代码]

从一个模块到自身的同态。

方法

kernel([modulus])

计算一个表示此同态核的子模块。

matrix([modulus])

计算这个同态的矩阵。

__init__(domain, mapping)[源代码][源代码]
参数:
: Module模块

映射的公共定义域和陪域。

映射可调用

接受任意可调用对象,但应选择能够代表实际模块自同态的函数。特别是,应接受并返回 domain 的元素。

class sympy.polys.numberfields.modules.InnerEndomorphism(domain, multiplier)[源代码][源代码]

一个模块上的内自同态,即对应于固定元素乘法的自同态。

方法

kernel([modulus])

计算一个表示此同态核的子模块。

matrix([modulus])

计算这个同态的矩阵。

__init__(domain, multiplier)[源代码][源代码]
参数:
: Module模块

自同态的定义域和陪域。

乘数 : ModuleElement模块元素

定义映射的元素 \(a\)\(x \mapsto a x\)

class sympy.polys.numberfields.modules.EndomorphismRing(domain)[源代码][源代码]

模上的自同态环。

方法

inner_endomorphism(multiplier)

构成属于这个自同态环的内自同态。

represent(element)

将这个自同态环的一个元素表示为一个单列向量。

__init__(domain)[源代码][源代码]
参数:
: Module模块

自同态的定义域和陪域。

inner_endomorphism(multiplier)[源代码][源代码]

构成属于这个自同态环的内自同态。

参数:
乘数 : ModuleElement模块元素

元素 \(a\) 定义了内自同态 \(x \mapsto a x\)

返回:
InnerEndomorphism
represent(element)[源代码][源代码]

将这个自同态环的一个元素表示为一个单列向量。

参数:
元素 : 属于此环的 ModuleEndomorphism属于此环的模块自同态。
返回:
DomainMatrix

列向量等于表示给定 元素 作为映射的矩阵的所有列的垂直堆叠。

示例

请注意,在这些示例中我们打印矩阵的转置,以便更容易检查它们的列。

>>> from sympy import Poly, cyclotomic_poly
>>> from sympy.polys.numberfields.modules import PowerBasis
>>> from sympy.polys.numberfields.modules import ModuleHomomorphism
>>> T = Poly(cyclotomic_poly(5))
>>> M = PowerBasis(T)
>>> E = M.endomorphism_ring()

\(\zeta\) 为单位根的五次原根,是我们域的生成元,并考虑由 \(\zeta\) 诱导的环上整数的内自同态 \(\tau\)

>>> zeta = M(1)
>>> tau = E.inner_endomorphism(zeta)
>>> tau.matrix().transpose()  
DomainMatrix(
    [[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], [-1, -1, -1, -1]],
    (4, 4), ZZ)

\(\tau\) 的矩阵表示符合预期。第一列显示乘以 \(\zeta\)\(1\) 变为 \(\zeta\),第二列显示它将 \(\zeta\) 变为 \(\zeta^2\),依此类推。

自同态环 Erepresent 方法将这些内容堆叠成一个单独的列:

>>> E.represent(tau).transpose()  
DomainMatrix(
    [[0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, -1, -1, -1]],
    (1, 16), ZZ)

当我们想要考虑一个同态 \(\varphi\)E 为陪域时,这很有用:

>>> phi = ModuleHomomorphism(M, E, lambda x: E.inner_endomorphism(x))

我们想要计算这样一个同态的矩阵:

>>> phi.matrix().transpose()  
DomainMatrix(
    [[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, -1, -1, -1],
    [0, 0, 1, 0, 0, 0, 0, 1, -1, -1, -1, -1, 1, 0, 0, 0],
    [0, 0, 0, 1, -1, -1, -1, -1, 1, 0, 0, 0, 0, 1, 0, 0]],
    (4, 16), ZZ)

注意,\(\tau\) 的堆叠矩阵在此示例中作为第二列出现。这是因为 \(\zeta\)M 的第二个基元素,且 \(\varphi(\zeta) = \tau\)

sympy.polys.numberfields.modules.find_min_poly(alpha, domain, x=None, powers=None)[源代码][源代码]

找到一个最低次数的多项式(不一定是不可约的),满足有限生成且具有单位元的环中的一个元素。

参数:
alpha模块元素

要找到其最小多项式的元素,其模块具有乘法并从单位元开始。

: Domain领域

多项式所需的定义域。

x : Symbol, 可选符号, 可选

多项式所需的变量。

权力列表,可选

如果需要,传递一个空列表。在计算过程中,从零次到最小多项式次数的 alpha 的幂(作为 ModuleElement 实例)将被记录在这里。

返回:
Poly, None

alpha 的最小多项式,如果在所需域上找不到多项式,则为 None

Raises:
MissingUnityError

如果alpha所属的模块不以unity开头。

ClosureFailure

如果alpha所属的模块在乘法下不封闭。

示例

对于第 \(n\) 个分圆域,\(n\) 是一个奇素数,考虑其根为长度 \((n-1)/2\) 的两个周期的二次方程。高斯的文章 356 告诉我们,根据 \(n\) 是 1 还是 3 mod 4,我们应分别得到 \(x^2 + x - (n-1)/4\)\(x^2 + x + (n+1)/4\)

>>> from sympy import Poly, cyclotomic_poly, primitive_root, QQ
>>> from sympy.abc import x
>>> from sympy.polys.numberfields.modules import PowerBasis, find_min_poly
>>> n = 13
>>> g = primitive_root(n)
>>> C = PowerBasis(Poly(cyclotomic_poly(n, x)))
>>> ee = [g**(2*k+1) % n for k in range((n-1)//2)]
>>> eta = sum(C(e) for e in ee)
>>> print(find_min_poly(eta, QQ, x=x).as_expr())
x**2 + x - 3
>>> n = 19
>>> g = primitive_root(n)
>>> C = PowerBasis(Poly(cyclotomic_poly(n, x)))
>>> ee = [g**(2*k+2) % n for k in range((n-1)//2)]
>>> eta = sum(C(e) for e in ee)
>>> print(find_min_poly(eta, QQ, x=x).as_expr())
x**2 + x + 5

实用工具

sympy.polys.numberfields.utilities.is_rat(c)[源代码][源代码]

测试一个参数是否是可接受类型,以便用作有理数。

参见

is_int
sympy.polys.numberfields.utilities.is_int(c)[源代码][源代码]

测试一个参数是否是可接受类型,以便用作整数。

参见

is_rat
sympy.polys.numberfields.utilities.get_num_denom(c)[源代码][源代码]

给定任何 is_rat()True 的参数,返回该数字的分子和分母。

参见

is_rat
sympy.polys.numberfields.utilities.extract_fundamental_discriminant(a)[源代码][源代码]

从一个整数 a 中提取一个基本判别式。

参数:
a: int, 必须是 0 或 1 mod 4
返回:
字典 (D, F) 对。
Raises:
ValueError

如果 a 不是 0 或 1 mod 4。

参考文献

[1]

Cohen, H. 计算代数数论课程. (参见命题 5.1.3)

示例

>>> from sympy.polys.numberfields.utilities import extract_fundamental_discriminant
>>> print(extract_fundamental_discriminant(-432))
({3: 1, -1: 1}, {2: 2, 3: 1})

比较如下:

>>> from sympy import factorint
>>> print(factorint(-432))
{2: 4, 3: 3, -1: 1}
class sympy.polys.numberfields.utilities.AlgIntPowers(T, modulus=None)[源代码][源代码]

计算代数整数的幂。

方法

compute_up_through

获取

红色

参考文献

[1]

Cohen, H. 计算代数数论课程.

示例

>>> from sympy import Poly, cyclotomic_poly
>>> from sympy.polys.numberfields.utilities import AlgIntPowers
>>> T = Poly(cyclotomic_poly(5))
>>> zeta_pow = AlgIntPowers(T)
>>> print(zeta_pow[0])
[1, 0, 0, 0]
>>> print(zeta_pow[1])
[0, 1, 0, 0]
>>> print(zeta_pow[4])  
[-1, -1, -1, -1]
>>> print(zeta_pow[24])  
[-1, -1, -1, -1]
__init__(T, modulus=None)[源代码][源代码]
参数:
T

ZZ 上定义代数整数的不可约多项式。

模数int, None, 可选

如果不是 None ,所有表示都将相对于此进行简化。

生成用于多项式搜索的系数。

参数:
m整数

系数列表的长度。

R整数

系数初始最大绝对值(随着搜索进行会增加)。

返回:
生成器

无限生成系数列表的生成器。

示例

>>> from sympy.polys.numberfields.utilities import coeff_search
>>> cs = coeff_search(2, 1)
>>> C = [next(cs) for i in range(13)]
>>> print(C)
[[1, 1], [1, 0], [1, -1], [0, 1], [2, 2], [2, 1], [2, 0], [2, -1], [2, -2],
 [1, 2], [1, -2], [0, 2], [3, 3]]
sympy.polys.numberfields.utilities.supplement_a_subspace(M)[源代码][源代码]

将子空间的基扩展为整个空间的基。

参数:
MDomainMatrix

这些列提供了子空间的基。

返回:
DomainMatrix

这个矩阵是可逆的,并且它的前 \(r\) 列等于 M

Raises:
DMRankError

如果 M 不是最大秩。

参考文献

[1]

Cohen, H. 计算代数数论课程 (参见第2.3.2节.)

示例

注意:该函数以列为单位工作,因此在这些示例中我们打印矩阵的转置,以便更容易检查列。

>>> from sympy.polys.matrices import DM
>>> from sympy import QQ, FF
>>> from sympy.polys.numberfields.utilities import supplement_a_subspace
>>> M = DM([[1, 7, 0], [2, 3, 4]], QQ).transpose()
>>> print(supplement_a_subspace(M).to_Matrix().transpose())
Matrix([[1, 7, 0], [2, 3, 4], [1, 0, 0]])
>>> M2 = M.convert_to(FF(7))
>>> print(M2.to_Matrix().transpose())
Matrix([[1, 0, 0], [2, 3, -3]])
>>> print(supplement_a_subspace(M2).to_Matrix().transpose())
Matrix([[1, 0, 0], [2, 3, -3], [0, 1, 0]])
sympy.polys.numberfields.utilities.isolate(alg, eps=None, fast=False)[源代码][源代码]

为实代数数找到一个合理的隔离区间。

参数:
algstr, int, Expr

要隔离的代数数。必须是一个实数,才能使用这个特定的函数。不过,也可以参考 Poly.intervals(),当你传递 all=True 时,它会隔离复数根。

eps : QQ 的正元素, None, 可选 (默认=None)积极的元素

传递给 Poly.refine_root() 的精度

快速布尔值,可选(默认=False)

说明是否应使用快速细化程序。(将传递给 Poly.refine_root()。)

返回:
一对有理数定义了一个给定数的隔离区间
代数数。

示例

>>> from sympy import isolate, sqrt, Rational
>>> print(isolate(sqrt(2)))  
(1, 2)
>>> print(isolate(sqrt(2), eps=Rational(1, 100)))
(24/17, 17/12)