SymPy-1-13-中文文档-二十八-

news/2024/10/5 7:59:56/文章来源:https://www.cnblogs.com/apachecn/p/18271702

SymPy 1.13 中文文档(二十八)

原文:docs.sympy.org/latest/index.html

数域

原文链接:docs.sympy.org/latest/modules/polys/numberfields.html

引言

像代数数论中许多其他计算一样,有理素数的分裂只能用有理方法处理。如果考虑用自动计算设备进行计算,这一事实非常重要。只需知道不可约多项式(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),计算:

  1. (\mathbb{Z}_K)的一个整数基底

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

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

  4. (K)的 Galois 封闭的 Galois 群

  5. (K)的一组基本单位

  6. 规则(R(K))

  7. 类数

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

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

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

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

  2. 子域问题:通过它们的生成元(\alpha)和(\beta)的最小多项式,给定两个数域(\mathbb{Q}(\alpha)),(\mathbb{Q}(\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 群
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 的“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_orderAlgebraicField.integral_basisAlgebraicField.discriminant

参考文献

[R802]

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

质数分解

sympy.polys.numberfields.primes.prime_decomp(p, T=None, ZK=None, dK=None, radical=None)

计算在一个数域中有理质数p的分解。

参数:

p:int

想要分解的有理质数。

TPoly,可选

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

ZKSubmodule,可选

如果已知,(K)的最大序。注意:TZK至少要提供一个。

dK:int,可选

如果已知,(K)的判别式。

radicalSubmodule,可选

如果已知,(K)的整数中的模p的零根式。

返回:

PrimeIdeal 实例列表。

解释

通常应通过 AlgebraicFieldprimes_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)

参数:

ZKSubmodule

此理想所在的最大阶。

p:int

此理想除以的有理素数。

alphaPowerBasisElement

使得理想等于 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减少到此素理想的“小代表”。

参数:

eltANP

要减少的元素。

返回:

ANP

减少后的元素。

另见

reduce_element, reduce_alg_num, Submodule.reduce_element

reduce_alg_num(a)

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

参数:

eltAlgebraicNumber

要减少的元素。

返回:

AlgebraicNumber

减少后的元素。

另见

reduce_elementreduce_ANPSubmodule.reduce_element

reduce_element(elt)

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

参数:

eltPowerBasisElement

要减少的元素。

返回:

PowerBasisElement

被减少的元素。

参见

reduce_ANPreduce_alg_numSubmodule.reduce_element

repr(field_gen=None, just_gens=False)

打印这个素数理想的表示。

参数:

field_genSymbolNone,可选(默认为 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})-递减估值。

参数:

ISubmodule

参见

prime_valuation

p-递减估值

sympy.polys.numberfields.primes.prime_valuation(I, P)

计算整数理想 IP-递减估值。

参数:

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.S1TransitiveSubgroupssympy.combinatorics.galois.S2TransitiveSubgroups 等枚举类的实例,如果 by_nameTrue,则返回其名称;如果是 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.S1TransitiveSubgroupssympy.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_isomorphismprimitive_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的抽象基类,它有两个具体子类,PowerBasisSubmodule

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

  • 对于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) 

因此,每个模块都是PowerBasisSubmodule的一个祖先,如果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) 

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

__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)

定位此模块及另一个模块的最近公共祖先。

返回:

ModuleNone

另见

Module

property number_field

返回关联的AlgebraicField(如果有的话)。

返回:

AlgebraicFieldNone

解释

可以在Poly (f)上或者在AlgebraicField (K)上构造PowerBasis。在后一种情况下,PowerBasis及其所有后代模块将返回(K)作为其.number_field属性,而在前一种情况下,它们将全部返回None

one()

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

property parent

如果有的话,返回此模块的父模块。

返回:

ModuleNone

解释

对于Submodule,这是其parent属性;对于PowerBasis,这是None

另请参见

Module

power_basis_ancestor()

返回这个模块的祖先的PowerBasis

另请参见

Module

represent(elt)

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

参数:

eltModuleElement

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

返回:

DomainMatrix关于 ZZ

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

引发:

ClosureFailure

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

解释

在我们的系统中,“表示”始终意味着将ModuleElement写成当前Module的生成元的 ZZ 线性组合。此外,传入的ModuleElement必须属于当前Module的祖先(或当前Module本身)。

最常见的应用是在Submodule中表示ModuleElement。例如,这涉及计算乘法表。

另一方面,在PowerBasis中表示是一个特例,这种情况通常不会在实践中出现,除非例如在ModuleEndomorphismPowerBasis上使用时。

在这种情况下,(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.representPowerBasis.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.representSubmodule.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)

将这个ModuleElementSubmodule进行归约。

参数:

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

如果selfother不共享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

参数:

ancModule

to_parent()

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

unify(other)

尝试生成一个与ModuleElement兼容的配对,一个等效于这个,另一个等效于另一个。

返回:

配对(e1, e2)

每个eiModuleElement,它们属于同一个Modulee1等效于selfe2等效于other

抛出:

UnificationFailed

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

Explanation

我们搜索元素对的最近共同祖先模块,并在那里表示每个元素。

class sympy.polys.numberfields.modules.PowerBasisElement(module, col, denom=1)

子类,用于模块为PowerBasisModuleElement实例。

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

一般来说,从AlgebraicNumberPowerBasisElement的转换会丢失信息,因为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)

参数:

domainModule

映射的定义域。

codomainModule

映射的值域。

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(p)上跨越。

matrix(modulus=None)

计算这个同态的矩阵。

参数:

modulus:int,可选

如果矩阵应该在模数p下被约简,则为正的素数(p)。

返回:

DomainMatrix

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

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 实例)记录在此处,我们在计算它们时。

返回:

PolyNone

对于 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

范畴论

原文链接:docs.sympy.org/latest/modules/categories.html

引言

SymPy 的范畴论模块将允许在单一范畴内操作图表,包括在 TikZ 中绘制它们并判断它们是否可交换。

此模块试图遵循的一般参考工作是

[JoyOfCats]

  1. Adamek, H. Herrlich. G. E. Strecker: 抽象和具体范畴。猫的乐趣。

最新版本的这本书可以免费下载。

katmat.math.uni-bremen.de/acc/acc.pdf

此模块仍处于前胚阶段。

基类参考

此部分列出了实现范畴论基本概念的类别的类:对象,态射,范畴和图表。

class sympy.categories.Object(name, **assumptions)

任何抽象范畴中任何类型对象的基类。

解释

尽管技术上任何 Basic 的实例都可以,但这个类是在抽象范畴中创建抽象对象的推荐方式。

class sympy.categories.Morphism(domain, codomain)

抽象范畴中任何态射的基类。

解释

在抽象范畴中,态射是两个范畴对象之间的箭头。箭头起点的对象称为定义域,而终点的对象称为值域。

相同对象之间的两个态射被认为是相同的态射。要区分相同对象之间的态射,请使用 NamedMorphism

禁止实例化此类。请改用其中一个派生类。

另见

IdentityMorphism, NamedMorphism, CompositeMorphism

property codomain

返回态射的值域。

示例

>>> from sympy.categories import Object, NamedMorphism
>>> A = Object("A")
>>> B = Object("B")
>>> f = NamedMorphism(A, B, "f")
>>> f.codomain
Object("B") 
compose(other)

与提供的态射组合自身。

构成组合的元素顺序是通常的顺序,即构造 (g\circ f) 使用 g.compose(f)

示例

>>> from sympy.categories import Object, NamedMorphism
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> g * f
CompositeMorphism((NamedMorphism(Object("A"), Object("B"), "f"),
NamedMorphism(Object("B"), Object("C"), "g")))
>>> (g * f).domain
Object("A")
>>> (g * f).codomain
Object("C") 
property domain

返回态射的定义域。

示例

>>> from sympy.categories import Object, NamedMorphism
>>> A = Object("A")
>>> B = Object("B")
>>> f = NamedMorphism(A, B, "f")
>>> f.domain
Object("A") 
class sympy.categories.NamedMorphism(domain, codomain, name)

表示具有名称的态射。

解释

名称用于区分具有相同定义域和值域的态射:如果它们具有相同的定义域,值域和名称,则两个命名的态射相等。

示例

>>> from sympy.categories import Object, NamedMorphism
>>> A = Object("A")
>>> B = Object("B")
>>> f = NamedMorphism(A, B, "f")
>>> f
NamedMorphism(Object("A"), Object("B"), "f")
>>> f.name
'f' 

另见

Morphism

property name

返回态射的名称。

示例

>>> from sympy.categories import Object, NamedMorphism
>>> A = Object("A")
>>> B = Object("B")
>>> f = NamedMorphism(A, B, "f")
>>> f.name
'f' 
class sympy.categories.CompositeMorphism(*components)

表示一个由其他态射组成的态射。

解释

如果它们从中获得的态射(组件)相同并以相同顺序列出,则两个复合态射相等。

此类的构造函数的参数应按图表顺序列出:从 Morphism 实例 gf 获取复合态射 (g\circ f)。

例子

>>> from sympy.categories import Object, NamedMorphism, CompositeMorphism
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> g * f
CompositeMorphism((NamedMorphism(Object("A"), Object("B"), "f"),
NamedMorphism(Object("B"), Object("C"), "g")))
>>> CompositeMorphism(f, g) == g * f
True 
property codomain

返回这个复合态射的余域。

复合态射的余域是其最后组成部分的余域。

例子

>>> from sympy.categories import Object, NamedMorphism
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> (g * f).codomain
Object("C") 
property components

返回此复合态射的组件。

例子

>>> from sympy.categories import Object, NamedMorphism
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> (g * f).components
(NamedMorphism(Object("A"), Object("B"), "f"),
NamedMorphism(Object("B"), Object("C"), "g")) 
property domain

返回这个复合态射的定义域。

复合态射的定义域是其第一个组成部分的定义域。

例子

>>> from sympy.categories import Object, NamedMorphism
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> (g * f).domain
Object("A") 
flatten(new_name)

忘记了这个态射的复合结构。

解释

如果 new_name 不为空,则返回一个带有提供名称的 NamedMorphism,否则返回一个 Morphism。在两种情况下,新态射的定义域是此复合态射的定义域,新态射的余域是此复合态射的余域。

例子

>>> from sympy.categories import Object, NamedMorphism
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> (g * f).flatten("h")
NamedMorphism(Object("A"), Object("C"), "h") 
class sympy.categories.IdentityMorphism(domain)

表示一个恒等态射。

解释

恒等态射是具有相同定义域和余域的态射,其在复合方面作为恒等元素。

例子

>>> from sympy.categories import Object, NamedMorphism, IdentityMorphism
>>> A = Object("A")
>>> B = Object("B")
>>> f = NamedMorphism(A, B, "f")
>>> id_A = IdentityMorphism(A)
>>> id_B = IdentityMorphism(B)
>>> f * id_A == f
True
>>> id_B * f == f
True 

另见

Morphism

class sympy.categories.Category(name, objects=EmptySet, commutative_diagrams=EmptySet)

一个(抽象)范畴。

解释

一个范畴 [JoyOfCats] 是一个四元组 (\mbox{K} = (O, \hom, id, \circ)),由以下组成:

  • 一个(集合论上的)类 (O),其成员称为 (K)-对象,

  • 对于每对 (K)-对象 ((A, B)),一个集合 (\hom(A, B)),其成员称为从 (A) 到 (B) 的 (K)-态射,

  • 对于每个 (K)-对象 (A),一个态射 (id:A\rightarrow A),称为 (A) 的 (K)-恒等态射,

  • 一个复合法则 (\circ),将每个 (K)-态射 (f:A\rightarrow B) 和 (g:B\rightarrow C) 关联到一个 (K)-态射 (g\circ f:A\rightarrow C),称为 (f) 和 (g) 的复合。

复合是可结合的,(K)-恒等式在复合方面是单位元,并且集合 (\hom(A, B)) 是两两不相交的。

这个类对其对象和态射一无所知。应将(抽象)范畴的具体情况实现为从此类派生的类。

通过在构造函数中提供参数 commutative_diagrams,可以断言某些实例的 DiagramCategory 中是交换的。

例子

>>> from sympy.categories import Object, NamedMorphism, Diagram, Category
>>> from sympy import FiniteSet
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> d = Diagram([f, g])
>>> K = Category("K", commutative_diagrams=[d])
>>> K.commutative_diagrams == FiniteSet(d)
True 

另见

Diagram

property commutative_diagrams

返回已知在此范畴中为交换的图表的 FiniteSet

例子

>>> from sympy.categories import Object, NamedMorphism, Diagram, Category
>>> from sympy import FiniteSet
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> d = Diagram([f, g])
>>> K = Category("K", commutative_diagrams=[d])
>>> K.commutative_diagrams == FiniteSet(d)
True 
property name

返回此范畴的名称。

例子

>>> from sympy.categories import Category
>>> K = Category("K")
>>> K.name
'K' 
property objects

返回此范畴的对象类。

例子

>>> from sympy.categories import Object, Category
>>> from sympy import FiniteSet
>>> A = Object("A")
>>> B = Object("B")
>>> K = Category("K", FiniteSet(A, B))
>>> K.objects
Class({Object("A"), Object("B")}) 
class sympy.categories.Diagram(*args)

表示某个范畴中的图表。

解释

非正式地说,一个图表是一个类别中对象和某些它们之间的态射的集合。一个图表仍然是关于态射组合的幺半群;即,包括在图表中的所有态射的恒等态射以及所有复合态射属于图表。有关此概念的更正式方法,请参见[Pare1970]。

复合态射的组成部分也添加到图表中。此类态射默认不分配属性。

通常,一个交换图表伴随着以下类型的声明:“如果存在这样的具有这样的属性的态射,则存在这样的具有这样的属性的态射,并且图表是交换的”。为了表示这一点,图表的一个实例包括属于相应类别的态射的集合,其具有FiniteSet的属性的集合。

复合态射的属性集是其组成部分的属性集的交集。结论态射的定义域和值域应该是图表前提中列出的态射的定义域和值域之一。

不检查所提供的对象和态射是否属于同一类别。

示例

>>> from sympy.categories import Object, NamedMorphism, Diagram
>>> from sympy import pprint, default_sort_key
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> d = Diagram([f, g])
>>> premises_keys = sorted(d.premises.keys(), key=default_sort_key)
>>> pprint(premises_keys, use_unicode=False)
[g*f:A-->C, id:A-->A, id:B-->B, id:C-->C, f:A-->B, g:B-->C]
>>> pprint(d.premises, use_unicode=False)
{g*f:A-->C: EmptySet, id:A-->A: EmptySet, id:B-->B: EmptySet,id:C-->C: EmptySet, f:A-->B: EmptySet, g:B-->C: EmptySet}
>>> d = Diagram([f, g], {g * f: "unique"})
>>> pprint(d.conclusions,use_unicode=False)
{g*f:A-->C: {unique}} 

参考文献

[Pare1970] B. Pareigis: 类别与函子。学术出版社,1970 年。

property conclusions

返回此图表的结论。

示例

>>> from sympy.categories import Object, NamedMorphism
>>> from sympy.categories import IdentityMorphism, Diagram
>>> from sympy import FiniteSet
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> d = Diagram([f, g])
>>> IdentityMorphism(A) in d.premises.keys()
True
>>> g * f in d.premises.keys()
True
>>> d = Diagram([f, g], {g * f: "unique"})
>>> d.conclusions[g * f] == FiniteSet("unique")
True 
hom(A, B)

返回对象AB之间的态射集的 2 元组:一个作为前提列出的态射集,另一个作为结论列出的态射集。

示例

>>> from sympy.categories import Object, NamedMorphism, Diagram
>>> from sympy import pretty
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> d = Diagram([f, g], {g * f: "unique"})
>>> print(pretty(d.hom(A, C), use_unicode=False))
({g*f:A-->C}, {g*f:A-->C}) 

另请参阅

对象态射

is_subdiagram(diagram)

检查diagram是否是self的子图。如果图表(D')的所有前提(结论)都包含在图表(D)的前提(结论)中,则图表(D')是图表(D)的子图。对于(D')成为(D)的子图,(D')和(D)中包含的态射应具有相同的属性。

示例

>>> from sympy.categories import Object, NamedMorphism, Diagram
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> d = Diagram([f, g], {g * f: "unique"})
>>> d1 = Diagram([f])
>>> d.is_subdiagram(d1)
True
>>> d1.is_subdiagram(d)
False 
property objects

返回出现在此图表中的对象的FiniteSet

示例

>>> from sympy.categories import Object, NamedMorphism, Diagram
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> d = Diagram([f, g])
>>> d.objects
{Object("A"), Object("B"), Object("C")} 
property premises

返回此图表的前提。

示例

>>> from sympy.categories import Object, NamedMorphism
>>> from sympy.categories import IdentityMorphism, Diagram
>>> from sympy import pretty
>>> A = Object("A")
>>> B = Object("B")
>>> f = NamedMorphism(A, B, "f")
>>> id_A = IdentityMorphism(A)
>>> id_B = IdentityMorphism(B)
>>> d = Diagram([f])
>>> print(pretty(d.premises, use_unicode=False))
{id:A-->A: EmptySet, id:B-->B: EmptySet, f:A-->B: EmptySet} 
subdiagram_from_objects(objects)

如果objectsself对象的子集,则返回一个图表,其前提是所有具有objects中的域和值域的前提,类似于结论。属性被保留。

示例

>>> from sympy.categories import Object, NamedMorphism, Diagram
>>> from sympy import FiniteSet
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> d = Diagram([f, g], {f: "unique", g*f: "veryunique"})
>>> d1 = d.subdiagram_from_objects(FiniteSet(A, B))
>>> d1 == Diagram([f], {f: "unique"})
True 
```  ## 图表绘制本节列出了允许自动绘制图表的类别。```py
class sympy.categories.diagram_drawing.DiagramGrid(diagram, groups=None, **hints)

构造并保存图表适合网格中。

解释

本课程的任务是分析所提供的图表结构,并将其对象放置在网格上,使得当对象和态射实际绘制时,图表将“可读”,即不会有太多态射的交叉。本课程不执行任何实际绘图。尽管如此,它仍努力提供足够的元数据来绘制图表。

考虑以下简单图表。

>>> from sympy.categories import Object, NamedMorphism
>>> from sympy.categories import Diagram, DiagramGrid
>>> from sympy import pprint
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> diagram = Diagram([f, g]) 

将图表布局最简单的方法如下:

>>> grid = DiagramGrid(diagram)
>>> (grid.width, grid.height)
(2, 2)
>>> pprint(grid)
A  BC 

有时人们将图表视为由逻辑分组组成。可以通过使用 groups 关键字参数向 DiagramGrid 提供此类分组建议。

考虑以下图表:

>>> D = Object("D")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> h = NamedMorphism(D, A, "h")
>>> k = NamedMorphism(D, B, "k")
>>> diagram = Diagram([f, g, h, k]) 

使用通用布局排列:

>>> grid = DiagramGrid(diagram)
>>> pprint(grid)
A  B  DC 

现在,我们可以将对象 (A) 和 (D) 分组,使它们彼此靠近:

>>> grid = DiagramGrid(diagram, groups=[[A, D], B, C])
>>> pprint(grid)
B     CA  D 

注意其他对象的定位如何改变。

可以使用关键字参数向 DiagramGrid 的构造函数提供进一步的指示。当前支持的提示在以下段落中解释。

DiagramGrid 不会自动猜测哪种布局更适合所提供的图表。例如,考虑以下线性图表:

>>> E = Object("E")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> h = NamedMorphism(C, D, "h")
>>> i = NamedMorphism(D, E, "i")
>>> diagram = Diagram([f, g, h, i]) 

当使用通用布局排列时,它不会呈线性外观:

>>> grid = DiagramGrid(diagram)
>>> pprint(grid)
A  BC  DE 

要将其布置在一条线上,请使用layout="sequential"

>>> grid = DiagramGrid(diagram, layout="sequential")
>>> pprint(grid)
A  B  C  D  E 

有时可能需要转置结果布局。虽然这可以手动完成,但 DiagramGrid 提供了一个用于此目的的提示:

>>> grid = DiagramGrid(diagram, layout="sequential", transpose=True)
>>> pprint(grid)
ABCDE 

还可以为每个组提供单独的提示。例如,请参考 tests/test_drawing.py,查看如何布置五引理 [FiveLemma] 的不同方法。

参见

Diagram

参考

[FiveLemma]

en.wikipedia.org/wiki/Five_lemma

property height

返回此图表布局中的行数。

示例

>>> from sympy.categories import Object, NamedMorphism
>>> from sympy.categories import Diagram, DiagramGrid
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> diagram = Diagram([f, g])
>>> grid = DiagramGrid(diagram)
>>> grid.height
2 
property morphisms

返回那些足够有意义以进行绘制的态射(及其属性)。

示例

>>> from sympy.categories import Object, NamedMorphism
>>> from sympy.categories import Diagram, DiagramGrid
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> diagram = Diagram([f, g])
>>> grid = DiagramGrid(diagram)
>>> grid.morphisms
{NamedMorphism(Object("A"), Object("B"), "f"): EmptySet,
NamedMorphism(Object("B"), Object("C"), "g"): EmptySet} 
property width

返回此图表布局中的列数。

示例

>>> from sympy.categories import Object, NamedMorphism
>>> from sympy.categories import Diagram, DiagramGrid
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> diagram = Diagram([f, g])
>>> grid = DiagramGrid(diagram)
>>> grid.width
2 
class sympy.categories.diagram_drawing.ArrowStringDescription(unit, curving, curving_amount, looping_start, looping_end, horizontal_direction, vertical_direction, label_position, label)

存储生成箭头的 Xy-pic 描述所需的信息。

本课程的主要目标是抽象化箭头的字符串表示,并提供生成实际 Xy-pic 字符串的功能。

unit 设置用于指定弯曲量和其他距离的单位。horizontal_direction 应该是 "r""l" 的字符串,指定相对于当前箭头的水平偏移量。vertical_direction 应该使用一系列 "d""u" 指定垂直偏移量。label_position 应该是 "^""_""|" 中的一个,指定标签应位于箭头上方、下方或正好在箭头上方的位置,在此期间请注意“上方”和“下方”概念是相对于箭头方向的。label 存储了态射标签。

此方法的操作如下(忽略尚未解释的参数):

>>> from sympy.categories.diagram_drawing import ArrowStringDescription
>>> astr = ArrowStringDescription(
... unit="mm", curving=None, curving_amount=None,
... looping_start=None, looping_end=None, horizontal_direction="d",
... vertical_direction="r", label_position="_", label="f")
>>> print(str(astr))
\ar[dr]_{f} 

curving 应该是 "^""_" 中的一个,用于指定箭头弯曲的方向。curving_amount 是一个数字,描述箭头弯曲的单位数目:

>>> astr = ArrowStringDescription(
... unit="mm", curving="^", curving_amount=12,
... looping_start=None, looping_end=None, horizontal_direction="d",
... vertical_direction="r", label_position="_", label="f")
>>> print(str(astr))
\ar@/¹²mm/[dr]_{f} 

looping_startlooping_end 目前仅用于环形态射,即具有相同定义域和值域的态射。这两个属性应存储有效的 Xy-pic 方向,并相应地指定箭头向外和向内的方向:

>>> astr = ArrowStringDescription(
... unit="mm", curving=None, curving_amount=None,
... looping_start="u", looping_end="l", horizontal_direction="",
... vertical_direction="", label_position="_", label="f")
>>> print(str(astr))
\ar@(u,l)[]_{f} 

label_displacement 控制箭头标签离箭头末端的距离。例如,要将箭头标签定位在箭头头部附近,请使用“>”:

>>> astr = ArrowStringDescription(
... unit="mm", curving="^", curving_amount=12,
... looping_start=None, looping_end=None, horizontal_direction="d",
... vertical_direction="r", label_position="_", label="f")
>>> astr.label_displacement = ">"
>>> print(str(astr))
\ar@/¹²mm/[dr]_>{f} 

最后,arrow_style 用于指定箭头样式。例如,要获得虚线箭头,请使用“{–>}”作为箭头样式:

>>> astr = ArrowStringDescription(
... unit="mm", curving="^", curving_amount=12,
... looping_start=None, looping_end=None, horizontal_direction="d",
... vertical_direction="r", label_position="_", label="f")
>>> astr.arrow_style = "{-->}"
>>> print(str(astr))
\ar@/¹²mm/@{-->}[dr]_{f} 

注意事项

XypicDiagramDrawer 将构造 ArrowStringDescription 的实例,并提供给格式化程序进一步使用。用户不应自行构造 ArrowStringDescription 的实例。

为了能够正确使用此类,请读者查看 Xy-pic 用户指南,可在 [Xypic] 上获取。

另见

XypicDiagramDrawer

参考文献

[Xypic]

xy-pic.sourceforge.net/

class sympy.categories.diagram_drawing.XypicDiagramDrawer

给定一个 Diagram 及其对应的 DiagramGrid,生成该图示的 Xy-pic 表示。

此类中最重要的方法是 draw。考虑以下三角形图示:

>>> from sympy.categories import Object, NamedMorphism, Diagram
>>> from sympy.categories import DiagramGrid, XypicDiagramDrawer
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> diagram = Diagram([f, g], {g * f: "unique"}) 

要绘制此图,需要使用 DiagramGrid 将其对象布局出来:

>>> grid = DiagramGrid(diagram) 

最后,绘制如下:

>>> drawer = XypicDiagramDrawer()
>>> print(drawer.draw(diagram, grid))
\xymatrix{
A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\
C &
} 

更多细节请参阅此方法的文档字符串。

要控制箭头的外观,需要使用格式化器。字典 arrow_formatters 将态射映射到格式化函数。格式化器接受一个 ArrowStringDescription 并允许修改其中公开的任何箭头属性。例如,要使所有具有 unique 属性的态射显示为虚线箭头,并在它们的名称前加上 (\exists !),应按如下方式操作:

>>> def formatter(astr):
...   astr.label = r"\exists !" + astr.label
...   astr.arrow_style = "{-->}"
>>> drawer.arrow_formatters["unique"] = formatter
>>> print(drawer.draw(diagram, grid))
\xymatrix{
A \ar@{-->}[d]_{\exists !g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\
C &
} 

要修改图示中所有箭头的外观,设置 default_arrow_formatter。例如,要将所有态射标签稍微远离箭头头部,使它们看起来更加居中,可以按如下方式操作:

>>> def default_formatter(astr):
...   astr.label_displacement = "(0.45)"
>>> drawer.default_arrow_formatter = default_formatter
>>> print(drawer.draw(diagram, grid))
\xymatrix{
A \ar@{-->}[d]_(0.45){\exists !g\circ f} \ar[r]^(0.45){f} & B \ar[ld]^(0.45){g} \\
C &
} 

在一些图示中,一些态射被绘制为弯曲箭头。考虑以下图示:

>>> D = Object("D")
>>> E = Object("E")
>>> h = NamedMorphism(D, A, "h")
>>> k = NamedMorphism(D, B, "k")
>>> diagram = Diagram([f, g, h, k])
>>> grid = DiagramGrid(diagram)
>>> drawer = XypicDiagramDrawer()
>>> print(drawer.draw(diagram, grid))
\xymatrix{
A \ar[r]_{f} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_3mm/[ll]_{h} \\
& C &
} 

要控制态射的默认弯曲程度,可以使用 unitdefault_curving_amount 属性:

>>> drawer.unit = "cm"
>>> drawer.default_curving_amount = 1
>>> print(drawer.draw(diagram, grid))
\xymatrix{
A \ar[r]_{f} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_1cm/[ll]_{h} \\
& C &
} 

在某些图示中,同一两个对象之间可能存在多个弯曲态射。要控制这些连续态射之间的弯曲程度变化,使用 default_curving_step

>>> drawer.default_curving_step = 1
>>> h1 = NamedMorphism(A, D, "h1")
>>> diagram = Diagram([f, g, h, k, h1])
>>> grid = DiagramGrid(diagram)
>>> print(drawer.draw(diagram, grid))
\xymatrix{
A \ar[r]_{f} \ar@/¹cm/[rr]^{h_{1}} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_2cm/[ll]_{h} \\
& C &
} 

default_curving_step 的默认值为 4 单位。

另请参见

drawArrowStringDescription

draw(diagram, grid, masked=None, diagram_format='')

返回在 grid 中布局的 diagram 的 Xy-pic 表示。

考虑以下简单的三角形图示。

>>> from sympy.categories import Object, NamedMorphism, Diagram
>>> from sympy.categories import DiagramGrid, XypicDiagramDrawer
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> diagram = Diagram([f, g], {g * f: "unique"}) 

要绘制此图示,需要使用 DiagramGrid 对其对象进行布局:

>>> grid = DiagramGrid(diagram) 

最后,绘制:

>>> drawer = XypicDiagramDrawer()
>>> print(drawer.draw(diagram, grid))
\xymatrix{
A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\
C &
} 

参数 masked 可用于在图示的表示中跳过态射:

>>> print(drawer.draw(diagram, grid, masked=[g * f]))
\xymatrix{
A \ar[r]^{f} & B \ar[ld]^{g} \\
C &
} 

最后,diagram_format 参数可用于指定图示的格式字符串。例如,要增加 1 厘米的间距,可以按以下步骤进行:

>>> print(drawer.draw(diagram, grid, diagram_format="@+1cm"))
\xymatrix@+1cm{
A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\
C &
} 
sympy.categories.diagram_drawing.xypic_draw_diagram(diagram, masked=None, diagram_format='', groups=None, **hints)

提供了一个快捷方式,结合了 DiagramGridXypicDiagramDrawer。返回 diagram 的 Xy-pic 表示。参数 masked 是一个不绘制的态射列表。参数 diagram_format 是插入到“xymatrix”之后的格式字符串。groups 应该是一组逻辑组。hints 将直接传递给 DiagramGrid 的构造函数。

有关参数的更多信息,请参见 DiagramGridXypicDiagramDrawer.draw 的文档字符串。

示例

>>> from sympy.categories import Object, NamedMorphism, Diagram
>>> from sympy.categories import xypic_draw_diagram
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> diagram = Diagram([f, g], {g * f: "unique"})
>>> print(xypic_draw_diagram(diagram))
\xymatrix{
A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\
C &
} 

另请参见

XypicDiagramDrawer, DiagramGrid

sympy.categories.diagram_drawing.preview_diagram(diagram, masked=None, diagram_format='', groups=None, output='png', viewer=None, euler=True, **hints)

结合了xypic_draw_diagramsympy.printing.preview的功能。参数maskeddiagram_formatgroupshints被传递给xypic_draw_diagram,而outputpyviewer, and ``euler被传递给preview

示例

>>> from sympy.categories import Object, NamedMorphism, Diagram
>>> from sympy.categories import preview_diagram
>>> A = Object("A")
>>> B = Object("B")
>>> C = Object("C")
>>> f = NamedMorphism(A, B, "f")
>>> g = NamedMorphism(B, C, "g")
>>> d = Diagram([f, g], {g * f: "unique"})
>>> preview_diagram(d) 

参见

XypicDiagramDrawer

密码学

原文链接:docs.sympy.org/latest/modules/crypto.html

警告

此模块仅供教育目的使用。请勿将此模块中的函数用于实际的加密应用。如果希望加密真实数据,建议使用类似 cryptography 模块。

加密是隐藏消息的过程,而密码是这样做的手段。此模块包含块和流密码:

  • 移位密码
  • 仿射密码
  • 替换密码
  • 维吉尼亚密码
  • Hill 密码
  • 双密码
  • RSA
  • Kid RSA
  • 线性反馈移位寄存器(用于流密码)
  • ElGamal 加密

替换密码 中,根据正规系统将明文的“单位”(不一定是单个字符)替换为密文。

置换密码 是一种加密方法,通过将明文中“单位”的位置替换为明文的置换来改变单位的顺序,使用字符位置的双射函数执行加密。

单字母密码 在整个消息上使用固定的替换,而多字母密码 在消息中的不同时间使用多个替换。

sympy.crypto.crypto.AZ(s=None)

返回字符串 s 中的大写字母。如果传入多个字符串,每个字符串将被处理,并返回大写字符串列表。

示例

>>> from sympy.crypto.crypto import AZ
>>> AZ('Hello, world!')
'HELLOWORLD'
>>> AZ('Hello, world!'.split())
['HELLO', 'WORLD'] 

另请参阅

check_and_join

sympy.crypto.crypto.padded_key(key, symbols)

返回 symbols 的不同字符的字符串,其中 key 的字符优先出现。如果 symbols 中存在重复字符或 key 中存在不在 symbols 中的字符,则引发 ValueError。

示例

>>> from sympy.crypto.crypto import padded_key
>>> padded_key('PUPPY', 'OPQRSTUVWXY')
'PUYOQRSTVWX'
>>> padded_key('RSA', 'ARTIST')
Traceback (most recent call last):
...
ValueError: duplicate characters in symbols: T 
sympy.crypto.crypto.check_and_join(phrase, symbols=None, filter=None)

连接 phrase 的字符,并且如果给定了 symbols,则如果 phrase 中的任何字符不在 symbols 中,则引发错误。

参数:

phrase

要作为字符串返回的字符串或字符串列表。

symbols

phrase 中允许的字符的可迭代。

如果 symbolsNone,则不执行检查。

示例

>>> from sympy.crypto.crypto import check_and_join
>>> check_and_join('a phrase')
'a phrase'
>>> check_and_join('a phrase'.upper().split())
'APHRASE'
>>> check_and_join('a phrase!'.upper().split(), 'ARE', filter=True)
'ARAE'
>>> check_and_join('a phrase!'.upper().split(), 'ARE')
Traceback (most recent call last):
...
ValueError: characters in phrase but not symbols: "!HPS" 
sympy.crypto.crypto.cycle_list(k, n)

返回列表 range(n) 的元素,左移 k 位(因此列表从 k(模 n)开始)。

示例

>>> from sympy.crypto.crypto import cycle_list
>>> cycle_list(3, 10)
[3, 4, 5, 6, 7, 8, 9, 0, 1, 2] 
sympy.crypto.crypto.encipher_shift(msg, key, symbols=None)

在明文 msg 上执行移位密码加密,并返回密文。

参数:

key :整数

秘密密钥。

msg :字符串

大写字母的明文。

返回:

字符串

大写字母的密文。

示例

>>> from sympy.crypto.crypto import encipher_shift, decipher_shift
>>> msg = "GONAVYBEATARMY"
>>> ct = encipher_shift(msg, 1); ct
'HPOBWZCFBUBSNZ' 

要解密移位文本,请更改密钥的符号:

>>> encipher_shift(ct, -1)
'GONAVYBEATARMY' 

还有一个方便的功能,可以使用原始密钥执行此操作:

>>> decipher_shift(ct, 1)
'GONAVYBEATARMY' 

注意事项

算法:

步骤:

  1. 从字母表中编号字母从 0 到 N
  2. 从字符串 msg 计算对应整数列表 L1
  3. 从列表 L1 计算新列表 L2,由 L1 中的每个元素加上 (k mod 26) 组成。
  4. 从列表 L2 计算对应字母的字符串 ct

移位密码也称为凯撒密码,以朱利叶斯·凯撒命名,据苏埃托尼乌斯说,他用 3 个移位来保护军事重要消息。据报道,凯撒的侄子奥古斯都也使用了类似的密码,但右移 1 位。

另请参阅

decipher_shift

参考文献

[R151]

en.wikipedia.org/wiki/Caesar_cipher

[R152]

mathworld.wolfram.com/CaesarsMethod.html

sympy.crypto.crypto.decipher_shift(msg, key, symbols=None)

通过将msg的字符向左移动key给定的量来返回文本。

示例

>>> from sympy.crypto.crypto import encipher_shift, decipher_shift
>>> msg = "GONAVYBEATARMY"
>>> ct = encipher_shift(msg, 1); ct
'HPOBWZCFBUBSNZ' 

要解密移位后的文本,改变密钥的符号:

>>> encipher_shift(ct, -1)
'GONAVYBEATARMY' 

或使用原始密钥使用此函数:

>>> decipher_shift(ct, 1)
'GONAVYBEATARMY' 
sympy.crypto.crypto.encipher_rot13(msg, symbols=None)

对给定的明文msg执行 ROT13 加密。

说明

ROT13 是一种替换密码,将明文消息中的每个字母替换为英语字母表中距离最远的字母。

等效地,它只是一个移位密码,其移位键为 13(字母表的中间点)。

另请参阅

decipher_rot13, encipher_shift

参考文献

[R153]

en.wikipedia.org/wiki/ROT13

sympy.crypto.crypto.decipher_rot13(msg, symbols=None)

对给定的明文msg执行 ROT13 解密。

说明

decipher_rot13encipher_rot13等效,因为decipher_shift使用密钥 13 和encipher_shift使用密钥 13 将返回相同的结果。尽管如此,decipher_rot13在这里仍然明确定义以保持一致性。

示例

>>> from sympy.crypto.crypto import encipher_rot13, decipher_rot13
>>> msg = 'GONAVYBEATARMY'
>>> ciphertext = encipher_rot13(msg);ciphertext
'TBANILORNGNEZL'
>>> decipher_rot13(ciphertext)
'GONAVYBEATARMY'
>>> encipher_rot13(msg) == decipher_rot13(msg)
True
>>> msg == decipher_rot13(ciphertext)
True 
sympy.crypto.crypto.encipher_affine(msg, key, symbols=None, _inverse=False)

对明文msg执行仿射密码加密,并返回密文。

参数:

msg : str

出现在symbols中的字符。

a, b : int, int

一对整数,其中gcd(a, N) = 1(秘密密钥)。

符号

字符串的字符(默认=大写字母)。

如果没有给出符号,则将msg转换为大写字母,并忽略所有其他字符。

返回:

ct

字符串的字符(密文消息)

说明

加密基于映射(x \rightarrow ax+b)(mod (N)),其中N是字母表中的字符数。解密基于映射(x \rightarrow cx+d)(mod (N)),其中(c = a^{-1})(mod (N))和(d = -a^{-1}b)(mod (N))。特别地,为了使映射可逆,我们需要(\mathrm{gcd}(a, N) = 1),如果不是这样将会引发错误。

注释

算法:

步骤:

  1. 将字母从 0 到 N 编号
  2. 从字符串msg计算相应整数列表L1
  3. 从列表L1计算一个新列表L2,替换每个元素xa*x + b (mod N)
  4. 从列表L2计算字符串ct的对应字母。

这是移位密码的简单概括,增加了需要解密两个字符才能恢复密钥的复杂性。

参见

decipher_affine

References

[R154]

en.wikipedia.org/wiki/Affine_cipher

sympy.crypto.crypto.decipher_affine(msg, key, symbols=None)

返回由映射制成的解密文本,其中映射为 (x \rightarrow ax+b) (mod (N)),其中 N 是字母表中的字符数。解密通过使用新密钥进行重新加密完成:(x \rightarrow cx+d) (mod (N)),其中 (c = a^{-1}) (mod (N)) 且 (d = -a^{-1}b) (mod (N))。

Examples

>>> from sympy.crypto.crypto import encipher_affine, decipher_affine
>>> msg = "GO NAVY BEAT ARMY"
>>> key = (3, 1)
>>> encipher_affine(msg, key)
'TROBMVENBGBALV'
>>> decipher_affine(_, key)
'GONAVYBEATARMY' 

参见

encipher_affine

sympy.crypto.crypto.encipher_atbash(msg, symbols=None)

将给定的msg加密为其 Atbash 密码文本并返回。

Explanation

Atbash 是最初用于加密希伯来字母表的代换密码。Atbash 的工作原理是将每个字母映射到其反向/对应物(即 a 映射到 z,b 映射到 y 等)。

Atbash 在功能上等同于具有 a = 25b = 25 的仿射密码。

参见

decipher_atbash

sympy.crypto.crypto.decipher_atbash(msg, symbols=None)

使用 Atbash 密码解密给定的msg并返回结果。

Explanation

decipher_atbash 在功能上等同于 encipher_atbash。然而,它仍然作为一个单独的函数添加以保持一致性。

Examples

>>> from sympy.crypto.crypto import encipher_atbash, decipher_atbash
>>> msg = 'GONAVYBEATARMY'
>>> encipher_atbash(msg)
'TLMZEBYVZGZINB'
>>> decipher_atbash(msg)
'TLMZEBYVZGZINB'
>>> encipher_atbash(msg) == decipher_atbash(msg)
True
>>> msg == encipher_atbash(encipher_atbash(msg))
True 

参见

encipher_atbash

References

[R155]

en.wikipedia.org/wiki/Atbash

sympy.crypto.crypto.encipher_substitution(msg, old, new=None)

返回通过使用old中定义的替换替换每个出现的字符而获得的密文。如果old是一个映射,则忽略new并使用old定义的替换。

Explanation

这比仿射密码更一般化,因为密钥只能通过确定每个符号的映射来恢复。尽管在实践中,一旦识别了几个符号,其他字符的映射可以很快地猜出。

Examples

>>> from sympy.crypto.crypto import encipher_substitution, AZ
>>> old = 'OEYAG'
>>> new = '034⁶'
>>> msg = AZ("go navy! beat army!")
>>> ct = encipher_substitution(msg, old, new); ct
'60N^V4B3^T^RM4' 

要解密代换,反转最后两个参数:

>>> encipher_substitution(ct, new, old)
'GONAVYBEATARMY' 

oldnew 是 2 阶置换(表示字符置换)的特殊情况下,它们的顺序是无关紧要的:

>>> old = 'NAVY'
>>> new = 'ANYV'
>>> encipher = lambda x: encipher_substitution(x, old, new)
>>> encipher('NAVY')
'ANYV'
>>> encipher(_)
'NAVY' 

代换密码通常是一种方法,按照规则系统将明文的“单元”(不一定是单个字符)替换为密文。

>>> ords = dict(zip('abc', ['\\%i' % ord(i) for i in 'abc']))
>>> print(encipher_substitution('abc', ords))
\97\98\99 

References

[R156]

en.wikipedia.org/wiki/Substitution_cipher

sympy.crypto.crypto.encipher_vigenere(msg, key, symbols=None)

对明文 msg 执行维吉尼亚密码加密,并返回密文。

Examples

>>> from sympy.crypto.crypto import encipher_vigenere, AZ
>>> key = "encrypt"
>>> msg = "meet me on monday"
>>> encipher_vigenere(msg, key)
'QRGKKTHRZQEBPR' 

CIA 总部的 Kryptos 雕塑第一部分使用此密码,并且还改变了字母表的顺序[R158]。以下是该雕塑部分的第一行:

>>> from sympy.crypto.crypto import decipher_vigenere, padded_key
>>> alp = padded_key('KRYPTOS', AZ())
>>> key = 'PALIMPSEST'
>>> msg = 'EMUFPHZLRFAXYUSDJKZLDKRNSHGNFIVJ'
>>> decipher_vigenere(msg, key, alp)
'BETWEENSUBTLESHADINGANDTHEABSENC' 

Explanation

维吉尼亚密码因历史原因被称为布莱斯·德·维吉尼亚,一位 16 世纪的外交家和密码学家。实际上,维吉尼亚实际上发明了一种不同且更复杂的密码。所谓的维吉尼亚密码实际上是由乔瓦尼·巴蒂斯塔·贝拉索于 1553 年发明的。

这种密码在 19 世纪被使用,例如在美国内战期间。南方联盟使用黄铜密码盘实现了维吉尼亚密码(现在展览在 NSA 博物馆中的 Fort Meade)[R157]。

维吉尼亚密码是移位密码的一种推广。而移位密码每个字母的移位量是相同的(移位密码的密钥),维吉尼亚密码则是由密钥决定字母的移位量(这是发件人和收件人唯一知道的单词或短语)。

例如,如果密钥是单个字母,比如“C”,那么所谓的维吉尼亚密码实际上是一种移位密码,移位量为(2)(因为“C”是字母表中的第 2 个字母,从 0 开始计数)。如果密钥是两个字母的单词,比如“CA”,那么所谓的维吉尼亚密码将会将偶数位置的字母向右移动(2)个位置,奇数位置的字母保持不变(移位(0),因为“A”是字母表中的第 0 个字母,从 0 开始计数)。

算法:

输入:

msg: 字符串,出现在symbols(明文)中的字符

key: 字符串,出现在symbols(密钥)中的字符

symbols: 字母串,定义字母表

输出:

ct: 字符串,字符(密文消息)

步骤:

  1. 将字母表中的字母编号为 0,…,N
  2. 从字符串key计算对应整数列表L1。令n1 = len(L1)
  3. 从字符串msg计算对应整数列表L2。令n2 = len(L2)
  4. L2按大小为n1的子列表顺序分解;最后一个子列表可能比n1
  5. 对于L2的每个子列表L,计算一个新列表C,给定为C[i] = L[i] + L1[i] (mod N)到子列表中的第i个元素,对于每个i
  6. 将这些列表C通过串联成一个长度为n2的新列表。
  7. 从新列表计算对应字母串ct

一旦知道密钥长度为(n)个字符,可以对密文的每第(n)个字母应用频率分析来确定明文。这种方法称为Kasiski 检查(尽管它最初由巴贝奇发现)。如果密钥与消息一样长,并由随机选择的字符组成——一次性密码本——则理论上消息是不可破解的。

维吉尼亚密码实际上发现的是一种“自动密钥”密码,如下所述。

算法:

输入:

key: 字母串,(密钥)

msg: 字母串,(明文消息)

输出:

ct: 大写字母串,(密文消息)

步骤:

  1. 将字母表中的字母编号为 0,…,N
  2. 从字符串 msg 计算一个与之对应的整数列表 L2。设 n2 = len(L2)
  3. n1 是密钥的长度。将明文消息的前 n2 - n1 个字符附加到字符串 key,计算这个长度为 n2 的字符串(也是长度为 n2 的字符串),得到一个与第一步中字母号对应的整数列表 L1
  4. 计算一个新列表 C,其定义为 C[i] = L1[i] + L2[i] (mod N)
  5. 从新列表 C 计算一个与新整数对应的字母字符串 ct

为了解密自动密钥的密文,使用密钥来解密前 n1 个字符,然后这些字符成为解密下一个 n1 个字符的密钥,依此类推。

>>> m = AZ('go navy, beat army! yes you can'); m
'GONAVYBEATARMYYESYOUCAN'
>>> key = AZ('gold bug'); n1 = len(key); n2 = len(m)
>>> auto_key = key + m[:n2 - n1]; auto_key
'GOLDBUGGONAVYBEATARMYYE'
>>> ct = encipher_vigenere(m, auto_key); ct
'MCYDWSHKOGAMKZCELYFGAYR'
>>> n1 = len(key)
>>> pt = []
>>> while ct:
...     part, ct = ct[:n1], ct[n1:]
...     pt.append(decipher_vigenere(part, key))
...     key = pt[-1]
...
>>> ''.join(pt) == m
True 

References

[R157] (1,2)

en.wikipedia.org/wiki/Vigenere_cipher

[R158] (1,2)

web.archive.org/web/20071116100808/https://filebox.vt.edu/users/batman/kryptos.html(短链接:goo.gl/ijr22d

sympy.crypto.crypto.decipher_vigenere(msg, key, symbols=None)

使用维吉尼亚密码解密。

Examples

>>> from sympy.crypto.crypto import decipher_vigenere
>>> key = "encrypt"
>>> ct = "QRGK kt HRZQE BPR"
>>> decipher_vigenere(ct, key)
'MEETMEONMONDAY' 
sympy.crypto.crypto.encipher_hill(msg, key, symbols=None, pad='Q')

返回 msg 的 Hill 密码加密。

Parameters:

msg

n 个大写字母的明文消息。

key

一个 (k \times k) 可逆矩阵 (K),其所有条目都在 (Z_{26}) 中(或者所用符号的任何数量中)。

pad

字符(默认为“Q”)用于使文本长度为 k 的倍数。

Returns:

ct

大写字母的密文。

Explanation

Hill 密码 [R159],由莱斯特·希尔在 1920 年代发明 [R160],是第一个可以同时处理超过三个符号的多图密码。以下讨论假设对矩阵有基本的了解。

首先,每个字母都被编码为从 0 开始的一个数字。假设您的消息 msgn 个大写字母组成,没有空格。这可以看作是 n 元组 M,其元素属于 Z_{26}(如果字母是英语字母)。在 Hill 密码中,一个密钥是一个 (k \times k) 矩阵 K,其所有条目都在 Z_{26} 中,并且矩阵 K 可逆(即,线性变换 K: Z_{N}^k \rightarrow Z_{N}^k 是一对一的)。

Notes

ALGORITHM:

STEPS:

  1. 将字母从 0 到 N 编号
  2. 从字符串 msg 计算一个与之对应的整数列表 L。设 n = len(L)
  3. 将列表 L 分解为 t = ceiling(n/k) 个大小为 k 的子列表 L_1, …, L_t(最后一个列表被“填充”以确保其大小为 k)。
  4. 计算新列表 C_1, …, C_t,其定义为 C[i] = K*L_i(所有的算术都在模 N 下进行),对每个 i
  5. 将它们连接成一个列表 C = C_1 + ... + C_t
  6. C 计算一个长度为 k*t 的字符串 ct,其对应于相应的字母。

See also

decipher_hill

References

[R159] (1,2)

en.wikipedia.org/wiki/Hill_cipher

[R160] (1,2)

Lester S. Hill,《代数字母表中的密码学》,《美国数学月刊》第 36 卷,1929 年 6 月至 7 月,第 306-312 页。

sympy.crypto.crypto.decipher_hill(msg, key, symbols=None)

解密与加密相同,但使用密钥矩阵的逆。

示例

>>> from sympy.crypto.crypto import encipher_hill, decipher_hill
>>> from sympy import Matrix 
>>> key = Matrix([[1, 2], [3, 5]])
>>> encipher_hill("meet me on monday", key)
'UEQDUEODOCTCWQ'
>>> decipher_hill(_, key)
'MEETMEONMONDAY' 

当明文长度(去除无效字符)不是密钥维度的倍数时,加密和解密文本的末尾将出现额外字符。为了解密文本,这些字符必须包含在待解密的文本中。接下来,密钥的维度为 4,但文本缺少 4 的倍数,因此将添加两个字符。

>>> key = Matrix([[1, 1, 1, 2], [0, 1, 1, 0],
...               [2, 2, 3, 4], [1, 1, 0, 1]])
>>> msg = "ST"
>>> encipher_hill(msg, key)
'HJEB'
>>> decipher_hill(_, key)
'STQQ'
>>> encipher_hill(msg, key, pad="Z")
'ISPK'
>>> decipher_hill(_, key)
'STZZ' 

如果忽略了密文的最后两个字符,则无论如何都会恢复错误的明文:

>>> decipher_hill("HD", key)
'ORMV'
>>> decipher_hill("IS", key)
'UIKY' 

参见

encipher_hill

sympy.crypto.crypto.encipher_bifid(msg, key, symbols=None)

对明文 msg 进行 Bifid 密码加密,并返回密文。

这是使用 (n \times n) Polybius 方阵的 Bifid 密码的版本。

参数:

消息

明文字符串。

密钥

密钥的简短字符串。

忽略重复字符,然后用 symbols 中不在短密钥中的字符填充。

符号

(n \times n) 字符定义字母表。

(默认为 string.printable)

返回:

密文

使用 Bifid5 密码的无空格密文。

参见

decipher_bifid, encipher_bifid5, encipher_bifid6

参考文献

[R161]

en.wikipedia.org/wiki/Bifid_cipher

sympy.crypto.crypto.decipher_bifid(msg, key, symbols=None)

对密文 msg 进行 Bifid 密码解密,并返回明文。

这是使用 (n \times n) Polybius 方阵的 Bifid 密码的版本。

参数:

消息

密文字符串。

密钥

密钥的简短字符串。

忽略重复字符,然后用不在短密钥中的符号填充。

符号

(n \times n) 字符定义字母表。

(默认=string.printable,一个 (10 \times 10) 矩阵)

返回:

解密

解密后的文本。

示例

>>> from sympy.crypto.crypto import (
...     encipher_bifid, decipher_bifid, AZ) 

使用 bifid5 字母表进行加密:

>>> alp = AZ().replace('J', '')
>>> ct = AZ("meet me on monday!")
>>> key = AZ("gold bug")
>>> encipher_bifid(ct, key, alp)
'IEILHHFSTSFQYE' 

在输入文本或密文时,忽略空格,以便根据需要格式化。重新输入上述密文,每行放置 4 个字符并用额外的 J 填充,不会导致解密问题:

>>> decipher_bifid('''
... IEILH
... HFSTS
... FQYEJ''', key, alp)
'MEETMEONMONDAY' 

当没有给出字母表时,将使用所有 100 个可打印字符:

>>> key = ''
>>> encipher_bifid('hello world!', key)
'bmtwmg-bIo*w'
>>> decipher_bifid(_, key)
'hello world!' 

如果更改密钥,则会获得不同的加密结果:

>>> key = 'gold bug'
>>> encipher_bifid('hello world!', 'gold_bug')
'hg2sfuei7t}w' 

如果用于解密消息的密钥不完全匹配,原始文本将无法完美获取:

>>> decipher_bifid(_, 'gold pug')
'heldo~wor6d!' 
sympy.crypto.crypto.bifid5_square(key=None)

5x5 Polybius 方阵。

生成 (5 \times 5) Bifid 密码的 Polybius 方阵。

例子

>>> from sympy.crypto.crypto import bifid5_square
>>> bifid5_square("gold bug")
Matrix([
[G, O, L, D, B],
[U, A, C, E, F],
[H, I, K, M, N],
[P, Q, R, S, T],
[V, W, X, Y, Z]]) 
sympy.crypto.crypto.encipher_bifid5(msg, key)

执行 Bifid 密码加密以获得明文 msg 的结果,并返回密文。

参数:

消息:str

明文字符串。

转换为大写并过滤掉除了所有字母之外的任何东西。

密钥

用于密钥的短字符串;忽略非字母字符、J 和重复字符,如果长度少于 25 个字符,则用字母表中的其他字母(按字母顺序)填充。

返回:

ct

密文(全大写,无空格)。

解释

这是使用 (5 \times 5) Polybius 方阵的 Bifid 密码的版本。字母“J”被忽略,因此在加密之前必须用其他东西替换(传统上是“I”)。

算法:(5x5 情况)

步骤:

  1. 创建与 key 相关的 (5 \times 5) Polybius 方阵 S 的方式如下:
    1. 从左到右,从上到下,将密钥的字母放入一个 (5 \times 5) 矩阵中,
    2. 如果密钥少于 25 个字母,添加字母表中不在密钥中的字母,直到填满 (5 \times 5) 方阵。
  2. 创建 msg 中字母在 Polybius 方阵中的坐标对的列表 P
  3. L1P 的所有第一个坐标的列表(L1 的长度为 n),L2P 的所有第二个坐标的列表(因此 L2 的长度也为 n)。
  4. LL1L2 的连接(长度为 L = 2*n),但连续的数字成对出现 (L[2*i], L[2*i + 1])。您可以将 L 视为长度为 n 的对的列表。
  5. C 为形如 S[i, j] 的所有字母的列表,对于所有 (i, j) 属于 L。作为字符串,这是 msg 的密文。

例子

>>> from sympy.crypto.crypto import (
...     encipher_bifid5, decipher_bifid5) 

“J” 将被省略,除非用其他内容替换:

>>> round_trip = lambda m, k: \
...     decipher_bifid5(encipher_bifid5(m, k), k)
>>> key = 'a'
>>> msg = "JOSIE"
>>> round_trip(msg, key)
'OSIE'
>>> round_trip(msg.replace("J", "I"), key)
'IOSIE'
>>> j = "QIQ"
>>> round_trip(msg.replace("J", j), key).replace(j, "J")
'JOSIE' 

注释

Bifid 密码是由 Felix Delastelle 大约在 1901 年发明的。它是一种 分数替代 密码,其中字母被较小字母表中的一对符号替换。该密码使用填充了字母顺序的 (5 \times 5) 方阵,除了将“J”替换为“I”之外(这是所谓的 Polybius 方阵;如果添加回“J”并且在通常的 26 个字母表后附加数字 0、1、…、9,则有一个 (6 \times 6) 的类似物)。根据 Helen Gaines 的书籍 Cryptanalysis,这种类型的密码曾被第一次世界大战期间的德国军队使用。

另请参阅

decipher_bifid5, encipher_bifid

sympy.crypto.crypto.decipher_bifid5(msg, key)

返回 msg 的 Bifid 密码解密。

参数:

消息

密文字符串。

密钥

用于密钥的短字符串;忽略重复字符,并且如果长度小于 25 个字符,则用字母表中排除“J”的其他字母填充。

返回:

明文

Plaintext from Bifid5 cipher (all caps, no spaces).

解释

这是使用(5 \times 5) Polybius 方阵的 Bifid 密码版本;除非使用长度为 25 的key,否则字母“J”将被忽略。

示例

>>> from sympy.crypto.crypto import encipher_bifid5, decipher_bifid5
>>> key = "gold bug"
>>> encipher_bifid5('meet me on friday', key)
'IEILEHFSTSFXEE'
>>> encipher_bifid5('meet me on monday', key)
'IEILHHFSTSFQYE'
>>> decipher_bifid5(_, key)
'MEETMEONMONDAY' 
sympy.crypto.crypto.encipher_bifid6(msg, key)

对明文msg执行 Bifid 密码加密,并返回密文。

这是使用(6 \times 6) Polybius 方阵的 Bifid 密码版本。

参数:

msg

明文字符串(允许数字)。

key

用于密钥的简短字符串(允许数字)。

如果key长度小于 36 个字符,方阵将填充字母 A 到 Z 和数字 0 到 9。

返回:

密文

来自 Bifid 密码的密文(全大写,无空格)。

另请参阅

decipher_bifid6encipher_bifid

sympy.crypto.crypto.decipher_bifid6(msg, key)

对密文msg执行 Bifid 密码解密,并返回明文。

这是使用(6 \times 6) Polybius 方阵的 Bifid 密码版本。

参数:

msg

密文字符串(允许数字);转换为大写

key

用于密钥的简短字符串(允许数字)。

如果key长度小于 36 个字符,方阵将填充字母 A 到 Z 和数字 0 到 9。所有字母均转换为大写。

返回:

明文

来自 Bifid 密码的明文(全大写,无空格)。

示例

>>> from sympy.crypto.crypto import encipher_bifid6, decipher_bifid6
>>> key = "gold bug"
>>> encipher_bifid6('meet me on monday at 8am', key)
'KFKLJJHF5MMMKTFRGPL'
>>> decipher_bifid6(_, key)
'MEETMEONMONDAYAT8AM' 
sympy.crypto.crypto.bifid6_square(key=None)

6x6 Polybius 方阵。

生成(6 \times 6) Bifid 密码的 Polybius 方阵。假设符号的字母表是“A”,…,“Z”,“0”,…,“9”。

示例

>>> from sympy.crypto.crypto import bifid6_square
>>> key = "gold bug"
>>> bifid6_square(key)
Matrix([
[G, O, L, D, B, U],
[A, C, E, F, H, I],
[J, K, M, N, P, Q],
[R, S, T, V, W, X],
[Y, Z, 0, 1, 2, 3],
[4, 5, 6, 7, 8, 9]]) 
sympy.crypto.crypto.rsa_public_key(*args, **kwargs)

返回 RSA 的公钥对,((n, e))

参数:

args:自然数

如果指定为(p, q, e),其中(p)和(q)是不同的素数,(e)是 RSA 的所需公共指数,则(n = p q),(e)将针对欧拉函数(\phi(n))或卡米歇尔函数(\lambda(n))进行验证,以确保(\gcd(e, \phi(n)) = 1)或(\gcd(e, \lambda(n)) = 1)。

如果指定为(p_1, p_2, \dots, p_n, e),其中(p_1, p_2, \dots, p_n)被指定为素数,(e)被指定为 RSA 的所需公共指数,则能够形成多素数 RSA,这是流行的双素数 RSA 的更广义形式。

还可以通过将参数指定为(p, e)来形成单素数 RSA,这可以被看作是多素数 RSA 的特例。

此外,还可以通过指定两个或更多对相同的素数来形成多功率 RSA。但是,与双不同素数 RSA 或多素数 RSA 不同,完全剩余系统((\mathbb{Z}n))中的每个数字都将无法解密,因为映射(\mathbb{Z} \rightarrow \mathbb{Z}_{n})不是双射的。(只有在(e = 1)或更一般地时除外,

[e \in \left { 1 + k \lambda(n) \mid k \in \mathbb{Z} \land k \geq 0 \right }]

当 RSA 归结为恒等式时。)但是,RSA 仍然可以解密在减少的剩余系统((\mathbb{Z}n{\times}))中的数字,因为映射(\mathbb{Z}_{n} \rightarrow \mathbb{Z}^{\times})仍然可以是双射。

如果将非素数整数传递给参数(p_1, p_2, \dots, p_n),则该特定数将被素数因子化,并且它将成为其规范形式中的多素数 RSA 或多功率 RSA,具体取决于乘积是否等于其基数或不等。(p_1 p_2 \dots p_n = \text{rad}(p_1 p_2 \dots p_n))

totient:布尔值,可选

如果是'欧拉',它使用欧拉的欧拉函数 (\phi(n)),即sympy.functions.combinatorial.numbers.totient() 在 SymPy 中。

如果是'卡迈克尔',它使用卡迈克尔的欧拉函数 (\lambda(n)),即sympy.functions.combinatorial.numbers.reduced_totient() 在 SymPy 中。

与私钥生成不同,这是公钥生成的一个微不足道的关键字,因为(\gcd(e, \phi(n)) = 1 \iff \gcd(e, \lambda(n)) = 1)。

index:非负整数,可选

返回指定在(0, 1, 2, \dots)处的 RSA 公钥的任意解。此参数需要与totient='Carmichael'一起指定。

与描述rsa_private_key()中的index参数文档的 RSA 私钥的非唯一性类似,RSA 公钥也不唯一,并且有无限多个可以以相同方式运行的 RSA 公共指数。

对于任何给定的 RSA 公共指数(e),都可以有另一个 RSA 公共指数(e + k \lambda(n)),其中(k)是整数,(\lambda)是卡迈克尔的欧拉函数。

然而,仅考虑正数情况,可以有 RSA 公共指数(e_0)的主要解,在(0 < e_0 < \lambda(n)),并且所有其他解可以以(e_0 + k \lambda(n))的形式规范化。

index指定(k)表示法,以产生 RSA 公钥可能具有的任何可能值。

计算任意 RSA 公钥的示例:

>>> from sympy.crypto.crypto import rsa_public_key>>> rsa_public_key(61, 53, 17, totient='Carmichael', index=0)(3233, 17)>>> rsa_public_key(61, 53, 17, totient='Carmichael', index=1)(3233, 797)>>> rsa_public_key(61, 53, 17, totient='Carmichael', index=2)(3233, 1577) 

multipower:布尔值,可选

在 RSA 规范中找到的任何非不同素数对将限制密码系统的域,如args参数说明中所述。

SymPy RSA 密钥生成器在将其分发为多功率 RSA 之前可能会发出警告,但是,如果将True传递给此关键字,可以禁用警告。

返回:

(n, e):整数,整数

(n)是给定作为参数的任意数量的素数的乘积。

(e)与欧拉函数(\phi(n))是相对素数(互质)的。

错误

如果给出的参数少于两个或 (e) 与模数不互质,则返回。

示例

>>> from sympy.crypto.crypto import rsa_public_key 

两素数 RSA 的公钥:

>>> p, q, e = 3, 5, 7
>>> rsa_public_key(p, q, e)
(15, 7)
>>> rsa_public_key(p, q, 30)
False 

多素数 RSA 的公钥:

>>> primes = [2, 3, 5, 7, 11, 13]
>>> e = 7
>>> args = primes + [e]
>>> rsa_public_key(*args)
(30030, 7) 

注意

尽管 RSA 可以推广到任意模数 (n),但使用两个大素数已经成为最流行的规范,因为两个大素数的乘积通常是相对于 (n) 的位数最难分解的。

但可能需要进一步了解每个素数分解算法的时间复杂度来验证该说法。

另请参阅

rsa_private_key, encipher_rsa, decipher_rsa

参考文献

[R162]

en.wikipedia.org/wiki/RSA_%28cryptosystem%29

[R163]

cacr.uwaterloo.ca/techreports/2006/cacr2006-16.pdf

[R164]

link.springer.com/content/pdf/10.1007/BFb0055738.pdf

[R165]

www.itiis.org/digital-library/manuscript/1381

sympy.crypto.crypto.rsa_private_key(*args, **kwargs)

返回 RSA 私钥 对,((n, d))

参数:

args : 自然数

该关键字与 rsa_public_key() 中的 args 相同。

totient : 布尔值,可选

如果是 'Euler',则使用欧拉的欧拉函数约定 (\phi(n)),即 SymPy 中的 sympy.functions.combinatorial.numbers.totient()

如果是 'Carmichael',则使用 Carmichael 的欧拉函数约定 (\lambda(n)),即 SymPy 中的 sympy.functions.combinatorial.numbers.reduced_totient()

对于私钥生成,可能会有一些输出差异,如下面的示例。

使用欧拉的示例:

>>> from sympy.crypto.crypto import rsa_private_key>>> rsa_private_key(61, 53, 17, totient='Euler')(3233, 2753) 

使用 Carmichael 的欧拉函数的示例:

>>> from sympy.crypto.crypto import rsa_private_key>>> rsa_private_key(61, 53, 17, totient='Carmichael')(3233, 413) 

index : 非负整数,可选

返回指定索引 (0, 1, 2, \dots) 处的 RSA 私钥的任意解。此参数需与 totient='Carmichael' 一起指定。

RSA 私钥指数是 (e d \mod \lambda(n) = 1) 的非唯一解,可以用 (d + k \lambda(n)) 的形式表示,其中 (d) 是另一个已计算的私钥指数,(\lambda) 是 Carmichael 的欧拉函数,(k) 是任意整数。

然而,仅考虑正面情况,RSA 私钥指数(d_0)在(0 < d_0 < \lambda(n))中可能有一个主要解,所有其他解可以被规范化为(d_0 + k \lambda(n))的形式。

index指定了(k)符号来产生 RSA 私钥可能有的任何可能值。

计算任意 RSA 私钥的示例:

>>> from sympy.crypto.crypto import rsa_private_key>>> rsa_private_key(61, 53, 17, totient='Carmichael', index=0)(3233, 413)>>> rsa_private_key(61, 53, 17, totient='Carmichael', index=1)(3233, 1193)>>> rsa_private_key(61, 53, 17, totient='Carmichael', index=2)(3233, 1973) 

多幂:布尔值,可选

关键字与rsa_public_key()中的multipower相同。

返回:

(n, d):整数,整数

(n)是作为参数给出的任意数量质数的乘积。

(d)是给定指数(e)的模(\phi(n))的逆,(\phi)是欧拉函数。

False

如果给出少于两个参数,或者(e)与模数的欧拉函数不互质,则返回。

示例

>>> from sympy.crypto.crypto import rsa_private_key 

双质数 RSA 的私钥:

>>> p, q, e = 3, 5, 7
>>> rsa_private_key(p, q, e)
(15, 7)
>>> rsa_private_key(p, q, 30)
False 

多质数 RSA 的私钥:

>>> primes = [2, 3, 5, 7, 11, 13]
>>> e = 7
>>> args = primes + [e]
>>> rsa_private_key(*args)
(30030, 823) 

另请参阅

rsa_public_keyencipher_rsadecipher_rsa的关键字。

参考文献

[R166]

en.wikipedia.org/wiki/RSA_%28cryptosystem%29

[R167]

cacr.uwaterloo.ca/techreports/2006/cacr2006-16.pdf

[R168]

link.springer.com/content/pdf/10.1007/BFb0055738.pdf

[R169]

www.itiis.org/digital-library/manuscript/1381

sympy.crypto.crypto.encipher_rsa(i, key, factors=None)

使用 RSA 加密明文。

参数:

i:整数

待加密的明文。

密钥:(n, e),其中 n、e 为整数

(n)是密钥的模数,(e)是密钥的指数。加密计算为(i^e \bmod n)。

密钥可以是公钥或私钥,但通过公钥加密的消息只能由私钥解密,反之亦然,因为 RSA 是一种非对称加密系统。

因子:互质整数列表

这与decipher_rsa()中的关键字factors相同。

注意

一些规范可能使 RSA 不具有密码学上的意义。

例如,(0),(1)在进行任意次幂后始终保持不变,因此应避免使用。

此外,如果(i^e < n),则(i)可能很容易通过取(e)次根来找到。

并且,将指数指定为(1)或更一般的形式,如(1 + k \lambda(n)),其中(k)是非负整数,(\lambda)是卡迈克尔欧拉函数,RSA 变成一个恒等映射。

示例

>>> from sympy.crypto.crypto import encipher_rsa
>>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key 

公钥加密:

>>> p, q, e = 3, 5, 7
>>> puk = rsa_public_key(p, q, e)
>>> msg = 12
>>> encipher_rsa(msg, puk)
3 

私钥加密:

>>> p, q, e = 3, 5, 7
>>> prk = rsa_private_key(p, q, e)
>>> msg = 12
>>> encipher_rsa(msg, prk)
3 

使用中国剩余定理加密:

>>> encipher_rsa(msg, prk, factors=[p, q])
3 
sympy.crypto.crypto.decipher_rsa(i, key, factors=None)

使用 RSA 解密密文。

参数:

i : 整数

要解密的密文。

key : (n, d),其中 n, d 是整数

(n) 是密钥的模数,(d) 是密钥的指数。解密通过 (i^d \bmod n) 计算。

密钥可以是公钥或私钥,然而,用公钥加密的消息只能用私钥解密,反之亦然,因为 RSA 是一种非对称加密系统。

factors : 互质整数列表

由于 RSA 密钥生成中创建的模数 (n) 由任意的素数因子组成 (n = {p_1}{k_1}{p_2}\dots{p_n}^{k_n}),其中 (p_1, p_2, \dots, p_n) 是不同的素数,(k_1, k_2, \dots, k_n) 是正整数,可以使用中国剩余定理从分段的模操作计算 (i^d \bmod n)。

[i^d \bmod {p_1}^{k_1}, i^d \bmod {p_2}^{k_2}, \dots, i^d \bmod {p_n}^{k_n}]

或者如下

[i^d \bmod {p_1}{k_1}{p_2}, i^d \bmod {p_3}^{k_3}, \dots , i^d \bmod {p_n}^{k_n}]

只要每个模数之间没有共同的除数。

用于生成 RSA 密钥对的原始素数可以是一个不错的选择。

注意使用此方法的速度优势仅适用于非常大的情况(如 2048 位 RSA 密钥),因为使用sympy.ntheory.modular.crt()的纯 Python 实现的开销可能超过了理论上的速度优势。

注释

encipher_rsa()的文档的Notes部分查看。

示例

>>> from sympy.crypto.crypto import decipher_rsa, encipher_rsa
>>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key 

公钥加密和解密:

>>> p, q, e = 3, 5, 7
>>> prk = rsa_private_key(p, q, e)
>>> puk = rsa_public_key(p, q, e)
>>> msg = 12
>>> new_msg = encipher_rsa(msg, prk)
>>> new_msg
3
>>> decipher_rsa(new_msg, puk)
12 

私钥加密和解密:

>>> p, q, e = 3, 5, 7
>>> prk = rsa_private_key(p, q, e)
>>> puk = rsa_public_key(p, q, e)
>>> msg = 12
>>> new_msg = encipher_rsa(msg, puk)
>>> new_msg
3
>>> decipher_rsa(new_msg, prk)
12 

使用中国剩余定理进行解密:

>>> decipher_rsa(new_msg, prk, factors=[p, q])
12 

参见

encipher_rsa

sympy.crypto.crypto.kid_rsa_public_key(a, b, A, B)

Kid RSA 是一种版本的 RSA,适合用来教授小学生,因为它不涉及指数运算。

解释

Alice 想要和 Bob 交流。Bob 生成密钥如下。密钥生成:

  • 随机选择正整数 (a, b, A, B)。

  • 计算 (M = a b - 1), (e = A M + a), (d = B M + b), (n = (e d - 1)//M)。

  • 公钥 是 ((n, e))。Bob 将这些发送给 Alice。

  • 私钥 是 ((n, d)), 这是 Bob 保密的。

加密:如果 (p) 是明文消息,则密文是 (c = p e \pmod n)。

解密:如果 (c) 是密文消息,则明文是 (p = c d \pmod n)。

示例

>>> from sympy.crypto.crypto import kid_rsa_public_key
>>> a, b, A, B = 3, 4, 5, 6
>>> kid_rsa_public_key(a, b, A, B)
(369, 58) 
sympy.crypto.crypto.kid_rsa_private_key(a, b, A, B)

计算 (M = a b - 1), (e = A M + a), (d = B M + b), (n = (e d - 1) / M)。私钥 是 (d), 这是 Bob 保密的。

示例

>>> from sympy.crypto.crypto import kid_rsa_private_key
>>> a, b, A, B = 3, 4, 5, 6
>>> kid_rsa_private_key(a, b, A, B)
(369, 70) 
sympy.crypto.crypto.encipher_kid_rsa(msg, key)

这里 msg 是明文,key 是公钥。

示例

>>> from sympy.crypto.crypto import (
...     encipher_kid_rsa, kid_rsa_public_key)
>>> msg = 200
>>> a, b, A, B = 3, 4, 5, 6
>>> key = kid_rsa_public_key(a, b, A, B)
>>> encipher_kid_rsa(msg, key)
161 
sympy.crypto.crypto.decipher_kid_rsa(msg, key)

这里 msg 是明文,key 是私钥。

示例

>>> from sympy.crypto.crypto import (
...     kid_rsa_public_key, kid_rsa_private_key,
...     decipher_kid_rsa, encipher_kid_rsa)
>>> a, b, A, B = 3, 4, 5, 6
>>> d = kid_rsa_private_key(a, b, A, B)
>>> msg = 200
>>> pub = kid_rsa_public_key(a, b, A, B)
>>> pri = kid_rsa_private_key(a, b, A, B)
>>> ct = encipher_kid_rsa(msg, pub)
>>> decipher_kid_rsa(ct, pri)
200 
sympy.crypto.crypto.encode_morse(msg, sep='|', mapping=None)

将明文编码为普通的摩斯密码,字母之间用 sep 分隔,单词之间用双 sep 分隔。

示例

>>> from sympy.crypto.crypto import encode_morse
>>> msg = 'ATTACK RIGHT FLANK'
>>> encode_morse(msg)
'.-|-|-|.-|-.-.|-.-||.-.|..|--.|....|-||..-.|.-..|.-|-.|-.-' 

参考

[R170]

en.wikipedia.org/wiki/Morse_code

sympy.crypto.crypto.decode_morse(msg, sep='|', mapping=None)

解码摩斯电码,字母用 sep(默认为‘|’)分隔,单词用 (word_sep)(默认为‘||’)分隔成纯文本。

示例

>>> from sympy.crypto.crypto import decode_morse
>>> mc = '--|---|...-|.||.|.-|...|-'
>>> decode_morse(mc)
'MOVE EAST' 

参考文献

[R171]

en.wikipedia.org/wiki/Morse_code

sympy.crypto.crypto.lfsr_sequence(key, fill, n)

此函数创建一个 LFSR 序列。

参数:

密钥:list

有限域元素列表,([c_0, c_1, \ldots, c_k])。

填充:list

LFSR 序列的初始项列表,([x_0, x_1, \ldots, x_k])。

n

函数返回的序列项数。

返回:

L

由 (x_{n+1} = c_k x_n + \ldots + c_0 x_{n-k}) 定义的 LFSR 序列,对于 (n \leq k)。

备注

S. Golomb [G171] 给出了一个数字序列 (a = {a_n}_{n=1}^\infty), (a_n \in {0,1}),应显示为“随机”的三个统计属性列表。定义 (a) 的自相关为

[C(k) = C(k,a) = \lim_{N\rightarrow \infty} {1\over N}\sum_{n=1}^N (-1)^{a_n + a_{n+k}}.]

如果 (a) 周期为 (P),则此情况下简化为

[C(k) = {1\over P}\sum_{n=1}^P (-1)^{a_n + a_{n+k}}.]

假设 (a) 是周期为 (P) 的周期性序列。

  • 平衡:

    [\left|\sum_{n=1}P(-1)\right| \leq 1.]

  • 低自相关:

    [\begin{split}C(k) = \left{ \begin{array}{cc} 1,& k = 0,\ \epsilon, & k \ne 0. \end{array} \right.\end{split}]

    (对于满足这两个属性的序列,已知必须满足 (\epsilon = -1/P)。)

  • 比例运行特性:在每个周期内,一半的运行长度为 (1),四分之一的运行长度为 (2),等等。此外,(1) 的运行数与 (0) 的运行数相同。

示例

>>> from sympy.crypto.crypto import lfsr_sequence
>>> from sympy.polys.domains import FF
>>> F = FF(2)
>>> fill = [F(1), F(1), F(0), F(1)]
>>> key = [F(1), F(0), F(0), F(1)]
>>> lfsr_sequence(key, fill, 10)
[1 mod 2, 1 mod 2, 0 mod 2, 1 mod 2, 0 mod 2,
1 mod 2, 1 mod 2, 0 mod 2, 0 mod 2, 1 mod 2] 

参考文献

[G171] (1,2)

Solomon Golomb, Shift register sequences, Aegean Park Press, Laguna Hills, Ca, 1967

sympy.crypto.crypto.lfsr_autocorrelation(L, P, k)

此函数计算 LFSR 自相关函数。

参数:

L

(GF(2)) 元素的周期序列。 L 必须比 P 长。

P

L 的周期。

k:int

一个整数 (k) ((0 < k < P))。

返回:

自相关

LFSR L 的自相关的第 k 个值。

示例

>>> from sympy.crypto.crypto import (
...     lfsr_sequence, lfsr_autocorrelation)
>>> from sympy.polys.domains import FF
>>> F = FF(2)
>>> fill = [F(1), F(1), F(0), F(1)]
>>> key = [F(1), F(0), F(0), F(1)]
>>> s = lfsr_sequence(key, fill, 20)
>>> lfsr_autocorrelation(s, 15, 7)
-1/15
>>> lfsr_autocorrelation(s, 15, 0)
1 
sympy.crypto.crypto.lfsr_connection_polynomial(s)

此函数计算 LFSR 连接多项式。

参数:

s

一个偶数长度的元素序列,其条目在有限域内。

返回:

C(x)

生成 s 的最小 LFSR 的连接多项式。

此处实现了 J. L. Massey 文章第三部分的算法 [M172]。

示例

>>> from sympy.crypto.crypto import (
...     lfsr_sequence, lfsr_connection_polynomial)
>>> from sympy.polys.domains import FF
>>> F = FF(2)
>>> fill = [F(1), F(1), F(0), F(1)]
>>> key = [F(1), F(0), F(0), F(1)]
>>> s = lfsr_sequence(key, fill, 20)
>>> lfsr_connection_polynomial(s)
x**4 + x + 1
>>> fill = [F(1), F(0), F(0), F(1)]
>>> key = [F(1), F(1), F(0), F(1)]
>>> s = lfsr_sequence(key, fill, 20)
>>> lfsr_connection_polynomial(s)
x**3 + 1
>>> fill = [F(1), F(0), F(1)]
>>> key = [F(1), F(1), F(0)]
>>> s = lfsr_sequence(key, fill, 20)
>>> lfsr_connection_polynomial(s)
x**3 + x**2 + 1
>>> fill = [F(1), F(0), F(1)]
>>> key = [F(1), F(0), F(1)]
>>> s = lfsr_sequence(key, fill, 20)
>>> lfsr_connection_polynomial(s)
x**3 + x + 1 

参考文献

[M172] (1,2)

James L. Massey, “Shift-Register Synthesis and BCH Decoding.” IEEE Trans. on Information Theory, vol. 15(1), pp. 122-127, Jan 1969.

sympy.crypto.crypto.elgamal_public_key(key)

以公钥返回三个数字元组。

参数:

密钥:(p, r, e)

elgamal_private_key 生成的元组。

返回:

元组:(p, r, e)

(e = r**d \bmod p)

(d) 是私钥中的随机数。

示例

>>> from sympy.crypto.crypto import elgamal_public_key
>>> elgamal_public_key((1031, 14, 636))
(1031, 14, 212) 
sympy.crypto.crypto.elgamal_private_key(digit=10, seed=None)

以私钥返回三个数字元组。

参数:

数字:int

密钥的最小二进制位数。

返回:

元组:(p, r, d)

p = 素数。

r = 原根。

d = 随机数。

说明

Elgamal 加密基于称为离散对数问题(DLP)的数学问题。例如,

(a^{b} \equiv c \pmod p)

一般来说,如果已知 ab,则很容易计算 ct。如果 b 是未知的,则很难使用 act 来获得 b

注释

为了测试目的,可以设置 seed 参数以控制此过程的输出。参见 sympy.core.random._randrange。

示例

>>> from sympy.crypto.crypto import elgamal_private_key
>>> from sympy.ntheory import is_primitive_root, isprime
>>> a, b, _ = elgamal_private_key()
>>> isprime(a)
True
>>> is_primitive_root(b, a)
True 
sympy.crypto.crypto.encipher_elgamal(i, key, seed=None)

使用公钥加密消息。

参数:

msg

编码消息的整数。

key

公钥。

返回:

tuple : (c1, c2)

将加密成两个数字。

说明

i是以整数表示的明文消息。 key是公钥(p,r,e)。为了加密消息,生成范围为 range(2, p) 中的随机数 a,并返回加密后的消息作为 (c_{1}) 和 (c_{2}),其中:

(c_{1} \equiv r^{a} \pmod p)

(c_{2} \equiv m e^{a} \pmod p)

注释

为了测试目的,可以设置 seed 参数以控制此过程的输出。参见 sympy.core.random._randrange。

示例

>>> from sympy.crypto.crypto import encipher_elgamal, elgamal_private_key, elgamal_public_key
>>> pri = elgamal_private_key(5, seed=[3]); pri
(37, 2, 3)
>>> pub = elgamal_public_key(pri); pub
(37, 2, 8)
>>> msg = 36
>>> encipher_elgamal(msg, pub, seed=[3])
(8, 6) 
sympy.crypto.crypto.decipher_elgamal(msg, key)

使用私钥解密消息。

(msg = (c_{1}, c_{2}))

(key = (p, r, d))

根据扩展欧几里得定理,(u c_{1}^{d} + p n = 1)

(u \equiv 1/{{c_{1}}^d} \pmod p)

(u c_{2} \equiv \frac{1}{c_{1}^d} c_{2} \equiv \frac{1}{r^{ad}} c_{2} \pmod p)

(\frac{1}{r^{ad}} m e^a \equiv \frac{1}{r^{ad}} m {r^{d a}} \equiv m \pmod p)

示例

>>> from sympy.crypto.crypto import decipher_elgamal
>>> from sympy.crypto.crypto import encipher_elgamal
>>> from sympy.crypto.crypto import elgamal_private_key
>>> from sympy.crypto.crypto import elgamal_public_key 
>>> pri = elgamal_private_key(5, seed=[3])
>>> pub = elgamal_public_key(pri); pub
(37, 2, 8)
>>> msg = 17
>>> decipher_elgamal(encipher_elgamal(msg, pub), pri) == msg
True 
sympy.crypto.crypto.dh_public_key(key)

返回三个数字元组作为公钥。

这是 Alice 发送给 Bob 的元组。

参数:

key : (p, g, a)

dh_private_key 生成的元组。

返回:

tuple : int, int, int

一个元组 ((p, g, g^a \mod p)),其中给定参数为 pga

示例

>>> from sympy.crypto.crypto import dh_private_key, dh_public_key
>>> p, g, a = dh_private_key();
>>> _p, _g, x = dh_public_key((p, g, a))
>>> p == _p and g == _g
True
>>> x == pow(g, a, p)
True 
sympy.crypto.crypto.dh_private_key(digit=10, seed=None)

返回三个整数元组作为私钥。

参数:

digit

钥匙所需的最小二进制位数。

返回:

tuple : (p, g, a)

p = 素数。

g = p 的原根。

a = 从 2 到 p-1 的随机数。

说明

Diffie-Hellman 密钥交换基于称为离散对数问题的数学问题(参见 ElGamal)。

Diffie-Hellman 密钥交换分为以下步骤:

  • Alice 和 Bob 同意一个基础,由素数 p 和称为 g 的原根组成。

  • Alice 选择一个数字 a,Bob 选择一个数字 b,其中 ab 是在范围 ([2, p)) 中的随机数。这些是他们的私钥。

  • Alice 公开发送 (g^{a} \pmod p) 给 Bob,而 Bob 向 Alice 发送 (g^{b} \pmod p)。

  • 他们都将接收到的值提升到他们秘密选择的数字(ab)上,现在两者都有 g^{ab} \pmod p 作为他们的共享密钥。

注释

为了测试目的,可以设置 seed 参数以控制此过程的输出。参见 sympy.core.random._randrange。

示例

>>> from sympy.crypto.crypto import dh_private_key
>>> from sympy.ntheory import isprime, is_primitive_root
>>> p, g, _ = dh_private_key()
>>> isprime(p)
True
>>> is_primitive_root(g, p)
True
>>> p, g, _ = dh_private_key(5)
>>> isprime(p)
True
>>> is_primitive_root(g, p)
True 
sympy.crypto.crypto.dh_shared_key(key, b)

返回一个整数,即共享密钥。

这是 Bob 和 Alice 可以使用彼此收到的公钥及其私钥计算的内容。

参数:

key : (p, g, x)

dh_public_key 生成的元组 ((p, g, x))。

b

在范围(2)到(p - 1)内的随机数(由第二个密钥交换成员(Bob)选择)。

返回:

int

共享密钥。

示例

>>> from sympy.crypto.crypto import (
...     dh_private_key, dh_public_key, dh_shared_key)
>>> prk = dh_private_key();
>>> p, g, x = dh_public_key(prk);
>>> sk = dh_shared_key((p, g, x), 1000)
>>> sk == pow(x, 1000, p)
True 
sympy.crypto.crypto.gm_public_key(p, q, a=None, seed=None)

计算pq的公钥。请注意,在 Goldwasser-Micali 加密中,公钥是随机选择的。

参数:

p, q, a:int, int, int

初始化变量。

返回:

tuple:(a, N)

如果a不为None,则a是输入的a,否则是一些与pq互质的随机整数。

Npq的乘积。

sympy.crypto.crypto.gm_private_key(p, q, a=None)

检查pq是否可以用作 Goldwasser-Micali 加密的私钥。该方法大致如下运行。

参数:

p, q, a

初始化变量。

返回:

tuple:(p, q)

输入值pq

引发:

ValueError

如果pq不是不同的奇素数。

解释

  1. 选择两个大素数(p)和(q)。

  2. 称它们的乘积为(N)。

  3. 给定一个整数消息(i),将(i)用其比特表示写成(b_0, \dots, b_n)。

  4. 对于每个(k),

如果(b_k = 0):

让(a_k)是一个随机平方数(二次剩余),模(p q),使得jacobi_symbol(a, p*q) = 1

如果(b_k = 1):

让(a_k)是一个随机的非平方数(非二次剩余),模(p q),使得jacobi_symbol(a, p*q) = 1

返回(\left[a_1, a_2, \dots\right])

(b_k)可以通过检查(a_k)是否是余数来恢复。并且从(b_k)中,消息可以被重建。

思路是,虽然jacobi_symbol(a, p*q)可以很容易计算(当等于(-1)时,表明(a)在模(p q)下不是二次剩余),但二次剩余性模一个复合数的难度在不知其因数分解的情况下很难计算。

此外,大约一半与(p q)互质的数具有jacobi_symbol()等于(1)。在这些数中,大约一半是剩余,大约一半不是。这最大化了代码的熵。

sympy.crypto.crypto.encipher_gm(i, key, seed=None)

使用公钥‘key’加密整数‘i’注意,gm 使用随机加密。

参数:

i:int

要加密的消息。

key:(a, N)

公钥。

返回:

list:int 列表

随机化的加密消息。

sympy.crypto.crypto.decipher_gm(message, key)

使用公钥‘key’解密消息‘message’。

参数:

message:int 列表

随机化的加密消息。

key:(p, q)

私钥。

返回:

int

加密后的消息。

sympy.crypto.crypto.encipher_railfence(message, rails)

在明文上执行栅栏加密并返回密文

参数:

message:string,要加密的消息。

rails:int,栏的数量。

返回:

加密后的字符串消息。

示例

>>> from sympy.crypto.crypto import encipher_railfence
>>> message = "hello world"
>>> encipher_railfence(message,3)
'horel ollwd' 

参考文献

[R174]

zh.wikipedia.org/wiki/铁栏加密

sympy.crypto.crypto.decipher_railfence(ciphertext, rails)

使用给定的栏解密消息

参数:

message:string,要加密的消息。

rails:int,栏的数量。

返回:

解密后的字符串消息。

示例

>>> from sympy.crypto.crypto import decipher_railfence
>>> decipher_railfence("horel ollwd",3)
'hello world' 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/732264.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SymPy-1-13-中文文档-二十-

SymPy 1.13 中文文档(二十)原文:docs.sympy.org/latest/index.html控制系统绘图原文:docs.sympy.org/latest/modules/physics/control/control_plots.html该模块包含用于控制系统中一些常见绘图的绘图函数。如果用户需要绘图,则需要外部依赖 Matplotlib。如果仅需获得绘图…

SciPy-1-12-中文文档-十八-

SciPy 1.12 中文文档(十八)原文:docs.scipy.org/doc/scipy-1.12.0/index.htmlscipy.special.fdtr原文:docs.scipy.org/doc/scipy-1.12.0/reference/generated/scipy.special.fdtr.html#scipy.special.fdtrscipy.special.fdtr(dfn, dfd, x, out=None) = <ufunc fdtr>F…

Centos7在已有python3.6的基础上安装python3.8

需要系统带有gcc和make wget http://www.python.org/ftp/python/3.8.13/Python-3.8.13.tgz tar -zxvf Python-3.8.13.tgz sudo mkdir -p /usr/local/python3.8 cd Python-3.8.13/# --prefix表示把编译好的python放到哪个地方 ./configure --prefix=/usr/local/python3.8 --enab…

zabbix提示链接数过多

一、先进入mysql查看连接数是多少mysql -uroot -p 输入密码 show variables like max_%; #查询连接 默认是一100, 二、改修msyql连接参数‘,先查配置文件在哪里mysql --help|morevim /etc/my.cnf.d/mysql-server.cnfmax_connections=1000 #新增这条参数 再重启一下mysq…

npm install pnpm问题解决方法

安装npm install -g pnpm 正确配置环境变量 在cmd输入: Start-Process powershell -Verb runAs 设置缓存路径: npm config set prefix "E:\nodejs\node_global"npm config set cache "E:\nodejs\node_cache" 解决方法: 设置执行策略: 检查策略: Get-E…

代理时响应头大小写区别

配置代理访问非代理访问

Cilium Native Routing with KubeProxyReplacement 模式

Cilium Native Routing with KubeProxyReplacement 模式Cilium Native Routing with KubeProxyReplacement 模式 一、环境信息主机 IPubuntu 172.16.94.141软件 版本docker 26.1.4helm v3.15.0-rc.2kind 0.18.0kubernetes 1.23.4ubuntu os Ubuntu 20.04.6 LTSkernel 5.11.5 内核…

OOP课程第三次Blog

一、 前言 本次博客是对于题目集7~8的总结和反思。 知识点 本阶段题目集的主要对之前所有知识进行综合考察,主要知识点包括封装、继承、多态,继承、抽象类和接口、List及泛型等。继承包括对super、extend关键字的使用,方法的重写等,多态包括向上转型、向下转型等。在设计上…

Linux 网卡端口 Bonding

通过将多个网卡端口聚合成一个虚拟端口,虚拟端口提供冗余及增加了链路带宽,参与聚合的网卡端口应连接到不同的网络交换机。Linux 网卡端口聚合主要有bonding、team技术,team 技术是 RHEL 7 推出的,由于其普及程度不高又没有优势在RHEL 9 版本中已经废弃,bonding 技术则更成…

2024好用的项目管理软件有哪些?这10款最火国内项目管理工具你应该知道

不管是大公司还是小公司,如果想提高企业运作效率、规范管理并且高效且实用的项目管理工具,对项目流程进行把控、及时共享工作进度,从而让工作变得更有效率。那么一款好用的项目管理工具必不可少。然而面对市场上这么多的项目管理工具,你是否感到疑惑,不知道选择哪款项目管…

古希腊字母书写和发音

Greek Alphabethttps://www.pw.live/maths-symbols https://www.youtube.com/watch?v=ZGvF1JSEu2I&t=14s

Ubuntu22.04下Docker中安装Mysql

1.Docker中拉起最新版本mysqldocker pull mysql结果出现: 解决方案:配置国内docker镜像源vi /etc/docker/daemon.json添加阿里云镜像源:{"registry-mirrors":["https://6kx4zyno.mirror.aliyuncs.com"]}重启命令systemctl daemon-reloadsystemctl resta…