胁迫¶
准备工作¶
什么是强迫?¶
强制的主要目标是能够透明地在不同集合的元素之间进行算术、比较等。
作为一个具体的例子 1 + 1/2 尽管左边是一个整数,但人们希望将操作数作为有理数执行算术运算。这是有意义的,因为在有理数中包含了明显和自然的整数。强制系统的目标是促进这一点(以及更复杂的算法),而不必显式地将所有内容映射到同一个域中,同时还要严格到不解决歧义或接受无稽之谈。以下是一些例子:
sage: 1 + 1/2
3/2
sage: R.<x,y> = ZZ[]
sage: R
Multivariate Polynomial Ring in x, y over Integer Ring
sage: parent(x)
Multivariate Polynomial Ring in x, y over Integer Ring
sage: parent(1/3)
Rational Field
sage: x+1/3
x + 1/3
sage: parent(x+1/3)
Multivariate Polynomial Ring in x, y over Rational Field
sage: GF(5)(1) + CC(I)
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for +: 'Finite Field of size 5' and 'Complex Field with 53 bits of precision'
父项和元素¶
父对象是具体类别中的对象,元素是其成员。父母是第一流的。Sage中的大多数事物不是父母就是有父母。通常只要你看到这个词 起源 一个人可以思考 Set . 以下是一些例子:
sage: parent(1)
Integer Ring
sage: parent(1) is ZZ
True
sage: ZZ
Integer Ring
sage: parent(1.50000000000000000000000000000000000)
Real Field with 120 bits of precision
sage: parent(x)
Symbolic Ring
sage: x^sin(x)
x^sin(x)
sage: R.<t> = Qp(5)[]
sage: f = t^3-5; f
(1 + O(5^20))*t^3 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + 4*5^5 + 4*5^6 + 4*5^7 + 4*5^8 + 4*5^9 + 4*5^10 + 4*5^11 + 4*5^12 + 4*5^13 + 4*5^14 + 4*5^15 + 4*5^16 + 4*5^17 + 4*5^18 + 4*5^19 + 4*5^20 + O(5^21)
sage: parent(f)
Univariate Polynomial Ring in t over 5-adic Field with capped relative precision 20
sage: f = EllipticCurve('37a').lseries().taylor_series(10); f # abs tol 1e-14
0.997997869801216 + 0.00140712894524925*z - 0.000498127610960097*z^2 + 0.000118835596665956*z^3 - 0.0000215906522442708*z^4 + (3.20363155418421e-6)*z^5 + O(z^6) # 32-bit
0.997997869801216 + 0.00140712894524925*z - 0.000498127610960097*z^2 + 0.000118835596665956*z^3 - 0.0000215906522442708*z^4 + (3.20363155418427e-6)*z^5 + O(z^6) # 64-bit
sage: parent(f)
Power Series Ring in z over Complex Field with 53 bits of precision
父母和类型之间有一个重要的区别:
sage: a = GF(5).random_element()
sage: b = GF(7).random_element()
sage: type(a)
<type 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>
sage: type(b)
<type 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>
sage: type(a) == type(b)
True
sage: parent(a)
Finite Field of size 5
sage: parent(a) == parent(b)
False
但是,非Sage对象并没有真正的父对象,但是我们仍然希望能够与它们进行推理,因此使用它们的类型来代替:
sage: a = int(10)
sage: parent(a)
<... 'int'>
实际上,在这种情况下,一种特殊的父类“T类的所有Python对象的集合”在这些情况下被使用。
请注意,父母是 not 总是尽可能的紧。
sage: parent(1/2)
Rational Field
sage: parent(2/1)
Rational Field
父母之间的映射¶
许多父母都带着往返于其他父母之间的地图。
Sage区分 转换 在不同的父母之间,以及 胁迫 他们之间。转换是显式的,如果可能的话,它会尝试理解目标域中的对象。通过调用调用:
sage: ZZ(5)
5
sage: ZZ(10/5)
2
sage: QQ(10)
10
sage: parent(QQ(10))
Rational Field
sage: a = GF(5)(2); a
2
sage: parent(a)
Finite Field of size 5
sage: parent(ZZ(a))
Integer Ring
sage: GF(71)(1/5)
57
sage: ZZ(1/2)
Traceback (most recent call last):
...
TypeError: no conversion of this rational to integer
转换不需要是规范的(例如,它们可能涉及升力的选择),甚至不需要在数学上有意义(例如某种结构)。
sage: ZZ("123")
123
sage: ZZ(GF(5)(14))
4
sage: ZZ['x']([4,3,2,1])
x^3 + 2*x^2 + 3*x + 4
sage: a = Qp(5, 10)(1/3); a
2 + 3*5 + 5^2 + 3*5^3 + 5^4 + 3*5^5 + 5^6 + 3*5^7 + 5^8 + 3*5^9 + O(5^10)
sage: ZZ(a)
6510417
另一方面,Sage有一个概念 强制 ,这是父母之间的规范态射(偶尔由开发人员进行常规选择)。从父母一方到另一方的胁迫 must 在整个域上定义,并且总是成功的。因为它可以被含蓄地引用,它应该是明显的和自然的(在数学上严格的和口语的意义上)。对于不精确表示所引起的不可避免的舍入问题,这些强制态射应该全部转换。特别是,如果有强制映射 A to B 和 B to A ,那么它们的组合必须是身份映射。
强制可以通过 Parent.has_coerce_map_from()
方法,如果需要,使用 Parent.coerce()
方法:
sage: QQ.has_coerce_map_from(ZZ)
True
sage: QQ.has_coerce_map_from(RR)
False
sage: ZZ['x'].has_coerce_map_from(QQ)
False
sage: ZZ['x'].has_coerce_map_from(ZZ)
True
sage: ZZ['x'].coerce(5)
5
sage: ZZ['x'].coerce(5).parent()
Univariate Polynomial Ring in x over Integer Ring
sage: ZZ['x'].coerce(5/1)
Traceback (most recent call last):
...
TypeError: no canonical coercion from Rational Field to Univariate Polynomial Ring in x over Integer Ring
基本算术规则¶
假设我们要添加两个元素a和b,它们的父元素分别是a和b。当我们打字的时候 a+b
然后
如果
is
B、 打电话给a如果有胁迫 phi: B rightarrow A ,呼叫a.U add_( phi (b) )
如果有胁迫 phi: A rightarrow B ,呼叫 phi (a) 加上(b)
寻找 Z 以至于有一种胁迫 phi_A: A rightarrow Z 和 phi_B: B rightarrow Z ,呼叫 phi_A (a) .u添加_( phi_B (b) )
这些规则是按顺序计算的;因此,如果在两个方向上都有强制,则a..u add_b的父级是a——在这种情况下,使用左手操作数的父级。
相同的规则用于减法、乘法和除法。该逻辑嵌入到强制模型对象中,可以获取和查询该对象。
sage: parent(1 + 1/2)
Rational Field
sage: cm = coercion_model; cm
<sage.structure.coerce.CoercionModel object at ...>
sage: cm.explain(ZZ, QQ)
Coercion on left operand via
Natural morphism:
From: Integer Ring
To: Rational Field
Arithmetic performed after coercions.
Result lives in Rational Field
Rational Field
sage: cm.explain(ZZ['x','y'], QQ['x'])
Coercion on left operand via
Coercion map:
From: Multivariate Polynomial Ring in x, y over Integer Ring
To: Multivariate Polynomial Ring in x, y over Rational Field
Coercion on right operand via
Coercion map:
From: Univariate Polynomial Ring in x over Rational Field
To: Multivariate Polynomial Ring in x, y over Rational Field
Arithmetic performed after coercions.
Result lives in Multivariate Polynomial Ring in x, y over Rational Field
Multivariate Polynomial Ring in x, y over Rational Field
强制模型可以直接用于任何二进制操作(callable接受两个参数)。
sage: cm.bin_op(77, 9, gcd)
1
也有 行动 从某种意义上说 K 作用于一个模块 K ,或置换组作用于集合。这些是在上述步骤1和2之间发现的。
sage: cm.explain(ZZ['x'], ZZ, operator.mul)
Action discovered.
Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring
Result lives in Univariate Polynomial Ring in x over Integer Ring
Univariate Polynomial Ring in x over Integer Ring
sage: cm.explain(ZZ['x'], ZZ, operator.truediv)
Action discovered.
Right inverse action by Rational Field on Univariate Polynomial Ring in x over Integer Ring
with precomposition on right by Natural morphism:
From: Integer Ring
To: Rational Field
Result lives in Univariate Polynomial Ring in x over Rational Field
Univariate Polynomial Ring in x over Rational Field
sage: f = QQ.coerce_map_from(ZZ)
sage: f(3).parent()
Rational Field
请注意 :trac:`14711` Sage的强制系统使用对域的弱引用的映射。此类地图只能在内部使用,因此应使用副本(除非知道自己在做什么):
sage: QQ._internal_coerce_map_from(int)
(map internal to coercion system -- copy before use)
Native morphism:
From: Set of Python objects of class 'int'
To: Rational Field
sage: copy(QQ._internal_coerce_map_from(int))
Native morphism:
From: Set of Python objects of class 'int'
To: Rational Field
请注意,用户可见方法(不带下划线)自动执行此复制:
sage: copy(QQ.coerce_map_from(int))
Native morphism:
From: Set of Python objects of class 'int'
To: Rational Field
sage: QQ.has_coerce_map_from(RR)
False
sage: QQ['x'].get_action(QQ)
Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Rational Field
sage: QQ2 = QQ^2
sage: (QQ2).get_action(QQ)
Right scalar multiplication by Rational Field on Vector space of dimension 2 over Rational Field
sage: QQ['x'].get_action(RR)
Right scalar multiplication by Real Field with 53 bits of precision on Univariate Polynomial Ring in x over Rational Field
如何实施¶
实施方法¶
元素运算:
_add_
,_sub_
,_mul_
,_div_
在二进制运算符应该实现的地方。不像Python的
__add__
,两个操作数都是 放心 在这一点上有相同的父母。强迫父母:
_coerce_map_from_
给两个父母R和S,
R._coerce_map_from_(S)
调用以确定是否存在强制 phi: S rightarrow R . 请注意,函数是在潜在的密码域上调用的。若要指示不存在从S到R(self)的强制,请返回False
或None
. 这是默认行为。如果有胁迫,就回去True
(在这种情况下,态射使用R._element_constructor_
将被创建)或Morphism
对象,其中S为域,R为codomain。家长行动:
_get_action_
或_rmul_
,_lmul_
,_act_on_
,_acted_upon_
假设有人想让R作用于S R = QQ , S = QQ[x] 或 R = {{rm Gal}}(S/QQ) 在哪里? S 是一个数字域。有几种方法可以实现这一点:
如果 R is the base of S (as in the first example), simply implement
_ rmul ``和/或 ``_lmul_
论 S. In this caser * s
gets handled ass._rmul_(r)
ands * r
ass._lmul_(r)
. The argument to_ 和 ``_lmul_
是 放心 成为 S (如有必要,可事先采取强制措施)。如果 R acts on S, one can define the methods
_ 对元素采取行动 `R` or ``_ 作用于 `S` . 在这种情况下 ``r * s
处理为r._act_on_(s, True)
或s._acted_upon_(r, False)
和s * r
作为r._act_on_(s, False)
或s._acted_upon_(r, True)
. 传递给这些方法的对象的类型或父对象没有约束;引发TypeError
或ValueError
如果传入的对象类型错误,则表明此操作不合适。If either R acts on S or S acts on R, one may implement
R._get_action_
to return an actualAction
object to be used. This is how non-multiplicative actions must be implemented, and is the most powerful and complete way to do things.
应该注意的是,对于第一种工作方式,元素 S 必须是模块元素。这一要求将来可能会取消。
Element conversion/construction for Parents: use
_element_constructor_
not__call__
这个
Parent.__call__()
方法调度到_element_constructor_
. 当有人写R(x, ...)
,这是在大多数情况下最终被调用的方法。请参阅上的文档__call__
方法如下。
家长也可以打电话给 self._populate_coercion_lists_
他们的方法 __init__
函数传递任何可调用而不是 _element_constructor_
,提供一份强迫自己的父母的名单(作为实现 _coerce_map_from_
),提供特殊施工方法(如 _integer_
这也允许指定一个单一的强制嵌入 out (而其余的强制函数都指定映射 into 自我)。的docstring中有大量文档 _populate_coercion_lists_
方法。
例子¶
有时一个简单的例子胜过千言万语。下面是设置一个处理强制的简单环的最小示例。(很容易想象出更复杂、更强大的本地化,但这会掩盖本文的主要观点。)
class Localization(Ring):
def __init__(self, primes):
"""
Localization of `\ZZ` away from primes.
"""
Ring.__init__(self, base=ZZ)
self._primes = primes
self._populate_coercion_lists_()
def _repr_(self):
"""
How to print self.
"""
return "%s localized at %s" % (self.base(), self._primes)
def _element_constructor_(self, x):
"""
Make sure x is a valid member of self, and return the constructed element.
"""
if isinstance(x, LocalizationElement):
x = x._value
else:
x = QQ(x)
for p, e in x.denominator().factor():
if p not in self._primes:
raise ValueError("Not integral at %s" % p)
return LocalizationElement(self, x)
def _coerce_map_from_(self, S):
"""
The only things that coerce into this ring are:
- the integer ring
- other localizations away from fewer primes
"""
if S is ZZ:
return True
elif isinstance(S, Localization):
return all(p in self._primes for p in S._primes)
class LocalizationElement(RingElement):
def __init__(self, parent, x):
RingElement.__init__(self, parent)
self._value = x
# We're just printing out this way to make it easy to see what's going on in the examples.
def _repr_(self):
return "LocalElt(%s)" % self._value
# Now define addition, subtraction, and multiplication of elements.
# Note that left and right always have the same parent.
def _add_(left, right):
return LocalizationElement(left.parent(), left._value + right._value)
def _sub_(left, right):
return LocalizationElement(left.parent(), left._value - right._value)
def _mul_(left, right):
return LocalizationElement(left.parent(), left._value * right._value)
# The basering was set to ZZ, so c is guaranteed to be in ZZ
def _rmul_(self, c):
return LocalizationElement(self.parent(), c * self._value)
def _lmul_(self, c):
return LocalizationElement(self.parent(), self._value * c)
就这些了。现在我们可以测试一下:
sage: R = Localization([2]); R
Integer Ring localized at [2]
sage: R(1)
LocalElt(1)
sage: R(1/2)
LocalElt(1/2)
sage: R(1/3)
Traceback (most recent call last):
...
ValueError: Not integral at 3
sage: R.coerce(1)
LocalElt(1)
sage: R.coerce(1/4)
Traceback (click to the left for traceback)
...
TypeError: no canonical coercion from Rational Field to Integer Ring localized at [2]
sage: R(1/2) + R(3/4)
LocalElt(5/4)
sage: R(1/2) + 5
LocalElt(11/2)
sage: 5 + R(1/2)
LocalElt(11/2)
sage: R(1/2) + 1/7
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for +: 'Integer Ring localized at [2]' and 'Rational Field'
sage: R(3/4) * 7
LocalElt(21/4)
sage: R.get_action(ZZ)
Right scalar multiplication by Integer Ring on Integer Ring localized at [2]
sage: cm = sage.structure.element.get_coercion_model()
sage: cm.explain(R, ZZ, operator.add)
Coercion on right operand via
Conversion map:
From: Integer Ring
To: Integer Ring localized at [2]
Arithmetic performed after coercions.
Result lives in Integer Ring localized at [2]
Integer Ring localized at [2]
sage: cm.explain(R, ZZ, operator.mul)
Action discovered.
Right scalar multiplication by Integer Ring on Integer Ring localized at [2]
Result lives in Integer Ring localized at [2]
Integer Ring localized at [2]
sage: R6 = Localization([2,3]); R6
Integer Ring localized at [2, 3]
sage: R6(1/3) - R(1/2)
LocalElt(-1/6)
sage: parent(R6(1/3) - R(1/2))
Integer Ring localized at [2, 3]
sage: R.has_coerce_map_from(ZZ)
True
sage: R.coerce_map_from(ZZ)
Conversion map:
From: Integer Ring
To: Integer Ring localized at [2]
sage: R6.coerce_map_from(R)
Conversion map:
From: Integer Ring localized at [2]
To: Integer Ring localized at [2, 3]
sage: R6.coerce(R(1/2))
LocalElt(1/2)
sage: cm.explain(R, R6, operator.mul)
Coercion on left operand via
Conversion map:
From: Integer Ring localized at [2]
To: Integer Ring localized at [2, 3]
Arithmetic performed after coercions.
Result lives in Integer Ring localized at [2, 3]
Integer Ring localized at [2, 3]
提供的方法¶
__call__
这为元素构造提供了一致的接口。特别是,如果存在强制,它可以确保转换总是给出与强制相同的结果。(在Sage中,由于转换和强制的代码分别进行了编辑,所以在Sage中,这一点常常被违反。)让R作为父级,并假设用户键入R(x),其中x有父级x。粗略地说,会发生以下情况:
如果X
is
R、 返回x(*)如果有胁迫 f: X rightarrow R 返回 f(x)
如果有胁迫 f: R rightarrow X ,尝试返回 {{f^{{-1}}}}(x)
返回
R._element_constructor_(x)
(**)
关键字和额外的参数被传递。所有这些逻辑的结果都被缓存。
(*)除非有“copy”关键字,如R(x,copy=False)
(**)从技术上讲,一个通用的态射是从X到R创建的,它可以使用像
_integer_
或其他由_populate_coercion_lists_
.coerce
将元素强制为self,如果没有强制映射,则引发类型错误。
coerce_map_from, convert_map_from
返回实际值
Morphism
对象将从另一个父对象强制/转换为自身。除非直接构造R元素,R.convert_map_from(S)
将提供一个可调用的Python对象,这是将S的元素转换为R的元素的最快方法_call_
方法。has_coerce_map_from
返回
True
或False
取决于是否有胁迫。R.has_coerce_map_from(S)
是R.coerce_map_from(S) is not None
get_action
这会让你放松
_get_action_, _rmul_, _lmul_, _act_on_, _acted_upon_, ...
方法提供一个Action
对象,如果存在。
发现新父母¶
使用sage/category中的算法来发现新的父代/推出.py. 其基本思想是Sage中的大多数父类都是通过各种函子从更简单的对象中构造出来的。这些可以通过 construction()
方法,该方法返回一个(更简单)父级以及一个可以创建self的函子。
sage: CC.construction()
(AlgebraicClosureFunctor, Real Field with 53 bits of precision)
sage: RR.construction()
(Completion[+Infinity, prec=53], Rational Field)
sage: QQ.construction()
(FractionField, Integer Ring)
sage: ZZ.construction() # None
sage: Zp(5).construction()
(Completion[5, prec=20], Integer Ring)
sage: QQ.completion(5, 100, {})
5-adic Field with capped relative precision 100
sage: c, R = RR.construction()
sage: a = CC.construction()[0]
sage: a.commutes(c)
False
sage: RR == c(QQ)
True
sage: sage.categories.pushout.construction_tower(Frac(CDF['x']))
[(None,
Fraction Field of Univariate Polynomial Ring in x over Complex Double Field),
(FractionField, Univariate Polynomial Ring in x over Complex Double Field),
(Poly[x], Complex Double Field),
(AlgebraicClosureFunctor, Real Double Field),
(Completion[+Infinity, prec=53], Rational Field),
(FractionField, Integer Ring)]
给定双亲R和S,使得没有从R到S或从S到R的强制,我们可以找到带有强制的公共Z R rightarrow Z 和 S rightarrow Z 通过考虑从一个共同祖先到R和S的构造函子的序列,我们使用a 启发式的 交错这些构造器以尝试到达合适的Z(如果存在的话)的算法。例如::
sage: ZZ['x'].construction()
(Poly[x], Integer Ring)
sage: QQ.construction()
(FractionField, Integer Ring)
sage: sage.categories.pushout.pushout(ZZ['x'], QQ)
Univariate Polynomial Ring in x over Rational Field
sage: sage.categories.pushout.pushout(ZZ['x'], QQ).construction()
(Poly[x], Rational Field)
共同的祖先是 Z 我们对Z的选择是 mathrm{{Frac}}(ZZ[x]) 或 mathrm{{Frac}}(ZZ)[x] . 在Sage中,我们选择后者,将分数域函子视为比多项式函子“更紧密”的结合,正如大多数人所同意的那样 QQ[x] 是比较自然的选择。同样的过程也适用于更复杂的父对象,如果可以明确地确定一个新的父对象,则返回一个新的父对象。
sage: sage.categories.pushout.pushout(Frac(ZZ['x,y,z']), QQ['z, t'])
Univariate Polynomial Ring in t over Fraction Field of Multivariate Polynomial Ring in x, y, z over Rational Field