CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In

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: 717156
1
Coercion
2
========
3
4
Preliminaries
5
--------------
6
7
What is coercion all about?
8
~~~~~~~~~~~~~~~~~~~~~~~~~~~
9
10
*The primary goal of coercion is to be able to transparently do arithmetic, comparisons, etc. between elements of distinct sets.*
11
12
As a concrete example, when one writes `1 + 1/2` one wants to perform
13
arithmetic on the operands as rational numbers, despite the left being
14
an integer. This makes sense given the obvious and natural inclusion
15
of the integers into the rational numbers. The goal of the coercion
16
system is to facilitate this (and more complicated arithmetic) without
17
having to explicitly map everything over into the same domain, and at
18
the same time being strict enough to not resolve ambiguity or accept
19
nonsense. Here are some examples::
20
21
sage: 1 + 1/2
22
3/2
23
sage: R.<x,y> = ZZ[]
24
sage: R
25
Multivariate Polynomial Ring in x, y over Integer Ring
26
sage: parent(x)
27
Multivariate Polynomial Ring in x, y over Integer Ring
28
sage: parent(1/3)
29
Rational Field
30
sage: x+1/3
31
x + 1/3
32
sage: parent(x+1/3)
33
Multivariate Polynomial Ring in x, y over Rational Field
34
35
sage: GF(5)(1) + CC(I)
36
Traceback (most recent call last):
37
...
38
TypeError: unsupported operand parent(s) for '+': 'Finite Field of size 5' and 'Complex Field with 53 bits of precision'
39
40
Parents and Elements
41
~~~~~~~~~~~~~~~~~~~~
42
43
Parents are objects in concrete categories, and Elements are their
44
members. Parents are first-class objects. Most things in Sage are
45
either parents or have a parent. Typically whenever one sees the word
46
*Parent* one can think *Set*. Here are some examples::
47
48
sage: parent(1)
49
Integer Ring
50
sage: parent(1) is ZZ
51
True
52
sage: ZZ
53
Integer Ring
54
sage: parent(1.50000000000000000000000000000000000)
55
Real Field with 120 bits of precision
56
sage: parent(x)
57
Symbolic Ring
58
sage: x^sin(x)
59
x^sin(x)
60
sage: R.<t> = Qp(5)[]
61
sage: f = t^3-5; f
62
(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))
63
sage: parent(f)
64
Univariate Polynomial Ring in t over 5-adic Field with capped relative precision 20
65
sage: f = EllipticCurve('37a').lseries().taylor_series(10); f
66
0.990010459847588 + 0.0191338632530789*z - 0.0197489006172923*z^2 + 0.0137240085327618*z^3 - 0.00703880791607153*z^4 + 0.00280906165766519*z^5 + O(z^6) # 32-bit
67
0.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-bit
68
sage: parent(f)
69
Power Series Ring in z over Complex Field with 53 bits of precision
70
71
There is an important distinction between Parents and types::
72
73
sage: a = GF(5).random_element()
74
sage: b = GF(7).random_element()
75
sage: type(a)
76
<type 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>
77
sage: type(b)
78
<type 'sage.rings.finite_rings.integer_mod.IntegerMod_int'>
79
sage: type(a) == type(b)
80
True
81
sage: parent(a)
82
Finite Field of size 5
83
sage: parent(a) == parent(b)
84
False
85
86
However, non-Sage objects don't really have parents, but we still want
87
to be able to reason with them, so their type is used instead::
88
89
sage: a = int(10)
90
sage: parent(a)
91
<type 'int'>
92
93
In fact, under the hood, a special kind of parent "The set of all
94
Python objects of type T" is used in these cases.
95
96
Note that parents are **not** always as tight as possible.
97
98
::
99
100
sage: parent(1/2)
101
Rational Field
102
sage: parent(2/1)
103
Rational Field
104
105
Maps between Parents
106
~~~~~~~~~~~~~~~~~~~~
107
108
Many parents come with maps to and from other parents.
109
110
Sage makes a distinction between being able to **convert** between
111
various parents, and **coerce** between them. Conversion is explicit
112
and tries to make sense of an object in the target domain if at all
113
possible. It is invoked by calling::
114
115
sage: ZZ(5)
116
5
117
sage: ZZ(10/5)
118
2
119
sage: QQ(10)
120
10
121
sage: parent(QQ(10))
122
Rational Field
123
sage: a = GF(5)(2); a
124
2
125
sage: parent(a)
126
Finite Field of size 5
127
sage: parent(ZZ(a))
128
Integer Ring
129
sage: GF(71)(1/5)
130
57
131
sage: ZZ(1/2)
132
Traceback (most recent call last):
133
...
134
TypeError: no conversion of this rational to integer
135
136
Conversions need not be canonical (they may for example involve a
137
choice of lift) or even make sense mathematically (e.g. constructions
138
of some kind).
139
140
::
141
142
sage: ZZ("123")
143
123
144
sage: ZZ(GF(5)(14))
145
4
146
sage: ZZ['x']([4,3,2,1])
147
x^3 + 2*x^2 + 3*x + 4
148
sage: a = Qp(5, 10)(1/3); a
149
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)
150
sage: ZZ(a)
151
6510417
152
153
On the other hand, Sage has the notion of a **coercion**, which is a
154
canonical morphism (occasionally up to a conventional choice made by
155
developers) between parents. A coercion from one parent to another
156
**must** be defined on the whole domain, and always succeeds. As it
157
may be invoked implicitly, it should be obvious and natural (in both
158
the mathematically rigorous and colloquial sense of the word). Up to
159
inescapable rounding issues that arise with inexact representations,
160
these coercion morphisms should all commute. In particular, if there
161
are coercion maps `A \to B` and `B \to A`, then their composites
162
must be the identity maps.
163
164
Coercions can be discovered via the :meth:`Parent.has_coerce_map_from`
165
method, and if needed explicitly invoked with the
166
:meth:`Parent.coerce` method::
167
168
sage: QQ.has_coerce_map_from(ZZ)
169
True
170
sage: QQ.has_coerce_map_from(RR)
171
False
172
sage: ZZ['x'].has_coerce_map_from(QQ)
173
False
174
sage: ZZ['x'].has_coerce_map_from(ZZ)
175
True
176
sage: ZZ['x'].coerce(5)
177
5
178
sage: ZZ['x'].coerce(5).parent()
179
Univariate Polynomial Ring in x over Integer Ring
180
sage: ZZ['x'].coerce(5/1)
181
Traceback (most recent call last):
182
...
183
TypeError: no canonical coercion from Rational Field to Univariate Polynomial Ring in x over Integer Ring
184
185
Basic Arithmetic Rules
186
----------------------
187
188
Suppose we want to add two element, a and b, whose parents are A and B
189
respectively. When we type ``a+b`` then
190
191
1. If A ``is`` B, call a._add_(b)
192
193
2. If there is a coercion `\phi: B \rightarrow A`, call a._add_( `\phi` (b))
194
195
3. If there is a coercion `\phi: A \rightarrow B`, call `\phi` (a)._add_(b)
196
197
4. Look for `Z` such that there is a coercion `\phi_A: A \rightarrow Z` and
198
`\phi_B: B \rightarrow Z`, call `\phi_A` (a)._add_( `\phi_B` (b))
199
200
These rules are evaluated in order; therefore if there are coercions
201
in both directions, then the parent of a._add_b is A -- the parent
202
of the left-hand operand is used in such cases.
203
204
The same rules are used for subtraction, multiplication, and
205
division. This logic is embedded in a coercion model object, which can
206
be obtained and queried.
207
208
::
209
210
sage: parent(1 + 1/2)
211
Rational Field
212
sage: cm = sage.structure.element.get_coercion_model(); cm
213
<sage.structure.coerce.CoercionModel_cache_maps object at ...>
214
sage: cm.explain(ZZ, QQ)
215
Coercion on left operand via
216
Natural morphism:
217
From: Integer Ring
218
To: Rational Field
219
Arithmetic performed after coercions.
220
Result lives in Rational Field
221
Rational Field
222
223
sage: cm.explain(ZZ['x','y'], QQ['x'])
224
Coercion on left operand via
225
Conversion map:
226
From: Multivariate Polynomial Ring in x, y over Integer Ring
227
To: Multivariate Polynomial Ring in x, y over Rational Field
228
Coercion on right operand via
229
Conversion map:
230
From: Univariate Polynomial Ring in x over Rational Field
231
To: Multivariate Polynomial Ring in x, y over Rational Field
232
Arithmetic performed after coercions.
233
Result lives in Multivariate Polynomial Ring in x, y over Rational Field
234
Multivariate Polynomial Ring in x, y over Rational Field
235
236
The coercion model can be used directly for any binary operation
237
(callable taking two arguments).
238
239
.. link
240
241
::
242
243
sage: cm.bin_op(77, 9, gcd)
244
1
245
246
There are also **actions** in the sense that a field `K` acts on a
247
module over `K`, or a permutation group acts on a set. These are
248
discovered between steps 1 and 2 above.
249
250
.. link
251
252
::
253
254
sage: cm.explain(ZZ['x'], ZZ, operator.mul)
255
Action discovered.
256
Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring
257
Result lives in Univariate Polynomial Ring in x over Integer Ring
258
Univariate Polynomial Ring in x over Integer Ring
259
260
sage: cm.explain(ZZ['x'], ZZ, operator.div)
261
Action discovered.
262
Right inverse action by Rational Field on Univariate Polynomial Ring in x over Integer Ring
263
with precomposition on right by Natural morphism:
264
From: Integer Ring
265
To: Rational Field
266
Result lives in Univariate Polynomial Ring in x over Rational Field
267
Univariate Polynomial Ring in x over Rational Field
268
269
sage: f = QQ.coerce_map_from(ZZ)
270
sage: f(3).parent()
271
Rational Field
272
273
Note that by :trac:`14711` Sage's coercion system uses maps with weak
274
references to the domain. Such maps should only be used internally, and so a
275
copy should be used instead (unless one knows what one is doing)::
276
277
sage: QQ._internal_coerce_map_from(int)
278
(map internal to coercion system -- copy before use)
279
Native morphism:
280
From: Set of Python objects of type 'int'
281
To: Rational Field
282
sage: copy(QQ._internal_coerce_map_from(int))
283
Native morphism:
284
From: Set of Python objects of type 'int'
285
To: Rational Field
286
287
Note that the user-visible method (without underscore) automates this copy::
288
289
sage: copy(QQ.coerce_map_from(int))
290
Native morphism:
291
From: Set of Python objects of type 'int'
292
To: Rational Field
293
294
::
295
296
sage: QQ.has_coerce_map_from(RR)
297
False
298
sage: QQ['x'].get_action(QQ)
299
Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Rational Field
300
sage: QQ2 = QQ^2
301
sage: (QQ2).get_action(QQ)
302
Right scalar multiplication by Rational Field on Vector space of dimension 2 over Rational Field
303
sage: QQ['x'].get_action(RR)
304
Right scalar multiplication by Real Field with 53 bits of precision on Univariate Polynomial Ring in x over Rational Field
305
306
How to Implement
307
----------------
308
309
Methods to implement
310
~~~~~~~~~~~~~~~~~~~~
311
312
* Arithmetic on Elements: ``_add_``, ``_sub_``, ``_mul_``, ``_div_``
313
314
This is where the binary arithmetic operators should be
315
implemented. Unlike Python's ``__add__``, both operands are
316
*guaranteed* to have the same Parent at this point.
317
318
* Coercion for Parents: ``_coerce_map_from_``
319
320
Given two parents R and S, ``R._coerce_map_from_(S)`` is called to
321
determine if there is a coercion `\phi: S \rightarrow R`. Note that
322
the function is called on the potential codomain. To indicate that
323
there is no coercion from S to R (self), return ``False`` or
324
``None``. This is the default behavior. If there is a coercion,
325
return ``True`` (in which case an morphism using
326
``R._element_constructor_`` will be created) or an actual
327
:class:`Morphism` object with S as the domain and R as the codomain.
328
329
* Actions for Parents: ``_get_action_`` or ``_rmul_``, ``_lmul_``, ``_r_action_``, ``_l_action_``
330
331
Suppose one wants R to act on S. Some examples of this could be
332
`R = \QQ`, `S = \QQ[x]` or `R = {\rm Gal}(S/\QQ)`
333
where `S` is a number field. There are several ways to implement this:
334
335
* If `R` is the base of `S` (as in the first example), simply
336
implement ``_rmul_`` and/or ``_lmul_`` on the Elements of `S`.
337
In this case ``r * s`` gets handled as ``s._rmul_(r)`` and
338
``s * r`` as ``s._lmul_(r)``. The argument to ``_rmul_``
339
and ``_lmul_`` are *guaranteed* to be Elements of the base of
340
`S` (with coercion happening beforehand if necessary).
341
342
* If `R` acts on `S`, one can alternatively define the methods
343
``_r_action_`` and/or ``_l_action_`` on the Elements of `R`.
344
There is no constraint on the type or parents of objects passed to
345
these methods; raise a ``TypeError`` or ``ValueError`` if the
346
wrong kind of object is passed in to indicate the action is not
347
appropriate here.
348
349
* If either `R` acts on `S` *or* `S` acts on `R`, one may implement
350
``R._get_action_`` to return an actual
351
:class:`~sage.categories.action.Action` object to be used. This
352
is how non-multiplicative actions must be implemented, and is the
353
most powerful (and completed) way to do things.
354
355
* Element conversion/construction for Parents: use
356
``_element_constructor_`` **not** ``__call__``
357
358
The :meth:`Parent.__call__` method dispatches to
359
``_element_constructor_``. When someone writes ``R(x, ...)``, this is
360
the method that eventually gets called in most cases. See the
361
documentation on the ``__call__`` method below.
362
363
Parents may also call the ``self._populate_coercion_lists_`` method in
364
their ``__init__`` functions to pass any callable for use instead of
365
``_element_constructor_``, provide a list of Parents with coercions to
366
self (as an alternative to implementing ``_coerce_map_from_``),
367
provide special construction methods (like ``_integer_`` for ZZ),
368
etc. This also allows one to specify a single coercion embedding *out*
369
of self (whereas the rest of the coercion functions all specify maps
370
*into* self). There is extensive documentation in the docstring of the
371
``_populate_coercion_lists_`` method.
372
373
Example
374
~~~~~~~
375
376
Sometimes a simple example is worth a thousand words. Here is a
377
minimal example of setting up a simple Ring that handles coercion. (It
378
is easy to imagine much more sophisticated and powerful localizations,
379
but that would obscure the main points being made here.)
380
381
::
382
383
class Localization(Ring):
384
def __init__(self, primes):
385
"""
386
Localization of `\ZZ` away from primes.
387
"""
388
Ring.__init__(self, base=ZZ)
389
self._primes = primes
390
self._populate_coercion_lists_()
391
392
def _repr_(self):
393
"""
394
How to print self.
395
"""
396
return "%s localized at %s" % (self.base(), self._primes)
397
398
def _element_constructor_(self, x):
399
"""
400
Make sure x is a valid member of self, and return the constructed element.
401
"""
402
if isinstance(x, LocalizationElement):
403
x = x._value
404
else:
405
x = QQ(x)
406
for p, e in x.denominator().factor():
407
if p not in self._primes:
408
raise ValueError("Not integral at %s" % p)
409
return LocalizationElement(self, x)
410
411
def _coerce_map_from_(self, S):
412
"""
413
The only things that coerce into this ring are:
414
415
- the integer ring
416
417
- other localizations away from fewer primes
418
"""
419
if S is ZZ:
420
return True
421
elif isinstance(S, Localization):
422
return all(p in self._primes for p in S._primes)
423
424
425
class LocalizationElement(RingElement):
426
427
def __init__(self, parent, x):
428
RingElement.__init__(self, parent)
429
self._value = x
430
431
432
# We're just printing out this way to make it easy to see what's going on in the examples.
433
434
def _repr_(self):
435
return "LocalElt(%s)" % self._value
436
437
# Now define addition, subtraction, and multiplication of elements.
438
# Note that left and right always have the same parent.
439
440
def _add_(left, right):
441
return LocalizationElement(left.parent(), left._value + right._value)
442
443
def _sub_(left, right):
444
return LocalizationElement(left.parent(), left._value - right._value)
445
446
def _mul_(left, right):
447
return LocalizationElement(left.parent(), left._value * right._value)
448
449
# The basering was set to ZZ, so c is guaranteed to be in ZZ
450
451
def _rmul_(self, c):
452
return LocalizationElement(self.parent(), c * self._value)
453
454
def _lmul_(self, c):
455
return LocalizationElement(self.parent(), self._value * c)
456
457
That's all there is to it. Now we can test it out:
458
459
.. skip
460
461
::
462
463
sage: R = Localization([2]); R
464
Integer Ring localized at [2]
465
sage: R(1)
466
LocalElt(1)
467
sage: R(1/2)
468
LocalElt(1/2)
469
sage: R(1/3)
470
Traceback (most recent call last):
471
...
472
ValueError: Not integral at 3
473
474
sage: R.coerce(1)
475
LocalElt(1)
476
sage: R.coerce(1/4)
477
Traceback (click to the left for traceback)
478
...
479
TypeError: no cannonical coercion from Rational Field to Integer Ring localized at [2]
480
481
sage: R(1/2) + R(3/4)
482
LocalElt(5/4)
483
sage: R(1/2) + 5
484
LocalElt(11/2)
485
sage: 5 + R(1/2)
486
LocalElt(11/2)
487
sage: R(1/2) + 1/7
488
Traceback (most recent call last):
489
...
490
TypeError: unsupported operand parent(s) for '+': 'Integer Ring localized at [2]' and 'Rational Field'
491
sage: R(3/4) * 7
492
LocalElt(21/4)
493
494
sage: R.get_action(ZZ)
495
Right scalar multiplication by Integer Ring on Integer Ring localized at [2]
496
sage: cm = sage.structure.element.get_coercion_model()
497
sage: cm.explain(R, ZZ, operator.add)
498
Coercion on right operand via
499
Conversion map:
500
From: Integer Ring
501
To: Integer Ring localized at [2]
502
Arithmetic performed after coercions.
503
Result lives in Integer Ring localized at [2]
504
Integer Ring localized at [2]
505
506
sage: cm.explain(R, ZZ, operator.mul)
507
Action discovered.
508
Right scalar multiplication by Integer Ring on Integer Ring localized at [2]
509
Result lives in Integer Ring localized at [2]
510
Integer Ring localized at [2]
511
512
sage: R6 = Localization([2,3]); R6
513
Integer Ring localized at [2, 3]
514
sage: R6(1/3) - R(1/2)
515
LocalElt(-1/6)
516
sage: parent(R6(1/3) - R(1/2))
517
Integer Ring localized at [2, 3]
518
519
sage: R.has_coerce_map_from(ZZ)
520
True
521
sage: R.coerce_map_from(ZZ)
522
Conversion map:
523
From: Integer Ring
524
To: Integer Ring localized at [2]
525
526
sage: R6.coerce_map_from(R)
527
Conversion map:
528
From: Integer Ring localized at [2]
529
To: Integer Ring localized at [2, 3]
530
531
sage: R6.coerce(R(1/2))
532
LocalElt(1/2)
533
534
sage: cm.explain(R, R6, operator.mul)
535
Coercion on left operand via
536
Conversion map:
537
From: Integer Ring localized at [2]
538
To: Integer Ring localized at [2, 3]
539
Arithmetic performed after coercions.
540
Result lives in Integer Ring localized at [2, 3]
541
Integer Ring localized at [2, 3]
542
543
Provided Methods
544
~~~~~~~~~~~~~~~~
545
546
* ``__call__``
547
548
This provides a consistent interface for element construction. In
549
particular, it makes sure that conversion always gives the same
550
result as coercion, if a coercion exists. (This used to be violated
551
for some Rings in Sage as the code for conversion and coercion got
552
edited separately.) Let R be a Parent and assume the user types
553
R(x), where x has parent X. Roughly speaking, the following occurs:
554
555
1. If X ``is`` R, return x (*)
556
557
2. If there is a coercion `f: X \rightarrow R`, return `f(x)`
558
559
3. If there is a coercion `f: R \rightarrow X`, try to return `{f^{-1}}(x)`
560
561
4. Return ``R._element_constructor_(x)`` (**)
562
563
Keywords and extra arguments are passed on. The result of all this logic is cached.
564
565
(*) Unless there is a "copy" keyword like R(x, copy=False)
566
567
(**) Technically, a generic morphism is created from X to R, which
568
may use magic methods like ``_integer_`` or other data provided by
569
``_populate_coercion_lists_``.
570
571
* ``coerce``
572
573
Coerces elements into self, raising a type error if there is no
574
coercion map.
575
576
* ``coerce_map_from, convert_map_from``
577
578
Returns an actual ``Morphism`` object to coerce/convert from
579
another Parent to self. Barring direct construction of elements of
580
R, ``R.convert_map_from(S)`` will provide a callable Python object
581
which is the fastest way to convert elements of S to elements of
582
R. From Cython, it can be invoked via the cdef ``_call_`` method.
583
584
* ``has_coerce_map_from``
585
586
Returns ``True`` or ``False`` depending on whether or not there is
587
a coercion. ``R.has_coerce_map_from(S)`` is shorthand for
588
``R.coerce_map_from(S) is not None``
589
590
* ``get_action``
591
592
This will unwind all the
593
``_rmul_, _lmul_, _r_action_, _l_action_, ...`` methods to provide
594
an actual ``Action`` object, if one exists.
595
596
597
Discovering new parents
598
-----------------------
599
600
New parents are discovered using an algorithm in
601
sage/category/pushout.py. The fundamental idea is that most Parents
602
in Sage are constructed from simpler objects via various functors.
603
These are accessed via the :meth:`construction` method, which returns a
604
(simpler) Parent along with a functor with which one can create self.
605
606
::
607
608
sage: CC.construction()
609
(AlgebraicClosureFunctor, Real Field with 53 bits of precision)
610
sage: RR.construction()
611
(Completion[+Infinity], Rational Field)
612
sage: QQ.construction()
613
(FractionField, Integer Ring)
614
sage: ZZ.construction() # None
615
616
sage: Qp(5).construction()
617
(Completion[5], Rational Field)
618
sage: QQ.completion(5, 100, {})
619
5-adic Field with capped relative precision 100
620
sage: c, R = RR.construction()
621
sage: a = CC.construction()[0]
622
sage: a.commutes(c)
623
False
624
sage: RR == c(QQ)
625
True
626
627
sage: sage.categories.pushout.construction_tower(Frac(CDF['x']))
628
[(None,
629
Fraction Field of Univariate Polynomial Ring in x over Complex Double Field),
630
(FractionField, Univariate Polynomial Ring in x over Complex Double Field),
631
(Poly[x], Complex Double Field),
632
(AlgebraicClosureFunctor, Real Double Field),
633
(Completion[+Infinity], Rational Field),
634
(FractionField, Integer Ring)]
635
636
Given Parents R and S, such that there is no coercion either from R to
637
S or from S to R, one can find a common Z with coercions
638
`R \rightarrow Z` and `S \rightarrow Z` by considering the sequence of
639
construction functors to get from a common ancestor to both R and S.
640
We then use a *heuristic* algorithm to interleave these constructors
641
in an attempt to arrive at a suitable Z (if one exists). For example::
642
643
sage: ZZ['x'].construction()
644
(Poly[x], Integer Ring)
645
sage: QQ.construction()
646
(FractionField, Integer Ring)
647
sage: sage.categories.pushout.pushout(ZZ['x'], QQ)
648
Univariate Polynomial Ring in x over Rational Field
649
sage: sage.categories.pushout.pushout(ZZ['x'], QQ).construction()
650
(Poly[x], Rational Field)
651
652
The common ancestor is `Z` and our options for Z are
653
`\mathrm{Frac}(\ZZ[x])` or `\mathrm{Frac}(\ZZ)[x]`.
654
In Sage we choose the later, treating the fraction
655
field functor as binding "more tightly" than the polynomial functor,
656
as most people agree that `\QQ[x]` is the more natural choice. The same
657
procedure is applied to more complicated Parents, returning a new
658
Parent if one can be unambiguously determined.
659
660
::
661
662
sage: sage.categories.pushout.pushout(Frac(ZZ['x,y,z']), QQ['z, t'])
663
Univariate Polynomial Ring in t over Fraction Field of Multivariate Polynomial Ring in x, y, z over Rational Field
664
665
Modules
666
-------
667
668
.. toctree::
669
:maxdepth: 2
670
671
sage/structure/coerce
672
sage/structure/coerce_actions
673
sage/structure/coerce_maps
674
675
676
.. include:: ../footer.txt
677
678