Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
| Download
Sage Reference Manual
Project: SageManifolds
Views: 717156Coercion1========23Preliminaries4--------------56What is coercion all about?7~~~~~~~~~~~~~~~~~~~~~~~~~~~89*The primary goal of coercion is to be able to transparently do arithmetic, comparisons, etc. between elements of distinct sets.*1011As a concrete example, when one writes `1 + 1/2` one wants to perform12arithmetic on the operands as rational numbers, despite the left being13an integer. This makes sense given the obvious and natural inclusion14of the integers into the rational numbers. The goal of the coercion15system is to facilitate this (and more complicated arithmetic) without16having to explicitly map everything over into the same domain, and at17the same time being strict enough to not resolve ambiguity or accept18nonsense. Here are some examples::1920sage: 1 + 1/2213/222sage: R.<x,y> = ZZ[]23sage: R24Multivariate Polynomial Ring in x, y over Integer Ring25sage: parent(x)26Multivariate Polynomial Ring in x, y over Integer Ring27sage: parent(1/3)28Rational Field29sage: x+1/330x + 1/331sage: parent(x+1/3)32Multivariate Polynomial Ring in x, y over Rational Field3334sage: GF(5)(1) + CC(I)35Traceback (most recent call last):36...37TypeError: unsupported operand parent(s) for '+': 'Finite Field of size 5' and 'Complex Field with 53 bits of precision'3839Parents and Elements40~~~~~~~~~~~~~~~~~~~~4142Parents are objects in concrete categories, and Elements are their43members. Parents are first-class objects. Most things in Sage are44either parents or have a parent. Typically whenever one sees the word45*Parent* one can think *Set*. Here are some examples::4647sage: parent(1)48Integer Ring49sage: parent(1) is ZZ50True51sage: ZZ52Integer Ring53sage: parent(1.50000000000000000000000000000000000)54Real Field with 120 bits of precision55sage: parent(x)56Symbolic Ring57sage: x^sin(x)58x^sin(x)59sage: R.<t> = Qp(5)[]60sage: f = t^3-5; f61(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))62sage: parent(f)63Univariate Polynomial Ring in t over 5-adic Field with capped relative precision 2064sage: f = EllipticCurve('37a').lseries().taylor_series(10); f650.990010459847588 + 0.0191338632530789*z - 0.0197489006172923*z^2 + 0.0137240085327618*z^3 - 0.00703880791607153*z^4 + 0.00280906165766519*z^5 + O(z^6) # 32-bit660.997997869801216 + 0.00140712894524925*z - 0.000498127610960097*z^2 + 0.000118835596665956*z^3 - 0.0000215906522442707*z^4 + (3.20363155418419e-6)*z^5 + O(z^6) # 64-bit67sage: parent(f)68Power Series Ring in z over Complex Field with 53 bits of precision6970There is an important distinction between Parents and types::7172sage: a = GF(5).random_element()73sage: b = GF(7).random_element()74sage: type(a)75<type 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>76sage: type(b)77<type 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>78sage: type(a) == type(b)79True80sage: parent(a)81Finite Field of size 582sage: parent(a) == parent(b)83False8485However, non-Sage objects don't really have parents, but we still want86to be able to reason with them, so their type is used instead::8788sage: a = int(10)89sage: parent(a)90<type 'int'>9192In fact, under the hood, a special kind of parent "The set of all93Python objects of type T" is used in these cases.9495Note that parents are **not** always as tight as possible.9697::9899sage: parent(1/2)100Rational Field101sage: parent(2/1)102Rational Field103104Maps between Parents105~~~~~~~~~~~~~~~~~~~~106107Many parents come with maps to and from other parents.108109Sage makes a distinction between being able to **convert** between110various parents, and **coerce** between them. Conversion is explicit111and tries to make sense of an object in the target domain if at all112possible. It is invoked by calling::113114sage: ZZ(5)1155116sage: ZZ(10/5)1172118sage: QQ(10)11910120sage: parent(QQ(10))121Rational Field122sage: a = GF(5)(2); a1232124sage: parent(a)125Finite Field of size 5126sage: parent(ZZ(a))127Integer Ring128sage: GF(71)(1/5)12957130sage: ZZ(1/2)131Traceback (most recent call last):132...133TypeError: no conversion of this rational to integer134135Conversions need not be canonical (they may for example involve a136choice of lift) or even make sense mathematically (e.g. constructions137of some kind).138139::140141sage: ZZ("123")142123143sage: ZZ(GF(5)(14))1444145sage: ZZ['x']([4,3,2,1])146x^3 + 2*x^2 + 3*x + 4147sage: a = Qp(5, 10)(1/3); a1482 + 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)149sage: ZZ(a)1506510417151152On the other hand, Sage has the notion of a **coercion**, which is a153canonical morphism (occasionally up to a conventional choice made by154developers) between parents. A coercion from one parent to another155**must** be defined on the whole domain, and always succeeds. As it156may be invoked implicitly, it should be obvious and natural (in both157the mathematically rigorous and colloquial sense of the word). Up to158inescapable rounding issues that arise with inexact representations,159these coercion morphisms should all commute. In particular, if there160are coercion maps `A \to B` and `B \to A`, then their composites161must be the identity maps.162163Coercions can be discovered via the :meth:`Parent.has_coerce_map_from`164method, and if needed explicitly invoked with the165:meth:`Parent.coerce` method::166167sage: QQ.has_coerce_map_from(ZZ)168True169sage: QQ.has_coerce_map_from(RR)170False171sage: ZZ['x'].has_coerce_map_from(QQ)172False173sage: ZZ['x'].has_coerce_map_from(ZZ)174True175sage: ZZ['x'].coerce(5)1765177sage: ZZ['x'].coerce(5).parent()178Univariate Polynomial Ring in x over Integer Ring179sage: ZZ['x'].coerce(5/1)180Traceback (most recent call last):181...182TypeError: no canonical coercion from Rational Field to Univariate Polynomial Ring in x over Integer Ring183184Basic Arithmetic Rules185----------------------186187Suppose we want to add two element, a and b, whose parents are A and B188respectively. When we type ``a+b`` then1891901. If A ``is`` B, call a._add_(b)1911922. If there is a coercion `\phi: B \rightarrow A`, call a._add_( `\phi` (b))1931943. If there is a coercion `\phi: A \rightarrow B`, call `\phi` (a)._add_(b)1951964. Look for `Z` such that there is a coercion `\phi_A: A \rightarrow Z` and197`\phi_B: B \rightarrow Z`, call `\phi_A` (a)._add_( `\phi_B` (b))198199These rules are evaluated in order; therefore if there are coercions200in both directions, then the parent of a._add_b is A -- the parent201of the left-hand operand is used in such cases.202203The same rules are used for subtraction, multiplication, and204division. This logic is embedded in a coercion model object, which can205be obtained and queried.206207::208209sage: parent(1 + 1/2)210Rational Field211sage: cm = sage.structure.element.get_coercion_model(); cm212<sage.structure.coerce.CoercionModel_cache_maps object at ...>213sage: cm.explain(ZZ, QQ)214Coercion on left operand via215Natural morphism:216From: Integer Ring217To: Rational Field218Arithmetic performed after coercions.219Result lives in Rational Field220Rational Field221222sage: cm.explain(ZZ['x','y'], QQ['x'])223Coercion on left operand via224Conversion map:225From: Multivariate Polynomial Ring in x, y over Integer Ring226To: Multivariate Polynomial Ring in x, y over Rational Field227Coercion on right operand via228Conversion map:229From: Univariate Polynomial Ring in x over Rational Field230To: Multivariate Polynomial Ring in x, y over Rational Field231Arithmetic performed after coercions.232Result lives in Multivariate Polynomial Ring in x, y over Rational Field233Multivariate Polynomial Ring in x, y over Rational Field234235The coercion model can be used directly for any binary operation236(callable taking two arguments).237238.. link239240::241242sage: cm.bin_op(77, 9, gcd)2431244245There are also **actions** in the sense that a field `K` acts on a246module over `K`, or a permutation group acts on a set. These are247discovered between steps 1 and 2 above.248249.. link250251::252253sage: cm.explain(ZZ['x'], ZZ, operator.mul)254Action discovered.255Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring256Result lives in Univariate Polynomial Ring in x over Integer Ring257Univariate Polynomial Ring in x over Integer Ring258259sage: cm.explain(ZZ['x'], ZZ, operator.div)260Action discovered.261Right inverse action by Rational Field on Univariate Polynomial Ring in x over Integer Ring262with precomposition on right by Natural morphism:263From: Integer Ring264To: Rational Field265Result lives in Univariate Polynomial Ring in x over Rational Field266Univariate Polynomial Ring in x over Rational Field267268sage: f = QQ.coerce_map_from(ZZ)269sage: f(3).parent()270Rational Field271272Note that by :trac:`14711` Sage's coercion system uses maps with weak273references to the domain. Such maps should only be used internally, and so a274copy should be used instead (unless one knows what one is doing)::275276sage: QQ._internal_coerce_map_from(int)277(map internal to coercion system -- copy before use)278Native morphism:279From: Set of Python objects of type 'int'280To: Rational Field281sage: copy(QQ._internal_coerce_map_from(int))282Native morphism:283From: Set of Python objects of type 'int'284To: Rational Field285286Note that the user-visible method (without underscore) automates this copy::287288sage: copy(QQ.coerce_map_from(int))289Native morphism:290From: Set of Python objects of type 'int'291To: Rational Field292293::294295sage: QQ.has_coerce_map_from(RR)296False297sage: QQ['x'].get_action(QQ)298Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Rational Field299sage: QQ2 = QQ^2300sage: (QQ2).get_action(QQ)301Right scalar multiplication by Rational Field on Vector space of dimension 2 over Rational Field302sage: QQ['x'].get_action(RR)303Right scalar multiplication by Real Field with 53 bits of precision on Univariate Polynomial Ring in x over Rational Field304305How to Implement306----------------307308Methods to implement309~~~~~~~~~~~~~~~~~~~~310311* Arithmetic on Elements: ``_add_``, ``_sub_``, ``_mul_``, ``_div_``312313This is where the binary arithmetic operators should be314implemented. Unlike Python's ``__add__``, both operands are315*guaranteed* to have the same Parent at this point.316317* Coercion for Parents: ``_coerce_map_from_``318319Given two parents R and S, ``R._coerce_map_from_(S)`` is called to320determine if there is a coercion `\phi: S \rightarrow R`. Note that321the function is called on the potential codomain. To indicate that322there is no coercion from S to R (self), return ``False`` or323``None``. This is the default behavior. If there is a coercion,324return ``True`` (in which case an morphism using325``R._element_constructor_`` will be created) or an actual326:class:`Morphism` object with S as the domain and R as the codomain.327328* Actions for Parents: ``_get_action_`` or ``_rmul_``, ``_lmul_``, ``_r_action_``, ``_l_action_``329330Suppose one wants R to act on S. Some examples of this could be331`R = \QQ`, `S = \QQ[x]` or `R = {\rm Gal}(S/\QQ)`332where `S` is a number field. There are several ways to implement this:333334* If `R` is the base of `S` (as in the first example), simply335implement ``_rmul_`` and/or ``_lmul_`` on the Elements of `S`.336In this case ``r * s`` gets handled as ``s._rmul_(r)`` and337``s * r`` as ``s._lmul_(r)``. The argument to ``_rmul_``338and ``_lmul_`` are *guaranteed* to be Elements of the base of339`S` (with coercion happening beforehand if necessary).340341* If `R` acts on `S`, one can alternatively define the methods342``_r_action_`` and/or ``_l_action_`` on the Elements of `R`.343There is no constraint on the type or parents of objects passed to344these methods; raise a ``TypeError`` or ``ValueError`` if the345wrong kind of object is passed in to indicate the action is not346appropriate here.347348* If either `R` acts on `S` *or* `S` acts on `R`, one may implement349``R._get_action_`` to return an actual350:class:`~sage.categories.action.Action` object to be used. This351is how non-multiplicative actions must be implemented, and is the352most powerful (and completed) way to do things.353354* Element conversion/construction for Parents: use355``_element_constructor_`` **not** ``__call__``356357The :meth:`Parent.__call__` method dispatches to358``_element_constructor_``. When someone writes ``R(x, ...)``, this is359the method that eventually gets called in most cases. See the360documentation on the ``__call__`` method below.361362Parents may also call the ``self._populate_coercion_lists_`` method in363their ``__init__`` functions to pass any callable for use instead of364``_element_constructor_``, provide a list of Parents with coercions to365self (as an alternative to implementing ``_coerce_map_from_``),366provide special construction methods (like ``_integer_`` for ZZ),367etc. This also allows one to specify a single coercion embedding *out*368of self (whereas the rest of the coercion functions all specify maps369*into* self). There is extensive documentation in the docstring of the370``_populate_coercion_lists_`` method.371372Example373~~~~~~~374375Sometimes a simple example is worth a thousand words. Here is a376minimal example of setting up a simple Ring that handles coercion. (It377is easy to imagine much more sophisticated and powerful localizations,378but that would obscure the main points being made here.)379380::381382class Localization(Ring):383def __init__(self, primes):384"""385Localization of `\ZZ` away from primes.386"""387Ring.__init__(self, base=ZZ)388self._primes = primes389self._populate_coercion_lists_()390391def _repr_(self):392"""393How to print self.394"""395return "%s localized at %s" % (self.base(), self._primes)396397def _element_constructor_(self, x):398"""399Make sure x is a valid member of self, and return the constructed element.400"""401if isinstance(x, LocalizationElement):402x = x._value403else:404x = QQ(x)405for p, e in x.denominator().factor():406if p not in self._primes:407raise ValueError("Not integral at %s" % p)408return LocalizationElement(self, x)409410def _coerce_map_from_(self, S):411"""412The only things that coerce into this ring are:413414- the integer ring415416- other localizations away from fewer primes417"""418if S is ZZ:419return True420elif isinstance(S, Localization):421return all(p in self._primes for p in S._primes)422423424class LocalizationElement(RingElement):425426def __init__(self, parent, x):427RingElement.__init__(self, parent)428self._value = x429430431# We're just printing out this way to make it easy to see what's going on in the examples.432433def _repr_(self):434return "LocalElt(%s)" % self._value435436# Now define addition, subtraction, and multiplication of elements.437# Note that left and right always have the same parent.438439def _add_(left, right):440return LocalizationElement(left.parent(), left._value + right._value)441442def _sub_(left, right):443return LocalizationElement(left.parent(), left._value - right._value)444445def _mul_(left, right):446return LocalizationElement(left.parent(), left._value * right._value)447448# The basering was set to ZZ, so c is guaranteed to be in ZZ449450def _rmul_(self, c):451return LocalizationElement(self.parent(), c * self._value)452453def _lmul_(self, c):454return LocalizationElement(self.parent(), self._value * c)455456That's all there is to it. Now we can test it out:457458.. skip459460::461462sage: R = Localization([2]); R463Integer Ring localized at [2]464sage: R(1)465LocalElt(1)466sage: R(1/2)467LocalElt(1/2)468sage: R(1/3)469Traceback (most recent call last):470...471ValueError: Not integral at 3472473sage: R.coerce(1)474LocalElt(1)475sage: R.coerce(1/4)476Traceback (click to the left for traceback)477...478TypeError: no cannonical coercion from Rational Field to Integer Ring localized at [2]479480sage: R(1/2) + R(3/4)481LocalElt(5/4)482sage: R(1/2) + 5483LocalElt(11/2)484sage: 5 + R(1/2)485LocalElt(11/2)486sage: R(1/2) + 1/7487Traceback (most recent call last):488...489TypeError: unsupported operand parent(s) for '+': 'Integer Ring localized at [2]' and 'Rational Field'490sage: R(3/4) * 7491LocalElt(21/4)492493sage: R.get_action(ZZ)494Right scalar multiplication by Integer Ring on Integer Ring localized at [2]495sage: cm = sage.structure.element.get_coercion_model()496sage: cm.explain(R, ZZ, operator.add)497Coercion on right operand via498Conversion map:499From: Integer Ring500To: Integer Ring localized at [2]501Arithmetic performed after coercions.502Result lives in Integer Ring localized at [2]503Integer Ring localized at [2]504505sage: cm.explain(R, ZZ, operator.mul)506Action discovered.507Right scalar multiplication by Integer Ring on Integer Ring localized at [2]508Result lives in Integer Ring localized at [2]509Integer Ring localized at [2]510511sage: R6 = Localization([2,3]); R6512Integer Ring localized at [2, 3]513sage: R6(1/3) - R(1/2)514LocalElt(-1/6)515sage: parent(R6(1/3) - R(1/2))516Integer Ring localized at [2, 3]517518sage: R.has_coerce_map_from(ZZ)519True520sage: R.coerce_map_from(ZZ)521Conversion map:522From: Integer Ring523To: Integer Ring localized at [2]524525sage: R6.coerce_map_from(R)526Conversion map:527From: Integer Ring localized at [2]528To: Integer Ring localized at [2, 3]529530sage: R6.coerce(R(1/2))531LocalElt(1/2)532533sage: cm.explain(R, R6, operator.mul)534Coercion on left operand via535Conversion map:536From: Integer Ring localized at [2]537To: Integer Ring localized at [2, 3]538Arithmetic performed after coercions.539Result lives in Integer Ring localized at [2, 3]540Integer Ring localized at [2, 3]541542Provided Methods543~~~~~~~~~~~~~~~~544545* ``__call__``546547This provides a consistent interface for element construction. In548particular, it makes sure that conversion always gives the same549result as coercion, if a coercion exists. (This used to be violated550for some Rings in Sage as the code for conversion and coercion got551edited separately.) Let R be a Parent and assume the user types552R(x), where x has parent X. Roughly speaking, the following occurs:5535541. If X ``is`` R, return x (*)5555562. If there is a coercion `f: X \rightarrow R`, return `f(x)`5575583. If there is a coercion `f: R \rightarrow X`, try to return `{f^{-1}}(x)`5595604. Return ``R._element_constructor_(x)`` (**)561562Keywords and extra arguments are passed on. The result of all this logic is cached.563564(*) Unless there is a "copy" keyword like R(x, copy=False)565566(**) Technically, a generic morphism is created from X to R, which567may use magic methods like ``_integer_`` or other data provided by568``_populate_coercion_lists_``.569570* ``coerce``571572Coerces elements into self, raising a type error if there is no573coercion map.574575* ``coerce_map_from, convert_map_from``576577Returns an actual ``Morphism`` object to coerce/convert from578another Parent to self. Barring direct construction of elements of579R, ``R.convert_map_from(S)`` will provide a callable Python object580which is the fastest way to convert elements of S to elements of581R. From Cython, it can be invoked via the cdef ``_call_`` method.582583* ``has_coerce_map_from``584585Returns ``True`` or ``False`` depending on whether or not there is586a coercion. ``R.has_coerce_map_from(S)`` is shorthand for587``R.coerce_map_from(S) is not None``588589* ``get_action``590591This will unwind all the592``_rmul_, _lmul_, _r_action_, _l_action_, ...`` methods to provide593an actual ``Action`` object, if one exists.594595596Discovering new parents597-----------------------598599New parents are discovered using an algorithm in600sage/category/pushout.py. The fundamental idea is that most Parents601in Sage are constructed from simpler objects via various functors.602These are accessed via the :meth:`construction` method, which returns a603(simpler) Parent along with a functor with which one can create self.604605::606607sage: CC.construction()608(AlgebraicClosureFunctor, Real Field with 53 bits of precision)609sage: RR.construction()610(Completion[+Infinity], Rational Field)611sage: QQ.construction()612(FractionField, Integer Ring)613sage: ZZ.construction() # None614615sage: Qp(5).construction()616(Completion[5], Rational Field)617sage: QQ.completion(5, 100, {})6185-adic Field with capped relative precision 100619sage: c, R = RR.construction()620sage: a = CC.construction()[0]621sage: a.commutes(c)622False623sage: RR == c(QQ)624True625626sage: sage.categories.pushout.construction_tower(Frac(CDF['x']))627[(None,628Fraction Field of Univariate Polynomial Ring in x over Complex Double Field),629(FractionField, Univariate Polynomial Ring in x over Complex Double Field),630(Poly[x], Complex Double Field),631(AlgebraicClosureFunctor, Real Double Field),632(Completion[+Infinity], Rational Field),633(FractionField, Integer Ring)]634635Given Parents R and S, such that there is no coercion either from R to636S or from S to R, one can find a common Z with coercions637`R \rightarrow Z` and `S \rightarrow Z` by considering the sequence of638construction functors to get from a common ancestor to both R and S.639We then use a *heuristic* algorithm to interleave these constructors640in an attempt to arrive at a suitable Z (if one exists). For example::641642sage: ZZ['x'].construction()643(Poly[x], Integer Ring)644sage: QQ.construction()645(FractionField, Integer Ring)646sage: sage.categories.pushout.pushout(ZZ['x'], QQ)647Univariate Polynomial Ring in x over Rational Field648sage: sage.categories.pushout.pushout(ZZ['x'], QQ).construction()649(Poly[x], Rational Field)650651The common ancestor is `Z` and our options for Z are652`\mathrm{Frac}(\ZZ[x])` or `\mathrm{Frac}(\ZZ)[x]`.653In Sage we choose the later, treating the fraction654field functor as binding "more tightly" than the polynomial functor,655as most people agree that `\QQ[x]` is the more natural choice. The same656procedure is applied to more complicated Parents, returning a new657Parent if one can be unambiguously determined.658659::660661sage: sage.categories.pushout.pushout(Frac(ZZ['x,y,z']), QQ['z, t'])662Univariate Polynomial Ring in t over Fraction Field of Multivariate Polynomial Ring in x, y, z over Rational Field663664Modules665-------666667.. toctree::668:maxdepth: 2669670sage/structure/coerce671sage/structure/coerce_actions672sage/structure/coerce_maps673674675.. include:: ../footer.txt676677678