数域
引言
像代数数论中许多其他计算一样,有理素数的分裂只能用有理方法处理。如果考虑用自动计算设备进行计算,这一事实非常重要。只需知道不可约多项式(f(x)),其零点生成所讨论的域即可。
—Olga Taussky,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),计算:
-
(\mathbb{Z}_K)的一个整数基底
-
(\mathbb{Z}_K)中有理素数的分解
-
对于理想和元素的(\mathfrak{p})-adic 赋值
-
(K)的 Galois 封闭的 Galois 群
-
(K)的一组基本单位
-
规则(R(K))
-
类数
-
类群(Cl(K))的结构
-
决定一个给定理想是否为主理想,如果是,则计算一个生成元。
作为基础,并支持我们定义和处理数域和代数数的基本能力,我们也根据[Cohen93],第 4.5 节,设置以下问题。
-
给定一个代数数,可以通过根式和有理运算表达,甚至可以作为超越函数的特殊值,确定它在(\mathbb{Q})上的最小多项式。
-
子域问题:通过它们的生成元(\alpha)和(\beta)的最小多项式,给定两个数域(\mathbb{Q}(\alpha)),(\mathbb{Q}(\beta)),决定一个数域是否同构于另一个数域的子域,并展示嵌入。
-
域成员问题:给定两个代数数(\alpha),(\beta),决定(\alpha \in \mathbb{Q}(\beta))是否成立,如果成立,则写成(\alpha = f(\beta)),其中(f(x) \in \mathbb{Q}[x])。
-
原初元问题:给定几个代数数(\alpha_1, \ldots, \alpha_m),计算一个单一的代数数(\theta),使得(\mathbb{Q}(\alpha_1, \ldots, \alpha_m) = \mathbb{Q}(\theta))。
目前,SymPy 仅支持上述任务的子集,如果您有兴趣扩展支持,请贡献!提供所有剩余问题解决方案(以及已解决的问题)的出色来源是 [Cohen93]。
在写作时,上述问题的现有解决方案可以在以下位置找到:
任务 | 实现 |
---|
|
- 整数基础
round_two() |
---|
|
- 素数分解
prime_decomp() |
---|
|
- (\mathfrak{p})-递值
prime_valuation() |
---|
|
- Galois 群
galois_group() |
---|
|
- 寻找最小多项式
minimal_polynomial() |
---|
|
- 子领域
field_isomorphism() |
---|
|
- 领域成员
to_number_field() |
---|
|
- 原始元素
primitive_element() |
---|
解决主要问题
整数基础
sympy.polys.numberfields.basis.round_two(T, radicals=None)
Zassenhaus 的“Round 2” 算法。
参数:
T : Poly
, AlgebraicField
要么是在 ZZ 或 QQ 上的不可约多项式,定义数域,或者是代表数域本身的
AlgebraicField
。
根式 : dict, optional
这是任何 (p)-根式(如果计算的话)通过引用返回的一种方式。如果需要,传递一个空字典。如果算法达到计算环 (Z_K) 的 nilradical mod (p) 的点,则该字典中将以
p
为键存储此理想的 (\mathbb{F}_p)-基础。这对于其他算法(如素数分解)可能很有用。
返回:
对 (ZK, dK)
,其中:
ZK
是表示最大秩的Submodule
。
dK
是字段 (K = \mathbb{Q}[x]/(T(x))) 的判别式。
说明
在 ZZ 或 QQ 上的不可约多项式T上执行 Zassenhaus 的“Round 2”算法。这计算了一个整数基和字段(K = \mathbb{Q}[x]/(T(x)))的判别式。
或者,您可以传递一个AlgebraicField
实例,替代多项式T,在这种情况下算法应用于该字段的原始元的最小多项式。
通常不必直接调用此函数,因为可以访问maximal_order()
、integral_basis()
和discriminant()
方法的AlgebraicField
。
示例
通过 AlgebraicField 进行操作:
>>> 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]]}
另见
AlgebraicField.maximal_order
,AlgebraicField.integral_basis
,AlgebraicField.discriminant
参考文献
[R802]
Cohen, H. 计算代数数论课程.
质数分解
sympy.polys.numberfields.primes.prime_decomp(p, T=None, ZK=None, dK=None, radical=None)
计算在一个数域中有理质数p的分解。
参数:
p:int
想要分解的有理质数。
T:Poly
,可选
定义数域(K)中的单一不可约多项式。注意:T或ZK至少要提供一个。
ZK:Submodule
,可选
如果已知,(K)的最大序。注意:T或ZK至少要提供一个。
dK:int,可选
如果已知,(K)的判别式。
radical:Submodule
,可选
如果已知,(K)的整数中的模p的零根式。
返回:
PrimeIdeal
实例列表。
解释
通常应通过 AlgebraicField
的 primes_above()
方法访问它。
示例
>>> 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 ]]
参考文献
[R803]
Cohen, H. 计算代数数论课程. (见算法 6.2.9.)
class sympy.polys.numberfields.primes.PrimeIdeal(ZK, p, alpha, f, e=None)
一个代数整数环中的素理想。
__init__(ZK, p, alpha, f, e=None)
参数:
ZK:Submodule
此理想所在的最大阶。
p:int
此理想除以的有理素数。
alpha:PowerBasisElement
使得理想等于
p*ZK + alpha*ZK
。
f:int
惯性度。
e:int,None
,可选
如果已知分歧指数。 如果为
None
,我们将在此计算它。
__add__(other)
转换为 Submodule
并添加到另一个 Submodule
中。
另请参阅
as_submodule
__mul__(other)
转换为 Submodule
并乘以另一个 Submodule
或有理数。
另请参阅
as_submodule
as_submodule()
将此素理想表示为 Submodule
。
返回:
Submodule
将等于
self.p * self.ZK + self.alpha * self.ZK
。
解释
PrimeIdeal
类用于捆绑关于素理想的信息,如其惯性度、分歧指数和双生成器表示,以及提供像 valuation()
和 test_factor()
这样有用的方法。
然而,为了能够与其他理想或有理数相加和相乘,首先必须将其转换为一个支持这些操作的 Submodule
类。
在许多情况下,用户不需要刻意执行这种转换,因为算术运算符方法__add__()
和__mul__()
会自动执行此操作。
将一个PrimeIdeal
提升到非负整数次方也是支持的。
示例
>>> 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
。在下一个等式中,我们回顾到添加理想值会产生它们的最大公约数。这次,我们需要在右边有一个明确的转换为Submodule
:
>>> print(P0 + 7*P0.ZK == P0.as_submodule())
True
另见
__add__
, __mul__
property is_inert
说清楚我们在整数环中保留的有理素数是否惰性,即保持原样。
reduce_ANP(a)
将一个ANP
减少到此素理想的“小代表”。
参数:
elt:ANP
要减少的元素。
返回:
ANP
减少后的元素。
另见
reduce_element
, reduce_alg_num
, Submodule.reduce_element
reduce_alg_num(a)
将一个AlgebraicNumber
减少到此素理想的“小代表”。
参数:
elt:AlgebraicNumber
要减少的元素。
返回:
AlgebraicNumber
减少后的元素。
另见
reduce_element
,reduce_ANP
,Submodule.reduce_element
reduce_element(elt)
将PowerBasisElement
减少到模这个素数理想的“小代表”。
参数:
elt:PowerBasisElement
要减少的元素。
返回:
PowerBasisElement
被减少的元素。
参见
reduce_ANP
,reduce_alg_num
,Submodule.reduce_element
repr(field_gen=None, just_gens=False)
打印这个素数理想的表示。
参数:
field_gen:Symbol
,None
,可选(默认为 None
)
用于场的生成器的符号。这将出现在我们对
self.alpha
的表示中。如果为None
,我们使用self.ZK
的定义多项式的变量。
just_gens:布尔值,可选(默认为 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()
计算这个素数理想的一个测试因子。
解释
为这个素数理想写下(\mathfrak{p}),(p)是它分解的有理素数。然后,为了计算(\mathfrak{p})-递减估值,有一个数(\beta \in \mathbb{Z}_K),使得(p/\mathfrak{p} = p \mathbb{Z}_K + \beta \mathbb{Z}_K)非常有用。
本质上,这与库默(Kummer)1847 年的论文(Ueber die Zerlegung…, Crelle vol. 35)中的数\Psi(或“试剂”)相同,其中发明了理想除法。
valuation(I)
计算整数理想 I 在这个素数理想上的(\mathfrak{p})-递减估值。
参数:
I:Submodule
参见
prime_valuation
p-递减估值
sympy.polys.numberfields.primes.prime_valuation(I, P)
计算整数理想 I 的P-递减估值。
参数:
I : Submodule
欲求其价值的整数理想。
P : PrimeIdeal
计算价值的质数。
返回:
int
示例
>>> 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
亦见:
PrimeIdeal.valuation
参考
[R804]
Cohen, H. A Course in Computational Algebraic Number Theory. (见算法 4.8.17。)
Galois 群
sympy.polys.numberfields.galoisgroups.galois_group(f, *gens, by_name=False, max_tries=30, randomize=False, **args)
计算多项式 f 的 Galois 群,直到 6 次。
参数:
f : 表达式
不可约多项式在 ZZ 或 QQ 上,其 Galois 群需确定。
gens : 符号的可选列表
将 f 转换为 Poly,并传递给
poly_from_expr()
函数。
by_name : bool,默认为 False
如果
True
,则以名称返回 Galois 群。否则将其作为PermutationGroup
返回。
max_tries : int,默认为 30
在生成 Tschirnhausen 变换的步骤中最多尝试这么多次。
randomize : bool,默认为 False
如果为
True
,则在生成 Tschirnhausen 变换时使用随机系数。否则,按固定顺序尝试变换。这两种方法都从小系数和次数开始,并向上工作。
args : 可选
将 f 转换为 Poly,并传递给
poly_from_expr()
函数。
返回:
对 (G, alt)
进行配对
第一个元素
G
表示 Galois 群。它是sympy.combinatorics.galois.S1TransitiveSubgroups
和sympy.combinatorics.galois.S2TransitiveSubgroups
等枚举类的实例,如果by_name
是True
,则返回其名称;如果是False
,则返回一个PermutationGroup
。第二个元素是一个布尔值,表明群是否包含于交错群 (A_n) ((n) 是 T 的次数)。
引发:
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.S1TransitiveSubgroups
,sympy.combinatorics.galois.S2TransitiveSubgroups
等的值。
另请参见
Poly.galois_group
查找最小多项式
sympy.polys.numberfields.minpoly.minimal_polynomial(ex, x=None, compose=True, polys=False, domain=None)
计算代数元素的最小多项式。
参数:
ex : 表达式
要计算其最小多项式的元素或表达式。
x : 符号,可选
最小多项式的自变量
compose : 布尔值,可选(默认值=True)
用于计算最小多项式的方法。如果
compose=True
(默认值),则使用_minpoly_compose
,如果compose=False
,则使用格罗本基。
polys : 布尔值, 可选(默认值=False)
如果
True
返回Poly
对象,否则返回Expr
对象。
domain : 域,可选
基域
注意
默认情况下 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 : Expr
任何表示代数数的表达式。
b : Expr
任何表示代数数的表达式。
fast : 布尔值,可选(默认为 True)
如果为
True
,首先尝试一种可能更快的计算同构的方法,如果失败,则退回到较慢的方法。如果为False
,则直接使用保证返回结果的较慢方法。
返回:
有理数列表,或者为 None
如果 (\mathbb{Q}(a)) 不同构于 (\mathbb{Q}(b)) 的某个子域,则返回
None
。否则,返回一个有序列表,表示 (\mathbb{Q}(b)) 中元素,其中 (a) 可能被映射到,以定义单同态,即从 (\mathbb{Q}(a)) 到 (\mathbb{Q}(b)) 的同构。列表的元素是 (b) 的降幂的系数。
解释
此函数寻找从 (\mathbb{Q}(a)) 到 (\mathbb{Q}(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)
找到由几个生成元给出的数域的单一生成元。
参数:
extension : Expr
的列表
每个表达式必须表示代数数 (\alpha_i)。
x : Symbol
,可选(默认为 None)
所需出现在原始元素 (\theta) 的计算最小多项式中的符号。如果为
None
,则使用虚拟符号。
ex : 布尔值,可选(默认为 False)
当且仅当为
True
时,计算每个 (\alpha_i) 的表示,作为 (\theta) 的幂次在 (\mathbb{Q}) 上的线性组合。
polys : 布尔值,可选(默认为 False)
如果为
True
,将最小多项式作为Poly
返回。否则将其作为Expr
返回。
返回:
一对 (f, coeffs) 或三元组 (f, coeffs, reps),其中:
f
是原始元素的最小多项式。coeffs
给出原始元素作为给定生成元的线性组合。如果传递了ex=True
,则reps
存在,并且是有理数列表的列表。每个列表给出原始生成元的降幂系数,以恢复其中之一。
解释
基本问题是:给定几个代数数 (\alpha_1, \alpha_2, \ldots, \alpha_n),找到一个单一的代数数 (\theta),使得 (\mathbb{Q}(\alpha_1, \alpha_2, \ldots, \alpha_n) = \mathbb{Q}(\theta))。
此函数实际上保证 (\theta) 将是 (\alpha_i) 的线性组合,其系数为非负整数。
此外,如果需要,此函数将告诉您如何将每个 (\alpha_i) 表示为 (\theta) 的 (\mathbb{Q}) 线性组合的幂次元素。
Examples
>>> 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}) 作为 (\mathbb{Q}) 线性组合的幂次元素 (\sqrt{2} + \sqrt{3}) 的恢复方式。
>>> 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)
在生成的域中表达一个代数数。
Parameters:
extension : Expr
或者 Expr
的列表
要么是要在另一个域中表达的代数数,要么是代数数的列表,其中一个原始元素将在另一个域中表达。
theta : Expr
, None, optional (default=None)
如果代表代数数的
Expr
,则其行为如 Explanation 中所述。如果为None
,则此函数简化为对extension
调用primitive_element()
并将计算得到的原始元素转换为AlgebraicNumber
。
gen : Symbol
, None, optional (default=None)
如果提供,则将用作返回的
AlgebraicNumber
的最小多项式的生成符号。
alias : str, Symbol
, None, optional (default=None)
如果提供,则将用作返回的
AlgebraicNumber
的别名符号。
Returns:
AlgebraicNumber
属于 (\mathbb{Q}(\theta)) 并等于 (\eta)。
Raises:
IsomorphismFailed
如果 (\eta \not\in \mathbb{Q}(\theta))。
Explanation
给定两个代数数 (\eta, \theta),此函数要么将 (\eta) 表示为 (\mathbb{Q}(\theta)) 中的元素,要么在 (\eta \not\in \mathbb{Q}(\theta)) 时引发异常。
此函数本质上只是一种方便的工具,利用 field_isomorphism()
(我们解决的子域问题)来解决这个域成员问题。
作为额外方便,此函数允许您传递代数数列 (\alpha_1, \alpha_2, \ldots, \alpha_n) 而不是 (\eta)。它会使用 primitive_element()
对 (\alpha_i) 列表计算 (\eta),作为原始元问题的解。
示例
>>> 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()
显示如何用 (\theta) 的降幂写出 (\eta) 的 (\mathbb{Q})-线性组合。
另见
field_isomorphism
,primitive_element
内部
代数数域
在 SymPy 中,代数数域由 AlgebraicField
类表示,这是 多项式域系统 的一部分。
表示代数数
表示代数数有多种不同的方式,对于不同的计算任务可能有不同的首选形式。参见 [Cohen93],第 4.2 节。
作为数域元素
在 SymPy 中,有一个区分数字和表达式类别的区别,分别在 sympy.core.numbers
模块中定义,在 polys
模块中定义域和域元素。这在 这里 有更详细的解释。
当涉及代数数时,sympy.core.numbers
模块提供 AlgebraicNumber
类,而 polys
模块提供 ANP
类。这是属于 AlgebraicField
域的域元素类型。
作为有限生成模块的元素
在计算代数数论中,有限生成的(\mathbb{Z})-模块具有至关重要的作用。例如,每个秩和每个理想都是这样一个模块。
特别地,在数域中,最大秩的序数——或整数环——是一个有限生成的(\mathbb{Z})-模块,其生成器形成该域的整基。
允许我们表示这种模块及其元素的类,都在modules
模块中提供。在这里,ModuleElement
类提供了另一种表示代数数的方式。
有限生成模块
数域中的模块。
这里定义的类允许我们处理有限生成的自由模块,其生成器是代数数。
还有一个名为Module
的抽象基类,它有两个具体子类,PowerBasis
和Submodule
。
每个模块由其基础或生成器集合定义:
-
对于
PowerBasis
,生成器是代数整数(\theta)的前(n)个幂(从零开始),其次数为(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
的一个祖先,如果S
是一个Submodule
,那么它的祖先是S.parent
、S.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)
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})-线性组合,即其自身的生成元。只有当子模块实际上在乘法下是封闭的时,这个过程才会成功。
模同态
许多重要的数论算法需要计算一个或多个模同态的核。因此,我们有几个轻量级类,ModuleHomomorphism
,ModuleEndomorphism
,InnerEndomorphism
和 EndomorphismRing
,它们提供了支持这些操作所需的最小机制。
类参考
class sympy.polys.numberfields.modules.Module
通用的有限生成模块。
这是一个抽象基类,不应直接实例化。两个具体的子类是PowerBasis
和 Submodule
。
每个Submodule
都来源于另一个模块,通过其parent
属性引用。如果S
是一个子模块,则我们称S.parent
,S.parent.parent
等为S
的“祖先”。因此,每个Module
要么是一个PowerBasis
,要么是一个Submodule
,其中某个祖先是PowerBasis
。
__call__(spec, denom=1)
生成属于此模块的ModuleElement
。
参数:
spec : DomainMatrix
, int
指定
ModuleElement
的系数的分子。可以是整数向量,范围为 ZZ,其长度必须等于此模块生成器的数量(n),或者是整数j
,(0 \leq j < n),表示单位矩阵(I_n)的第(n \times n)列的简写。
denom:整数,可选(默认=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:整数,ZZ,QQ
返回:
ModuleElement
解释
返回的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()
获取此模块的乘法表(如果在乘法下封闭)。
返回:
字典的字典的列表
抛出:
ClosureFailure
如果模块在乘法下不封闭。
解释
计算表示乘法表上三角部分的字典M
的字典的列表。
换句话说,如果0 <= i <= j < self.n
,那么M[i][j]
是系数列表c
,使得g[i] * g[j] == sum(c[k]*g[k], k in range(self.n))
,其中g
是此模块生成器的列表。
如果j < i
,则M[i][j]
未定义。
示例
>>> 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
解释
可以在Poly
(f)上或者在AlgebraicField
(K)上构造PowerBasis
。在后一种情况下,PowerBasis
及其所有后代模块将返回(K)作为其.number_field
属性,而在前一种情况下,它们将全部返回None
。
one()
返回表示单位的ModuleElement
,并属于该模块的第一个祖先(包括它自身),该祖先以单位开始。
property parent
如果有的话,返回此模块的父模块。
返回:
Module
,None
解释
对于Submodule
,这是其parent
属性;对于PowerBasis
,这是None
。
另请参见
Module
power_basis_ancestor()
返回这个模块的祖先的PowerBasis
。
另请参见
Module
represent(elt)
将模块元素表示为该模块生成器的整数线性组合。
参数:
elt:ModuleElement
要表示的模块元素。 必须属于此模块的某个祖先模块(包括此模块本身)。
返回:
DomainMatrix
关于 ZZ
这将是一个列向量,表示该模块生成器的线性组合的系数,其等于给定的元素。
引发:
ClosureFailure
如果给定的元素不能表示为此模块上的 ZZ 线性组合。
解释
在我们的系统中,“表示”始终意味着将ModuleElement
写成当前Module
的生成元的 ZZ 线性组合。此外,传入的ModuleElement
必须属于当前Module
的祖先(或当前Module
本身)。
最常见的应用是在Submodule
中表示ModuleElement
。例如,这涉及计算乘法表。
另一方面,在PowerBasis
中表示是一个特例,这种情况通常不会在实践中出现,除非例如在ModuleEndomorphism
在PowerBasis
上使用时。
在这种情况下,(1)传入的ModuleElement
必须属于PowerBasis
本身(因为后者没有适当的祖先),(2)它“可表示”当且仅当它属于(\mathbb{Z}[\theta])(尽管通常PowerBasisElement
可以表示(\mathbb{Q}(\theta))中的任何元素,即任何代数数)。
示例
>>> 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
另请参阅
Submodule.represent
,PowerBasis.represent
starts_with_unity()
判断模块的第一个生成元是否等于单位元。
submodule_from_gens(gens, hnf=True, hnf_modulus=None)
用属于本模块的 ModuleElement
列表生成的子模。
参数:
gens : 属于本模块的 ModuleElement
列表。
hnf : boolean, optional (默认=True)
如果为 True,则在形成
Submodule
前将矩阵缩减为 Hermite 正规形式。
hnf_modulus : int, None, optional (默认=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
submodule_from_matrix(B, denom=1)
用矩阵的列指示的本模块的元素生成的子模,带有可选的分母。
参数:
B : ZZ
上的 DomainMatrix
。
每一列都给出了子模的一个生成元的系数的分子。因此,B 的行数必须等于当前模的生成元的数量。
denom : int, optional (默认=1)
所有生成元的公共分母的最小公倍数。
返回:
Submodule
引发:
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
另请参阅
submodule_from_gens
whole_submodule()
返回一个等于整个模的子模。
说明
当您有一个 PowerBasis
并希望将其转换为 Submodule
(以使用后者属于的方法)时,这将非常有用。
zero()
返回一个表示零的 ModuleElement
。
class sympy.polys.numberfields.modules.PowerBasis(T)
由代数整数的幂生成的模。
__init__(T)
参数:
T : Poly
, AlgebraicField
(1)整数环上的首一、不可约、一元多项式,其根是幂基的生成元,或者(2)一个
代数域
,其原始元素是幂基的生成元。
element_from_ANP(a)
将 ANP 转换为幂基元素。
element_from_alg_num(a)
将代数数转换为幂基元素。
element_from_poly(f)
在我们定义的最小多项式模除后,产生此模块的元素,表示 f。
参数:
f : 多项式
over ZZ,与我们定义的多项式相同的变量。
返回:
幂基元素
represent(elt)
将模块元素表示为该模块生成器上的整数线性组合。
另请参阅
Module.represent
,Submodule.represent
class sympy.polys.numberfields.modules.Submodule(parent, matrix, denom=1, mult_tab=None)
另一个模块的子模块。
__init__(parent, matrix, denom=1, mult_tab=None)
参数:
parent : 模块
派生此模块的模块。
matrix : 域矩阵
over ZZ
其列定义此子模块生成器作为父生成器上的线性组合的矩阵。
denom : 整数, 可选 (默认为 1)
矩阵给定系数的分母。
mult_tab : 字典, None
, 可选
如果已知,可以提供此模块的乘法表。
property QQ_matrix
域矩阵
over QQ,等于 self.matrix / self.denom
,并保证为稠密矩阵。
返回:
域矩阵
over QQ
解释
取决于其形成方式,域矩阵
可能具有内部表示为稀疏或稠密的表现形式。我们在这里保证稠密表示,以便子模块的等价性测试总是符合预期。
示例
>>> 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)
将此 子模块
添加到另一个模块中。
参数:
other : 子模块
hnf : 布尔值, 可选 (默认为 True)
如果为
True
,将组合模块的矩阵减少到其 Hermite 正常形式。
hnf_modulus:ZZ,可选,默认为 None
如果提供了正整数,则在 HNF 约简中使用它作为模数。参见
hermite_normal_form()
。
返回:
子模块
说明
这代表由两个模块生成器集合的并集生成的模块。
basis_element_pullbacks()
返回此子模块作为父模块中的基元素列表。
discard_before(r)
通过丢弃给定索引r之前的所有生成器来生成一个新的模块。
mul(other, hnf=True, hnf_modulus=None)
将此子模块
乘以一个有理数,一个模元素
或另一个子模块
。
参数:
other:整数,ZZ,QQ,模元素
,子模块
hnf:布尔值,可选(默认为 True)
如果为
True
,将产品模块的矩阵减少到其 Hermite 正常形式。
hnf_modulus:ZZ,可选,默认为 None
如果提供了正整数,则在 HNF 约简中使用它作为模数。参见
hermite_normal_form()
。
返回:
子模块
说明
乘以有理数或模元素
意味着形成其生成器为当前子模块所有生成器与此数量的乘积的子模块。
乘以另一个子模块
意味着形成其生成器为一个子模块的一个生成器与另一个子模块的一个生成器的乘积的子模块。
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)在此过程下都将其减少为它。
参数:
元素 : 模块元素
这个子模块的父模块的一个元素。
返回:
元素 : 模块元素
这个子模块的父模块的一个元素。
引发:
未实现错误
如果给定的
模块元素
不属于此子模块的父模块。
结构错误
如果这个子模块的定义矩阵不是方的、最大秩的 Hermite 正则形式。
解释
特别情况下,当 (A) 是数域 (K) 的一个幂基,而 (B) 是代表理想 (I) 的一个子模块时,这个操作代表了将 (K) 中的一个元素对 (I) 取模以得到一个“小”代表的几种重要方法之一。参见 [Cohen00] 第 1.4.3 节。
示例
>>> 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]
参考文献
[Cohen00] (1,2)
Cohen, H. 计算数论的高级主题.
reduced()
生成这个子模块的简化版本。
返回:
子模块
解释
在简化版本中,保证 1 是唯一同时整除子模块的分母和子模块矩阵中每个条目的正整数。
represent(elt)
将一个模块元素表示为该模块生成元的整数线性组合。
另请参阅
Module.represent
, PowerBasis.represent
class sympy.polys.numberfields.modules.ModuleElement(module, col, denom=1)
表示 模块
的一个元素。
注:不应直接构造。请使用 __call__()
方法或 make_mod_elt()
工厂函数代替。
__init__(module, col, denom=1)
参数:
模块 : 模块
属于此元素的模块。
列 : 域矩阵
over ZZ
给出此元素系数的分子的列向量。
分母 : int, 可选 (默认=1)
此元素的系数的分母。
__add__(other)
一个ModuleElement
可以加到一个有理数,或者另一个ModuleElement
。
解释
当另一个加数是有理数时,它将被转换为一个ModuleElement
(属于这个模块的第一个以单位开始的祖先)。
在所有情况下,和属于两个加数模块的最近公共祖先(NCA)。如果 NCA 不存在,我们返回NotImplemented
。
__mul__(other)
一个ModuleElement
可以乘以有理数,或者另一个ModuleElement
。
解释
当乘数是一个有理数时,该产品通过直接操作这个ModuleElement
的系数来计算。
当乘数是另一个ModuleElement
时,该产品将属于两个操作数的模块的最近公共祖先(NCA),并且该 NCA 必须有一个乘法表。如果 NCA 不存在,我们返回NotImplemented
。如果 NCA 没有乘法表,将会引发ClosureFailure
。
__mod__(m)
将这个ModuleElement
对Submodule
进行归约。
参数:
m:整数,ZZ,QQ,Submodule
如果是
Submodule
,相对于此归约self
。如果是整数或有理数,则相对于我们自己模块乘以这个常数的Submodule
进行归约。
参见
Submodule.reduce_element
property QQ_col
DomainMatrix
在 QQ 上,等于self.col / self.denom
,并且保证是密集的。
参见
Submodule.QQ_matrix
column(domain=None)
获取此元素列的副本,可选择转换为域。
equiv(other)
如果它们表示相同的代数数,则ModuleElement
可能测试为等价于有理数或另一个。
参数:
other:int,ZZ,QQ,ModuleElement
返回:
布尔值
引发:
UnificationFailed
如果
self
和other
不共享PowerBasis
祖先。
解释
此方法仅意在检查等价性的情况下进行测试;即,当other是可以与此一致化的ModuleElement
(即,与此共享公共PowerBasis
祖先)或者是一个有理数时(因为每个PowerBasis
代表每个有理数)。
classmethod from_int_list(module, coeffs, denom=1)
从整数列表(而不是列向量)创建一个ModuleElement
。
is_compat(other)
测试other是否为另一个具有相同模块的ModuleElement
。
property n
此元素列的长度。
over_power_basis()
转换为我们PowerBasis
祖先上的PowerBasisElement
。
reduced()
生成此ModuleElement
的简化版本,即分母和所有分子系数的 gcd 为 1。
reduced_mod_p(p)
生成此ModuleElement
的版本,其中所有分子系数已经对p取模。
to_ancestor(anc)
将其转换为属于此元素模块祖先的ModuleElement
。
参数:
anc:Module
to_parent()
转换为此元素模块父级的ModuleElement
。
unify(other)
尝试生成一个与ModuleElement
兼容的配对,一个等效于这个,另一个等效于另一个。
返回:
配对(e1, e2)
每个
ei
是ModuleElement
,它们属于同一个Module
,e1
等效于self
,e2
等效于other
。
抛出:
UnificationFailed
如果
self
和other
没有共同的祖先模块。
Explanation
我们搜索元素对的最近共同祖先模块,并在那里表示每个元素。
class sympy.polys.numberfields.modules.PowerBasisElement(module, col, denom=1)
子类,用于模块为PowerBasis
的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
抛出:
StructureError
如果这个元素所属的
PowerBasis
没有关联的AlgebraicField
。
Explanation
一般来说,从AlgebraicNumber
到PowerBasisElement
的转换会丢失信息,因为AlgebraicNumber
指定了一个复数嵌入,而PowerBasisElement
则没有。然而,在某些情况下,可以将PowerBasisElement
转换回AlgebraicNumber
,特别是当相关的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)
从一个模块到另一个模块的同态映射。
__init__(domain, codomain, mapping)
参数:
domain:Module
映射的定义域。
codomain:Module
映射的值域。
mapping:可调用对象
任意可调用对象都可以被接受,但应选择代表实际模块同态的对象。特别是,应该接受定义域的元素并返回值域的元素。
示例:
>>> 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)
计算代表这个同态的核心的子模块。
参数:
modulus:int,可选
如果核心应该在模数
p
下计算,则为正的素数(p)。
返回:
Submodule
这个子模块的生成元跨越在 ZZ 上这个同态的核心,或者如果给定了模数,那么在 GF§上跨越。
matrix(modulus=None)
计算这个同态的矩阵。
参数:
modulus:int,可选
如果矩阵应该在模数
p
下被约简,则为正的素数(p)。
返回:
DomainMatrix
如果矩阵是在 ZZ 上,否则是在 GF§上,如果给定了模数。
class sympy.polys.numberfields.modules.ModuleEndomorphism(domain, mapping)
从一个模到其自身的同态映射。
__init__(domain, mapping)
参数:
定义域:Module
映射的公共定义域和值域。
映射:可调用
接受任意可调用对象,但应选择以表示实际的模自同态。特别地,应接受并返回 定义域 的元素。
class sympy.polys.numberfields.modules.InnerEndomorphism(domain, multiplier)
模上的内部自同态,即乘以固定元素所对应的自同态。
__init__(domain, multiplier)
参数:
定义域:Module
自同态的定义域和值域。
乘子:ModuleElement
元素 (a) 定义映射为 (x \mapsto a x)。
class sympy.polys.numberfields.modules.EndomorphismRing(domain)
一个模的自同态环。
__init__(domain)
参数:
定义域:Module
自同态的定义域和值域。
inner_endomorphism(multiplier)
形成属于这个自同态环的内部自同态。
参数:
乘子:ModuleElement
定义内部自同态的元素 (a),即 (x \mapsto a x)。
返回:
InnerEndomorphism
represent(element)
将这个自同态环的元素表示为一个单列向量。
参数:
元素:ModuleEndomorphism
属于这个环。
返回:
DomainMatrix
列向量等于将表示给定 元素 的矩阵的所有列竖直堆叠。
解释
设 (M) 是一个模,(E) 是其自同态环。设 (N) 是另一个模,并考虑一个同态 (\varphi: N \rightarrow E)。如果 (\varphi) 要用矩阵 (A) 表示,那么 (A) 的每一列必须表示 (E) 的一个元素。当 (E) 的元素本身可以表示为矩阵时,可以通过将这样一个矩阵的列堆叠成单列来实现这一点。
此方法支持计算这样的矩阵 (A),首先将这个自同态环的一个元素表示为矩阵,然后将该矩阵的列堆叠成单列。
示例
注意,在这些示例中,我们打印矩阵的转置,以便更容易检查其列。
>>> 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²),依此类推。
环 E
的同态的 represent
方法将它们堆叠到单列中:
>>> E.represent(tau).transpose()
DomainMatrix(
[[0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, -1, -1, -1]],
(1, 16), ZZ)
当我们想要考虑一个具有 E
作为余域的同态 (\varphi) 时,这是有用的:
>>> 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 : ModuleElement
期望找到其最小多项式的元素,并且其模具有乘法并以单位元开始。
domain : Domain
多项式的期望域。
x : Symbol
,可选
多项式的期望变量。
powers : 列表,可选
如果需要,传递空列表。从零到最小多项式的次数,将 alpha 的幂(作为
ModuleElement
实例)记录在此处,我们在计算它们时。
返回:
Poly
,None
对于 alpha 的最小多项式,如果在期望的域上找不到多项式,则返回
None
。
引发:
MissingUnityError
如果 alpha 属于的模不以单位元开头。
ClosureFailure
如果 alpha 属于的模不闭合于乘法。
示例
对于第 (n) 个旋缠域,(n) 为奇素数,考虑其根为长度为 ((n-1)/2) 的两个周期的二次方程。高斯的文章 356 告诉我们,根据 (n) 是 1 或 3 模 4,我们应该得到 (x² + x - (n-1)/4) 或 (x² + 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)
测试参数是否适合用作有理数。
解释
对于类型为 int
、ZZ 或 QQ 的任何参数返回 True
。
另请参阅
is_int
sympy.polys.numberfields.utilities.is_int(c)
测试参数是否适合用作整数。
解释
对于类型为 int
或 ZZ 的任何参数返回 True
。
另请参阅
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 模 4
返回:
字典对 (D, F)
。
抛出:
ValueError
如果 a 不是 4 的倍数余 0 或 1.
解释
给定任意 0 或 1 模 4 的有理整数 a,写成 (a = d f²),其中 (d) 要么是 1 要么是基本判别式,并返回给定的由 factorint()
返回格式相同的字典对 (D, F)
,分别给出 (d) 和 (f) 的素因子分解。
基本判别式 (d) 不同于单位,并且要么是 4 的倍数余 1 并且无平方因子,要么是 4 的倍数余 0 并且 (d/4) 是无平方因子并且余 2 或 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}
参考文献
[R805]
Cohen, H. 计算代数数论课程.(见 Prop. 5.1.3)
class sympy.polys.numberfields.utilities.AlgIntPowers(T, modulus=None)
计算代数整数的幂。
解释
给定一个代数整数 (\theta) 由其在 ZZ 上的首一不可约多项式 T
,此类计算 (\theta) 的任意高次幂的表示,作为 ZZ 上的线性组合,其中 (n = \deg(T))。
利用多项式 T
导出的 (\theta) 的幂的线性递归关系计算表示。见 [1],第 4.2.2 节。
可选地,可以将表示与模数减少。
示例
>>> 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]
参考文献
[R806]
Cohen, H. 计算代数数论课程.
__init__(T, modulus=None)
参数:
T : Poly
定义代数整数的首一不可约多项式在 ZZ 上。
modulus : int, None, 可选
如果不是
None
,所有表示将被减少到这个。
sympy.polys.numberfields.utilities.coeff_search(m, R)
为搜索多项式生成系数。
参数:
m : int
系数列表的长度。
R : int
系数的初始最大绝对值(搜索进行时将增加)。
返回:
generator
列表系数的无限生成器。
解释
导数系数始终为非负。在增加界限前,探索绝对值受限的所有组合。跳过全零列表,跳过任何重复。见示例。
示例
>>> 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)
将子空间的基扩展为整个空间的基。
参数:
M : DomainMatrix
列给出子空间的基。
返回:
DomainMatrix
此矩阵是可逆的,其前 (r) 列等于 M。
提升:
DMRankError
如果 M 不是最大秩。
解释
给定一个秩为 (r) 的 (n \times r) 矩阵 M(因此 (r \leq n)),此函数计算一个可逆的 (n \times n) 矩阵 (B),使得 (B) 的前 (r) 列等于 M。
这个操作可以解释为扩展子空间的基,从而给出整个空间的基。
具体来说,假设您有一个 (n)-维向量空间 (V),其基为 ({v_1, v_2, \ldots, v_n}),以及 (V) 的一个 (r)-维子空间 (W),其由基 ({w_1, w_2, \ldots, w_r}) 张成,其中 (w_j) 被给出作为 (v_i) 的线性组合。如果 M 的列表示这些 (w_j) 作为这种线性组合,则此函数计算的矩阵 (B) 的列给出一个新的基 ({u_1, u_2, \ldots, u_n}) 用于 (V),再次相对于 ({v_i}) 基,并且对于 (1 \leq j \leq r),有 (u_j = w_j)。
示例
注意:该函数按列处理,因此在这些示例中,我们打印矩阵的转置,以便更容易检查列。
>>> 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]])
参考资料
[R807]
Cohen, H. 计算代数数论课程(见第 2.3.2 节。)
sympy.polys.numberfields.utilities.isolate(alg, eps=None, fast=False)
为实数代数数找到一个有理隔离区间。
参数:
alg:str, int, Expr
要隔离的代数数。必须是实数,才能使用此特定函数。但是,另请参阅
Poly.intervals()
,当您传递all=True
时,它可以隔离复数根。
eps:正元素 QQ 中的元素,None,可选(默认为 None)
要传递给
Poly.refine_root()
的精度。
fast:布尔值,可选(默认为 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)
另请参阅
Poly.intervals