Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/structure/coerce.pyx
8814 views
1
r"""
2
The Coercion Model
3
4
The coercion model manages how elements of one parent get related to elements
5
of another. For example, the integer 2 can canonically be viewed as an element
6
of the rational numbers. (The Parent of a non-element is its Python type.)
7
8
::
9
10
sage: ZZ(2).parent()
11
Integer Ring
12
sage: QQ(2).parent()
13
Rational Field
14
15
The most prominent role of the coercion model is to make sense of binary
16
operations between elements that have distinct parents. It does this by
17
finding a parent where both elements make sense, and doing the operation
18
there. For example::
19
20
sage: a = 1/2; a.parent()
21
Rational Field
22
sage: b = ZZ[x].gen(); b.parent()
23
Univariate Polynomial Ring in x over Integer Ring
24
sage: a+b
25
x + 1/2
26
sage: (a+b).parent()
27
Univariate Polynomial Ring in x over Rational Field
28
29
If there is a coercion (see below) from one of the parents to the other,
30
the operation is always performed in the codomain of that coercion. Otherwise
31
a reasonable attempt to create a new parent with coercion maps from both
32
original parents is made. The results of these discoveries are cached.
33
On failure, a TypeError is always raised.
34
35
Some arithmetic operations (such as multiplication) can indicate an action
36
rather than arithmetic in a common parent. For example::
37
38
sage: E = EllipticCurve('37a')
39
sage: P = E(0,0)
40
sage: 5*P
41
(1/4 : -5/8 : 1)
42
43
where there is action of `\ZZ` on the points of `E` given by the additive
44
group law. Parents can specify how they act on or are acted upon by other
45
parents.
46
47
There are two kinds of ways to get from one parent to another, coercions and
48
conversions.
49
50
Coercions are canonical (possibly modulo a finite number of
51
deterministic choices) morphisms, and the set of all coercions between
52
all parents forms a commuting diagram (modulo possibly rounding
53
issues). `\ZZ \rightarrow \QQ` is an example of a
54
coercion. These are invoked implicitly by the coercion model.
55
56
Conversions try to construct an element out of their input if at all possible.
57
Examples include sections of coercions, creating an element from a string or
58
list, etc. and may fail on some inputs of a given type while succeeding on
59
others (i.e. they may not be defined on the whole domain). Conversions are
60
always explicitly invoked, and never used by the coercion model to resolve
61
binary operations.
62
63
For more information on how to specify coercions, conversions, and actions,
64
see the documentation for Parent.
65
"""
66
67
68
#*****************************************************************************
69
# Copyright (C) 2007 Robert Bradshaw <[email protected]>
70
#
71
# Distributed under the terms of the GNU General Public License (GPL)
72
#
73
# http://www.gnu.org/licenses/
74
#*****************************************************************************
75
76
77
include "sage/ext/stdsage.pxi"
78
from cpython.object cimport *
79
include "coerce.pxi"
80
81
import operator
82
83
from sage_object cimport SageObject
84
from sage.categories.map cimport Map
85
import sage.categories.morphism
86
from sage.categories.morphism import IdentityMorphism
87
from sage.categories.action import InverseAction, PrecomposedAction
88
from parent cimport Set_PythonType
89
from coerce_exceptions import CoercionException
90
91
import sys, traceback
92
93
from coerce_actions import LeftModuleAction, RightModuleAction, IntegerMulAction
94
95
cpdef py_scalar_parent(py_type):
96
"""
97
Returns the Sage equivalent of the given python type, if one exists.
98
If there is no equivalent, return None.
99
100
EXAMPLES::
101
102
sage: from sage.structure.coerce import py_scalar_parent
103
sage: py_scalar_parent(int)
104
Integer Ring
105
sage: py_scalar_parent(long)
106
Integer Ring
107
sage: py_scalar_parent(float)
108
Real Double Field
109
sage: py_scalar_parent(complex)
110
Complex Double Field
111
sage: py_scalar_parent(dict),
112
(None,)
113
"""
114
if py_type is int or py_type is long:
115
import sage.rings.integer_ring
116
return sage.rings.integer_ring.ZZ
117
elif py_type is float:
118
import sage.rings.real_double
119
return sage.rings.real_double.RDF
120
elif py_type is complex:
121
import sage.rings.complex_double
122
return sage.rings.complex_double.CDF
123
else:
124
return None
125
126
cdef object _native_coercion_ranks_inv = (bool, int, long, float, complex)
127
cdef object _native_coercion_ranks = dict([(t, k) for k, t in enumerate(_native_coercion_ranks_inv)])
128
129
cdef object _Integer
130
cdef bint is_Integer(x):
131
global _Integer
132
if _Integer is None:
133
from sage.rings.integer import Integer as _Integer
134
return PY_TYPE_CHECK_EXACT(x, _Integer) or PY_TYPE_CHECK_EXACT(x, int)
135
136
cdef class CoercionModel_cache_maps(CoercionModel):
137
"""
138
See also sage.categories.pushout
139
140
EXAMPLES::
141
142
sage: f = ZZ['t','x'].0 + QQ['x'].0 + CyclotomicField(13).gen(); f
143
t + x + (zeta13)
144
sage: f.parent()
145
Multivariate Polynomial Ring in t, x over Cyclotomic Field of order 13 and degree 12
146
sage: ZZ['x','y'].0 + ~Frac(QQ['y']).0
147
(x*y + 1)/y
148
sage: MatrixSpace(ZZ['x'], 2, 2)(2) + ~Frac(QQ['x']).0
149
[(2*x + 1)/x 0]
150
[ 0 (2*x + 1)/x]
151
sage: f = ZZ['x,y,z'].0 + QQ['w,x,z,a'].0; f
152
w + x
153
sage: f.parent()
154
Multivariate Polynomial Ring in w, x, y, z, a over Rational Field
155
sage: ZZ['x,y,z'].0 + ZZ['w,x,z,a'].1
156
2*x
157
158
AUTHOR:
159
160
- Robert Bradshaw
161
"""
162
163
def __init__(self, lookup_dict_size=127, lookup_dict_threshold=.75):
164
"""
165
INPUT:
166
167
- ``lookup_dict_size`` - initial size of the coercion hashtables
168
169
- ``lookup_dict_threshold`` - maximal density of the coercion
170
hashtables before forcing a re-hash
171
172
EXAMPLES::
173
174
sage: from sage.structure.coerce import CoercionModel_cache_maps
175
sage: cm = CoercionModel_cache_maps(4, .95)
176
sage: A = cm.get_action(ZZ, NumberField(x^2-2, 'a'), operator.mul)
177
sage: f, g = cm.coercion_maps(QQ, int)
178
sage: f, g = cm.coercion_maps(ZZ, int)
179
180
.. note::
181
182
In practice 4 would be a really bad number to choose, but
183
it makes the hashing deterministic.
184
"""
185
self.reset_cache(lookup_dict_size, lookup_dict_threshold)
186
187
def reset_cache(self, lookup_dict_size=127, lookup_dict_threshold=.75):
188
"""
189
Clear the coercion cache.
190
191
This should have no impact on the result of arithmetic operations, as
192
the exact same coercions and actions will be re-discovered when needed.
193
194
It may be useful for debugging, and may also free some memory.
195
196
EXAMPLES::
197
198
sage: cm = sage.structure.element.get_coercion_model()
199
sage: len(cm.get_cache()[0]) # random
200
42
201
sage: cm.reset_cache()
202
sage: cm.get_cache()
203
({}, {})
204
"""
205
# This MUST be a mapping of tuples, where each
206
# tuple contains at least two elements that are either
207
# None or of type Map.
208
self._coercion_maps = TripleDict(lookup_dict_size, threshold=lookup_dict_threshold)
209
# This MUST be a mapping to actions.
210
self._action_maps = TripleDict(lookup_dict_size, threshold=lookup_dict_threshold)
211
# This is a mapping from Parents to Parents, storing the result of division in the given parent.
212
self._division_parents = TripleDict(lookup_dict_size, threshold=lookup_dict_threshold)
213
214
def get_cache(self):
215
"""
216
This returns the current cache of coercion maps and actions, primarily
217
useful for debugging and introspection.
218
219
EXAMPLES::
220
221
sage: 1 + 1/2
222
3/2
223
sage: cm = sage.structure.element.get_coercion_model()
224
sage: maps, actions = cm.get_cache()
225
226
Now lets see what happens when we do a binary operations with
227
an integer and a rational::
228
229
sage: left_morphism, right_morphism = maps[ZZ, QQ]
230
sage: print left_morphism
231
Natural morphism:
232
From: Integer Ring
233
To: Rational Field
234
sage: print right_morphism
235
None
236
237
We can see that it coerces the left operand from an integer to a
238
rational, and doesn't do anything to the right.
239
240
Now for some actions::
241
242
sage: R.<x> = ZZ['x']
243
sage: 1/2 * x
244
1/2*x
245
sage: maps, actions = cm.get_cache()
246
sage: act = actions[QQ, R, operator.mul]; act
247
Left scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring
248
sage: act.actor()
249
Rational Field
250
sage: act.domain()
251
Univariate Polynomial Ring in x over Integer Ring
252
sage: act.codomain()
253
Univariate Polynomial Ring in x over Rational Field
254
sage: act(1/5, x+10)
255
1/5*x + 2
256
"""
257
return dict([((S, R), mors) for (S, R, op), mors in self._coercion_maps.iteritems()]), \
258
dict(self._action_maps.iteritems())
259
260
def record_exceptions(self, bint value=True):
261
r"""
262
Enables (or disables) recording of the exceptions suppressed during
263
arithmetic.
264
265
Each time that record_exceptions is called (either enabling or disabling
266
the record), the exception_stack is cleared.
267
268
TESTS::
269
270
sage: cm = sage.structure.element.get_coercion_model()
271
sage: cm.record_exceptions()
272
sage: cm._test_exception_stack()
273
sage: cm.exception_stack()
274
['Traceback (most recent call last):\n File "coerce.pyx", line ...TypeError: just a test']
275
sage: cm.record_exceptions(False)
276
sage: cm._test_exception_stack()
277
sage: cm.exception_stack()
278
[]
279
"""
280
self._record_exceptions = value
281
self._exceptions_cleared = True
282
self._exception_stack = []
283
284
cpdef _record_exception(self):
285
r"""
286
Pushes the last exception that occurred onto the stack for later reference,
287
for internal use.
288
289
If the stack has not yet been flagged as cleared, we clear it now (rather
290
than wasting time to do so for successful operations).
291
292
TEST::
293
294
sage: cm = sage.structure.element.get_coercion_model()
295
sage: cm.record_exceptions()
296
sage: 1+1/2+2 # make sure there aren't any errors hanging around
297
7/2
298
sage: cm.exception_stack()
299
[]
300
sage: cm._test_exception_stack()
301
sage: cm.exception_stack()
302
['Traceback (most recent call last):\n File "coerce.pyx", line ...TypeError: just a test']
303
304
The function _test_exception_stack is executing the following code::
305
306
try:
307
raise TypeError, "just a test"
308
except TypeError:
309
cm._record_exception()
310
"""
311
if not self._record_exceptions:
312
return
313
if not self._exceptions_cleared:
314
self._exception_stack = []
315
self._exceptions_cleared = True
316
self._exception_stack.append(traceback.format_exc().strip())
317
318
def _test_exception_stack(self):
319
r"""
320
A function to test the exception stack.
321
322
EXAMPLES::
323
324
sage: cm = sage.structure.element.get_coercion_model()
325
sage: cm.record_exceptions()
326
sage: 1 + 1/11 # make sure there aren't any errors hanging around
327
12/11
328
sage: cm.exception_stack()
329
[]
330
sage: cm._test_exception_stack()
331
sage: cm.exception_stack()
332
['Traceback (most recent call last):\n File "coerce.pyx", line ...TypeError: just a test']
333
"""
334
try:
335
raise TypeError, "just a test"
336
except TypeError:
337
self._record_exception()
338
339
def exception_stack(self):
340
r"""
341
Returns the list of exceptions that were caught in the course of
342
executing the last binary operation. Useful for diagnosis when
343
user-defined maps or actions raise exceptions that are caught in
344
the course of coercion detection.
345
346
If all went well, this should be the empty list. If things aren't
347
happening as you expect, this is a good place to check. See also
348
:func:`coercion_traceback`.
349
350
EXAMPLES::
351
352
sage: cm = sage.structure.element.get_coercion_model()
353
sage: cm.record_exceptions()
354
sage: 1/2 + 2
355
5/2
356
sage: cm.exception_stack()
357
[]
358
sage: 1/2 + GF(3)(2)
359
Traceback (most recent call last):
360
...
361
TypeError: unsupported operand parent(s) for '+': 'Rational Field' and 'Finite Field of size 3'
362
363
Now see what the actual problem was::
364
365
sage: import traceback
366
sage: cm.exception_stack()
367
['Traceback (most recent call last):...', 'Traceback (most recent call last):...']
368
sage: print cm.exception_stack()[-1]
369
Traceback (most recent call last):
370
...
371
TypeError: no common canonical parent for objects with parents: 'Rational Field' and 'Finite Field of size 3'
372
373
This is typically accessed via the :func:`coercion_traceback` function.
374
375
::
376
377
sage: coercion_traceback()
378
Traceback (most recent call last):
379
...
380
TypeError: no common canonical parent for objects with parents: 'Rational Field' and 'Finite Field of size 3'
381
"""
382
if not self._exceptions_cleared:
383
self._exception_stack = []
384
self._exceptions_cleared = True
385
return self._exception_stack
386
387
388
def explain(self, xp, yp, op=operator.mul, int verbosity=2):
389
"""
390
This function can be used to understand what coercions will happen
391
for an arithmetic operation between xp and yp (which may be either
392
elements or parents). If the parent of the result can be determined
393
then it will be returned.
394
395
EXAMPLES::
396
397
sage: cm = sage.structure.element.get_coercion_model()
398
399
sage: cm.explain(ZZ, ZZ)
400
Identical parents, arithmetic performed immediately.
401
Result lives in Integer Ring
402
Integer Ring
403
404
sage: cm.explain(QQ, int)
405
Coercion on right operand via
406
Native morphism:
407
From: Set of Python objects of type 'int'
408
To: Rational Field
409
Arithmetic performed after coercions.
410
Result lives in Rational Field
411
Rational Field
412
413
sage: cm.explain(ZZ['x'], QQ)
414
Action discovered.
415
Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring
416
Result lives in Univariate Polynomial Ring in x over Rational Field
417
Univariate Polynomial Ring in x over Rational Field
418
419
sage: cm.explain(ZZ['x'], QQ, operator.add)
420
Coercion on left operand via
421
Conversion map:
422
From: Univariate Polynomial Ring in x over Integer Ring
423
To: Univariate Polynomial Ring in x over Rational Field
424
Coercion on right operand via
425
Polynomial base injection morphism:
426
From: Rational Field
427
To: Univariate Polynomial Ring in x over Rational Field
428
Arithmetic performed after coercions.
429
Result lives in Univariate Polynomial Ring in x over Rational Field
430
Univariate Polynomial Ring in x over Rational Field
431
432
Sometimes with non-sage types there is not enough information to deduce
433
what will actually happen::
434
435
sage: cm.explain(RealField(100), float, operator.add)
436
Right operand is numeric, will attempt coercion in both directions.
437
Unknown result parent.
438
sage: parent(RealField(100)(1) + float(1))
439
<type 'float'>
440
sage: cm.explain(QQ, float, operator.add)
441
Right operand is numeric, will attempt coercion in both directions.
442
Unknown result parent.
443
sage: parent(QQ(1) + float(1))
444
<type 'float'>
445
446
447
Special care is taken to deal with division::
448
449
sage: cm.explain(ZZ, ZZ, operator.div)
450
Identical parents, arithmetic performed immediately.
451
Result lives in Rational Field
452
Rational Field
453
454
sage: cm.explain(ZZ['x'], QQ['x'], operator.div)
455
Coercion on left operand via
456
Conversion map:
457
From: Univariate Polynomial Ring in x over Integer Ring
458
To: Univariate Polynomial Ring in x over Rational Field
459
Arithmetic performed after coercions.
460
Result lives in Fraction Field of Univariate Polynomial Ring in x over Rational Field
461
Fraction Field of Univariate Polynomial Ring in x over Rational Field
462
463
sage: cm.explain(int, ZZ, operator.div)
464
Coercion on left operand via
465
Native morphism:
466
From: Set of Python objects of type 'int'
467
To: Integer Ring
468
Arithmetic performed after coercions.
469
Result lives in Rational Field
470
Rational Field
471
472
sage: cm.explain(ZZ['x'], ZZ, operator.div)
473
Action discovered.
474
Right inverse action by Rational Field on Univariate Polynomial Ring in x over Integer Ring
475
with precomposition on right by Natural morphism:
476
From: Integer Ring
477
To: Rational Field
478
Result lives in Univariate Polynomial Ring in x over Rational Field
479
Univariate Polynomial Ring in x over Rational Field
480
481
.. note::
482
483
This function is accurate only in so far as analyse is kept
484
in sync with the :meth:`bin_op` and
485
:meth:`canonical_coercion` which are kept separate for
486
maximal efficiency.
487
"""
488
all, res = self.analyse(xp, yp, op)
489
indent = " "*4
490
if verbosity >= 2:
491
print "\n".join([s if isinstance(s, str) else indent+(repr(s).replace("\n", "\n"+indent)) for s in all])
492
elif verbosity >= 1:
493
print "\n".join([s for s in all if isinstance(s, str)])
494
if verbosity >= 1:
495
if res is None:
496
print "Unknown result parent."
497
else:
498
print "Result lives in", res
499
return res
500
501
cpdef analyse(self, xp, yp, op=mul):
502
"""
503
Emulate the process of doing arithmetic between xp and yp, returning
504
a list of steps and the parent that the result will live in. The
505
``explain`` function is easier to use, but if one wants access to
506
the actual morphism and action objects (rather than their string
507
representations) then this is the function to use.
508
509
EXAMPLES::
510
511
sage: cm = sage.structure.element.get_coercion_model()
512
sage: steps, res = cm.analyse(GF(7), ZZ)
513
sage: print steps
514
['Coercion on right operand via', Natural morphism:
515
From: Integer Ring
516
To: Finite Field of size 7, 'Arithmetic performed after coercions.']
517
sage: print res
518
Finite Field of size 7
519
sage: f = steps[1]; type(f)
520
<type 'sage.rings.finite_rings.integer_mod.Integer_to_IntegerMod'>
521
sage: f(100)
522
2
523
"""
524
self._exceptions_cleared = False
525
res = None
526
if not PY_TYPE_CHECK(xp, type) and not PY_TYPE_CHECK(xp, Parent):
527
xp = parent_c(xp)
528
if not PY_TYPE_CHECK(yp, type) and not PY_TYPE_CHECK(yp, Parent):
529
yp = parent_c(yp)
530
531
all = []
532
if xp is yp:
533
all.append("Identical parents, arithmetic performed immediately." % xp)
534
if op is div and PY_TYPE_CHECK(xp, Parent):
535
xp = self.division_parent(xp)
536
return all, xp
537
if xp == yp:
538
all.append("Equal but distinct parents.")
539
540
if (op is not sub) and (op is not isub):
541
action = self.get_action(xp, yp, op)
542
if action is not None:
543
all.append("Action discovered.")
544
all.append(action)
545
return all, action.codomain()
546
547
homs = self.discover_coercion(xp, yp)
548
if homs is not None:
549
x_mor, y_mor = homs
550
if x_mor is not None:
551
all.append("Coercion on left operand via")
552
all.append(x_mor)
553
res = x_mor.codomain()
554
if y_mor is not None:
555
all.append("Coercion on right operand via")
556
all.append(y_mor)
557
if res is not None and res is not y_mor.codomain():
558
raise RuntimeError, ("BUG in coercion model: codomains not equal!", x_mor, y_mor)
559
res = y_mor.codomain()
560
all.append("Arithmetic performed after coercions.")
561
if op is div and PY_TYPE_CHECK(res, Parent):
562
res = self.division_parent(res)
563
return all, res
564
565
if PY_TYPE_CHECK(yp, Parent) and xp in [int, long, float, complex, bool]:
566
mor = yp.coerce_map_from(xp)
567
if mor is not None:
568
all.append("Coercion on numeric left operand via")
569
all.append(mor)
570
if op is div and PY_TYPE_CHECK(yp, Parent):
571
yp = self.division_parent(yp)
572
return all, yp
573
all.append("Left operand is numeric, will attempt coercion in both directions.")
574
elif type(xp) is type:
575
all.append("Left operand is not Sage element, will try _sage_.")
576
577
if PY_TYPE_CHECK(xp, Parent) and yp in [int, long, float, complex, bool]:
578
mor = xp.coerce_map_from(yp)
579
if mor is not None:
580
all.append("Coercion on numeric right operand via")
581
all.append(mor)
582
if op is div and PY_TYPE_CHECK(xp, Parent):
583
xp = self.division_parent(xp)
584
return all, xp
585
all.append("Right operand is numeric, will attempt coercion in both directions.")
586
elif type(yp) is type:
587
all.append("Right operand is not Sage element, will try _sage_.")
588
589
if op is mul or op is imul:
590
all.append("Will try _r_action and _l_action")
591
592
return all, None
593
594
def common_parent(self, *args):
595
"""
596
Computes a common parent for all the inputs. It's essentially
597
an `n`-ary canonical coercion except it can operate on parents
598
rather than just elements.
599
600
INPUT:
601
602
- ``args`` -- a set of elements and/or parents
603
604
OUTPUT:
605
606
A :class:`Parent` into which each input should coerce, or raises a
607
``TypeError`` if no such :class:`Parent` can be found.
608
609
EXAMPLES::
610
611
sage: cm = sage.structure.element.get_coercion_model()
612
sage: cm.common_parent(ZZ, QQ)
613
Rational Field
614
sage: cm.common_parent(ZZ, QQ, RR)
615
Real Field with 53 bits of precision
616
sage: cm.common_parent(ZZ[['T']], QQ['T'], RDF)
617
Power Series Ring in T over Real Double Field
618
sage: cm.common_parent(4r, 5r)
619
<type 'int'>
620
sage: cm.common_parent(int, float, ZZ)
621
<type 'float'>
622
sage: cm.common_parent(*[RealField(prec) for prec in [10,20..100]])
623
Real Field with 10 bits of precision
624
625
There are some cases where the ordering does matter, but if a parent
626
can be found it is always the same::
627
628
sage: cm.common_parent(QQ['x,y'], QQ['y,z']) == cm.common_parent(QQ['y,z'], QQ['x,y'])
629
True
630
sage: cm.common_parent(QQ['x,y'], QQ['y,z'], QQ['z,t'])
631
Multivariate Polynomial Ring in x, y, z, t over Rational Field
632
sage: cm.common_parent(QQ['x,y'], QQ['z,t'], QQ['y,z'])
633
Traceback (most recent call last):
634
...
635
TypeError: no common canonical parent for objects with parents: 'Multivariate Polynomial Ring in x, y over Rational Field' and 'Multivariate Polynomial Ring in z, t over Rational Field'
636
"""
637
base = None
638
for x in args:
639
if not isinstance(x, Parent) and not isinstance(x, type):
640
x = parent_c(x)
641
if base is None:
642
base = x
643
if isinstance(base, Parent) and (<Parent>base).has_coerce_map_from(x):
644
continue
645
elif isinstance(x, Parent) and (<Parent>x).has_coerce_map_from(base):
646
base = x
647
else:
648
a = base.an_element() if isinstance(base, Parent) else base(1)
649
b = x.an_element() if isinstance(x, Parent) else x(1)
650
base = parent_c(self.canonical_coercion(a, b)[0])
651
return base
652
653
cpdef Parent division_parent(self, Parent parent):
654
r"""
655
Deduces where the result of division in parent lies by calculating
656
the inverse of ``parent.one_element()`` or ``parent.an_element()``.
657
658
The result is cached.
659
660
EXAMPLES::
661
662
sage: cm = sage.structure.element.get_coercion_model()
663
sage: cm.division_parent(ZZ)
664
Rational Field
665
sage: cm.division_parent(QQ)
666
Rational Field
667
sage: cm.division_parent(ZZ['x'])
668
Fraction Field of Univariate Polynomial Ring in x over Integer Ring
669
sage: cm.division_parent(GF(41))
670
Finite Field of size 41
671
sage: cm.division_parent(Integers(100))
672
Ring of integers modulo 100
673
sage: cm.division_parent(SymmetricGroup(5))
674
Symmetric group of order 5! as a permutation group
675
"""
676
try:
677
return self._division_parents.get(parent, None, None)
678
except KeyError:
679
pass
680
try:
681
ret = parent_c(~parent.one_element())
682
except Exception:
683
self._record_exception()
684
ret = parent_c(~parent.an_element())
685
self._division_parents.set(parent, None, None, ret)
686
return ret
687
688
689
cpdef bin_op(self, x, y, op):
690
"""
691
Execute the operation op on x and y. It first looks for an action
692
corresponding to op, and failing that, it tries to coerces x and y
693
into the a common parent and calls op on them.
694
695
If it cannot make sense of the operation, a TypeError is raised.
696
697
INPUT:
698
699
- ``x`` - the left operand
700
701
- ``y`` - the right operand
702
703
- ``op`` - a python function taking 2 arguments
704
705
.. note::
706
707
op is often an arithmetic operation, but need not be so.
708
709
EXAMPLES::
710
711
sage: cm = sage.structure.element.get_coercion_model()
712
sage: cm.bin_op(1/2, 5, operator.mul)
713
5/2
714
715
The operator can be any callable::
716
717
set Rational Field Integer Ring <function <lambda> at 0xc0b2270> None None
718
(Rational Field, Rational Field)
719
sage: R.<x> = ZZ['x']
720
sage: cm.bin_op(x^2-1, x+1, gcd)
721
x + 1
722
723
Actions are detected and performed::
724
725
sage: M = matrix(ZZ, 2, 2, range(4))
726
sage: V = vector(ZZ, [5,7])
727
sage: cm.bin_op(M, V, operator.mul)
728
(7, 31)
729
730
TESTS::
731
732
sage: class Foo:
733
... def __rmul__(self, left):
734
... return 'hello'
735
...
736
sage: H = Foo()
737
sage: print int(3)*H
738
hello
739
sage: print Integer(3)*H
740
hello
741
sage: print H*3
742
Traceback (most recent call last):
743
...
744
TypeError: unsupported operand parent(s) for '*': '<type 'instance'>' and 'Integer Ring'
745
746
sage: class Nonsense:
747
... def __init__(self, s):
748
... self.s = s
749
... def __repr__(self):
750
... return self.s
751
... def __mul__(self, x):
752
... return Nonsense(self.s + chr(x%256))
753
... __add__ = __mul__
754
... def __rmul__(self, x):
755
... return Nonsense(chr(x%256) + self.s)
756
... __radd__ = __rmul__
757
...
758
sage: a = Nonsense('blahblah')
759
sage: a*80
760
blahblahP
761
sage: 80*a
762
Pblahblah
763
sage: a+80
764
blahblahP
765
sage: 80+a
766
Pblahblah
767
768
"""
769
self._exceptions_cleared = False
770
if (op is not sub) and (op is not isub):
771
# Actions take preference over common-parent coercions.
772
xp = parent_c(x)
773
yp = parent_c(y)
774
if xp is yp:
775
return op(x,y)
776
action = self.get_action(xp, yp, op, x, y)
777
if action is not None:
778
return (<Action>action)._call_(x, y)
779
780
xy = None
781
try:
782
xy = self.canonical_coercion(x,y)
783
return PyObject_CallObject(op, xy)
784
except TypeError, err:
785
if xy is not None:
786
# The error was in calling, not coercing
787
raise
788
self._record_exception()
789
790
if op is mul or op is imul:
791
792
# elements may also act on non-elements
793
# (e.g. sequences or parents)
794
if not isinstance(y, Element) or not isinstance(x, Element):
795
try:
796
if hasattr(x, '_act_on_'):
797
res = x._act_on_(y, True)
798
if res is not None: return res
799
except CoercionException:
800
self._record_exception()
801
802
try:
803
if hasattr(x, '_acted_upon_'):
804
res = x._acted_upon_(y, True)
805
if res is not None: return res
806
except CoercionException:
807
self._record_exception()
808
809
try:
810
if hasattr(y, '_act_on_'):
811
res = y._act_on_(x, False)
812
if res is not None: return res
813
except CoercionException:
814
self._record_exception()
815
816
try:
817
if hasattr(y, '_acted_upon_'):
818
res = y._acted_upon_(x, False)
819
if res is not None: return res
820
except CoercionException:
821
self._record_exception()
822
823
if not isinstance(y, Element):
824
op_name = op.__name__
825
if op_name[0] == 'i':
826
op_name = op_name[1:]
827
mul_method = getattr3(y, '__r%s__'%op_name, None)
828
if mul_method is not None:
829
res = mul_method(x)
830
if res is not None and res is not NotImplemented:
831
return res
832
833
# We should really include the underlying error.
834
# This causes so much headache.
835
raise TypeError, arith_error_message(x,y,op)
836
837
cpdef canonical_coercion(self, x, y):
838
r"""
839
Given two elements x and y, with parents S and R respectively,
840
find a common parent Z such that there are coercions
841
`f: S \mapsto Z` and `g: R \mapsto Z` and return `f(x), g(y)`
842
which will have the same parent.
843
844
Raises a type error if no such Z can be found.
845
846
EXAMPLES::
847
848
sage: cm = sage.structure.element.get_coercion_model()
849
sage: cm.canonical_coercion(mod(2, 10), 17)
850
(2, 7)
851
sage: x, y = cm.canonical_coercion(1/2, matrix(ZZ, 2, 2, range(4)))
852
sage: x
853
[1/2 0]
854
[ 0 1/2]
855
sage: y
856
[0 1]
857
[2 3]
858
sage: parent(x) is parent(y)
859
True
860
861
There is some support for non-Sage datatypes as well::
862
863
sage: x, y = cm.canonical_coercion(int(5), 10)
864
sage: type(x), type(y)
865
(<type 'sage.rings.integer.Integer'>, <type 'sage.rings.integer.Integer'>)
866
867
868
sage: x, y = cm.canonical_coercion(int(5), complex(3))
869
sage: type(x), type(y)
870
(<type 'complex'>, <type 'complex'>)
871
872
sage: class MyClass:
873
... def _sage_(self):
874
... return 13
875
sage: a, b = cm.canonical_coercion(MyClass(), 1/3)
876
sage: a, b
877
(13, 1/3)
878
sage: type(a)
879
<type 'sage.rings.rational.Rational'>
880
881
We also make an exception for 0, even if $\ZZ$ does not map in::
882
883
sage: canonical_coercion(vector([1, 2, 3]), 0)
884
((1, 2, 3), (0, 0, 0))
885
"""
886
xp = parent_c(x)
887
yp = parent_c(y)
888
if xp is yp:
889
return x,y
890
891
cdef Element x_elt, y_elt
892
coercions = self.coercion_maps(xp, yp)
893
if coercions is not None:
894
x_map, y_map = coercions
895
if x_map is not None:
896
x_elt = (<Map>x_map)._call_(x)
897
else:
898
x_elt = x
899
if y_map is not None:
900
y_elt = (<Map>y_map)._call_(y)
901
else:
902
y_elt = y
903
if x_elt is None:
904
raise RuntimeError, "BUG in map, returned None %s %s %s" % (x, type(x_map), x_map)
905
elif y_elt is None:
906
raise RuntimeError, "BUG in map, returned None %s %s %s" % (y, type(y_map), y_map)
907
if x_elt._parent is y_elt._parent:
908
# We must verify this as otherwise we are prone to
909
# getting into an infinite loop in c, and the above
910
# maps may be written by (imperfect) users.
911
return x_elt,y_elt
912
elif x_elt._parent == y_elt._parent:
913
# TODO: Non-uniqueness of parents strikes again!
914
# print parent_c(x_elt), " is not ", parent_c(y_elt)
915
y_elt = parent_c(x_elt)(y_elt)
916
if x_elt._parent is y_elt._parent:
917
return x_elt,y_elt
918
self._coercion_error(x, x_map, x_elt, y, y_map, y_elt)
919
920
921
cdef bint x_numeric = PY_IS_NUMERIC(x)
922
cdef bint y_numeric = PY_IS_NUMERIC(y)
923
924
if x_numeric and y_numeric:
925
x_rank = _native_coercion_ranks[type(x)]
926
y_rank = _native_coercion_ranks[type(y)]
927
ty = _native_coercion_ranks_inv[max(x_rank, y_rank)]
928
x = ty(x)
929
y = ty(y)
930
return x, y
931
932
# Now handle the native python + sage object cases
933
# that were not taken care of above.
934
elif x_numeric:
935
try:
936
sage_parent = py_scalar_parent(type(x))
937
if sage_parent is None or sage_parent.has_coerce_map_from(yp):
938
return x, x.__class__(y)
939
else:
940
return self.canonical_coercion(sage_parent(x), y)
941
except (TypeError, ValueError):
942
self._record_exception()
943
944
elif y_numeric:
945
try:
946
sage_parent = py_scalar_parent(type(y))
947
if sage_parent is None or sage_parent.has_coerce_map_from(xp):
948
return y.__class__(x), y
949
else:
950
return self.canonical_coercion(x, sage_parent(y))
951
except (TypeError, ValueError):
952
self._record_exception()
953
954
# See if the non-objects define a _sage_ method.
955
if not PY_TYPE_CHECK(x, SageObject) or not PY_TYPE_CHECK(y, SageObject):
956
try:
957
x = x._sage_()
958
y = y._sage_()
959
except AttributeError:
960
self._record_exception()
961
else:
962
return self.canonical_coercion(x, y)
963
964
# Allow coercion of 0 even if no coercion from Z
965
if is_Integer(x) and not x and not PY_TYPE_CHECK_EXACT(yp, type):
966
try:
967
return yp(0), y
968
except Exception:
969
self._record_exception()
970
971
if is_Integer(y) and not y and not PY_TYPE_CHECK_EXACT(xp, type):
972
try:
973
return x, xp(0)
974
except Exception:
975
self._record_exception()
976
977
raise TypeError, "no common canonical parent for objects with parents: '%s' and '%s'"%(xp, yp)
978
979
980
cpdef coercion_maps(self, R, S):
981
r"""
982
Give two parents R and S, return a pair of coercion maps
983
`f: R \rightarrow Z` and `g: S \rightarrow Z` , if such a `Z`
984
can be found.
985
986
In the (common) case that `R=Z` or `S=Z` then ``None`` is returned
987
for `f` or `g` respectively rather than constructing (and subsequently
988
calling) the identity morphism.
989
990
If no suitable `f, g` can be found, a single None is returned.
991
This result is cached.
992
993
EXAMPLES::
994
995
sage: cm = sage.structure.element.get_coercion_model()
996
sage: f, g = cm.coercion_maps(ZZ, QQ)
997
sage: print f
998
Natural morphism:
999
From: Integer Ring
1000
To: Rational Field
1001
sage: print g
1002
None
1003
1004
sage: f, g = cm.coercion_maps(ZZ['x'], QQ)
1005
sage: print f
1006
Conversion map:
1007
From: Univariate Polynomial Ring in x over Integer Ring
1008
To: Univariate Polynomial Ring in x over Rational Field
1009
sage: print g
1010
Polynomial base injection morphism:
1011
From: Rational Field
1012
To: Univariate Polynomial Ring in x over Rational Field
1013
1014
sage: cm.coercion_maps(QQ, GF(7)) == None
1015
True
1016
1017
Note that to break symmetry, if there is a coercion map in both
1018
directions, the parent on the left is used::
1019
1020
sage: V = QQ^3
1021
sage: W = V.__class__(QQ, 3)
1022
sage: V == W
1023
True
1024
sage: V is W
1025
False
1026
sage: cm = sage.structure.element.get_coercion_model()
1027
sage: cm.coercion_maps(V, W)
1028
(None,
1029
Call morphism:
1030
From: Vector space of dimension 3 over Rational Field
1031
To: Vector space of dimension 3 over Rational Field)
1032
sage: cm.coercion_maps(W, V)
1033
(None,
1034
Call morphism:
1035
From: Vector space of dimension 3 over Rational Field
1036
To: Vector space of dimension 3 over Rational Field)
1037
sage: v = V([1,2,3])
1038
sage: w = W([1,2,3])
1039
sage: parent(v+w) is V
1040
True
1041
sage: parent(w+v) is W
1042
True
1043
"""
1044
try:
1045
return self._coercion_maps.get(R, S, None)
1046
except KeyError:
1047
homs = self.discover_coercion(R, S)
1048
if 0:
1049
# This breaks too many things that are going to change
1050
# in the new coercion model anyways.
1051
# COERCE TODO: Enable it then.
1052
homs = self.verify_coercion_maps(R, S, homs)
1053
else:
1054
if homs is not None:
1055
x_map, y_map = homs
1056
if x_map is not None and not isinstance(x_map, Map):
1057
raise RuntimeError, "BUG in coercion model: coerce_map_from must return a Map"
1058
if y_map is not None and not isinstance(y_map, Map):
1059
raise RuntimeError, "BUG in coercion model: coerce_map_from must return a Map"
1060
if homs is None:
1061
swap = None
1062
else:
1063
R_map, S_map = homs
1064
if R_map is None and PY_TYPE_CHECK(S, Parent) and (<Parent>S).has_coerce_map_from(R):
1065
swap = None, (<Parent>S).coerce_map_from(R)
1066
else:
1067
swap = S_map, R_map
1068
self._coercion_maps.set(R, S, None, homs)
1069
self._coercion_maps.set(S, R, None, swap)
1070
return homs
1071
1072
cpdef verify_coercion_maps(self, R, S, homs, bint fix=False):
1073
"""
1074
Make sure this is a valid pair of homomorphisms from R and S to a common parent.
1075
This function is used to protect the user against buggy parents.
1076
1077
EXAMPLES::
1078
1079
sage: cm = sage.structure.element.get_coercion_model()
1080
sage: homs = QQ.coerce_map_from(ZZ), None
1081
sage: cm.verify_coercion_maps(ZZ, QQ, homs) == homs
1082
True
1083
sage: homs = QQ.coerce_map_from(ZZ), RR.coerce_map_from(QQ)
1084
sage: cm.verify_coercion_maps(ZZ, QQ, homs) == homs
1085
Traceback (most recent call last):
1086
...
1087
RuntimeError: ('BUG in coercion model, codomains must be identical', Natural morphism:
1088
From: Integer Ring
1089
To: Rational Field, Generic map:
1090
From: Rational Field
1091
To: Real Field with 53 bits of precision)
1092
"""
1093
if homs is None:
1094
return None
1095
cdef Map x_map, y_map
1096
R_map, S_map = homs
1097
if PY_TYPE_CHECK(R, type):
1098
R = Set_PythonType(R)
1099
elif PY_TYPE_CHECK(S, type):
1100
S = Set_PythonType(S)
1101
if R_map is None:
1102
R_map = IdentityMorphism(R)
1103
elif S_map is None:
1104
S_map = IdentityMorphism(S)
1105
# Make sure the domains are correct
1106
if R_map.domain() is not R:
1107
if fix:
1108
connecting = R_map.domain().coerce_map_from(R)
1109
if connecting is not None:
1110
R_map = R_map * connecting
1111
if R_map.domain() is not R:
1112
raise RuntimeError, ("BUG in coercion model, left domain must be original parent", R, R_map)
1113
if S_map is not None and S_map.domain() is not S:
1114
if fix:
1115
connecting = S_map.domain().coerce_map_from(S)
1116
if connecting is not None:
1117
S_map = S_map * connecting
1118
if S_map.domain() is not S:
1119
raise RuntimeError, ("BUG in coercion model, right domain must be original parent", S, S_map)
1120
# Make sure the codomains are correct
1121
if R_map.codomain() is not S_map.codomain():
1122
if fix:
1123
connecting = R_map.codomain().coerce_map_from(S_map.codomain())
1124
if connecting is not None:
1125
S_map = connecting * S_map
1126
else:
1127
connecting = S_map.codomain().coerce_map_from(R_map.codomain())
1128
if connecting is not None:
1129
R_map = connecting * R_map
1130
if R_map.codomain() is not S_map.codomain():
1131
raise RuntimeError, ("BUG in coercion model, codomains must be identical", R_map, S_map)
1132
if PY_TYPE_CHECK(R_map, IdentityMorphism):
1133
R_map = None
1134
elif PY_TYPE_CHECK(S_map, IdentityMorphism):
1135
S_map = None
1136
return R_map, S_map
1137
1138
1139
cpdef discover_coercion(self, R, S):
1140
"""
1141
This actually implements the finding of coercion maps as described in
1142
the ``coercion_maps`` method.
1143
1144
EXAMPLES::
1145
1146
sage: cm = sage.structure.element.get_coercion_model()
1147
1148
If R is S, then two identity morphisms suffice::
1149
1150
sage: cm.discover_coercion(SR, SR)
1151
(None, None)
1152
1153
If there is a coercion map either direction, use that::
1154
1155
sage: cm.discover_coercion(ZZ, QQ)
1156
(Natural morphism:
1157
From: Integer Ring
1158
To: Rational Field, None)
1159
sage: cm.discover_coercion(RR, QQ)
1160
(None,
1161
Generic map:
1162
From: Rational Field
1163
To: Real Field with 53 bits of precision)
1164
1165
Otherwise, try and compute an appropriate cover::
1166
1167
sage: cm.discover_coercion(ZZ['x,y'], RDF)
1168
(Call morphism:
1169
From: Multivariate Polynomial Ring in x, y over Integer Ring
1170
To: Multivariate Polynomial Ring in x, y over Real Double Field,
1171
Polynomial base injection morphism:
1172
From: Real Double Field
1173
To: Multivariate Polynomial Ring in x, y over Real Double Field)
1174
1175
Sometimes there is a reasonable "cover," but no canonical coercion::
1176
1177
sage: sage.categories.pushout.pushout(QQ, QQ^3)
1178
Vector space of dimension 3 over Rational Field
1179
sage: print cm.discover_coercion(QQ, QQ^3)
1180
None
1181
"""
1182
from sage.categories.homset import Hom
1183
if R is S:
1184
return None, None
1185
1186
# See if there is a natural coercion from R to S
1187
if PY_TYPE_CHECK(R, Parent):
1188
mor = (<Parent>R).coerce_map_from(S)
1189
if mor is not None:
1190
return None, mor
1191
1192
# See if there is a natural coercion from S to R
1193
if PY_TYPE_CHECK(S, Parent):
1194
mor = (<Parent>S).coerce_map_from(R)
1195
if mor is not None:
1196
return mor, None
1197
1198
# Try base extending
1199
if PY_TYPE_CHECK(R, Parent) and PY_TYPE_CHECK(S, Parent):
1200
from sage.categories.pushout import pushout
1201
try:
1202
Z = pushout(R, S)
1203
coerce_R = Z.coerce_map_from(R)
1204
coerce_S = Z.coerce_map_from(S)
1205
if coerce_R is None:
1206
raise TypeError, "No coercion from %s to pushout %s" % (R, Z)
1207
if coerce_S is None:
1208
raise TypeError, "No coercion from %s to pushout %s" % (S, Z)
1209
return coerce_R, coerce_S
1210
except Exception:
1211
self._record_exception()
1212
1213
return None
1214
1215
1216
cpdef get_action(self, R, S, op, r=None, s=None):
1217
"""
1218
Get the action of R on S or S on R associated to the operation op.
1219
1220
1221
1222
EXAMPLES::
1223
1224
sage: cm = sage.structure.element.get_coercion_model()
1225
sage: cm.get_action(ZZ['x'], ZZ, operator.mul)
1226
Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring
1227
sage: cm.get_action(ZZ['x'], ZZ, operator.imul)
1228
Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring
1229
sage: cm.get_action(ZZ['x'], QQ, operator.mul)
1230
Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring
1231
sage: cm.get_action(QQ['x'], int, operator.mul)
1232
Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Rational Field
1233
with precomposition on right by Native morphism:
1234
From: Set of Python objects of type 'int'
1235
To: Integer Ring
1236
1237
sage: R.<x> = QQ['x']
1238
sage: A = cm.get_action(R, ZZ, operator.div); A
1239
Right inverse action by Rational Field on Univariate Polynomial Ring in x over Rational Field
1240
with precomposition on right by Natural morphism:
1241
From: Integer Ring
1242
To: Rational Field
1243
sage: A(x+10, 5)
1244
1/5*x + 2
1245
1246
"""
1247
try:
1248
return self._action_maps.get(R, S, op)
1249
except KeyError:
1250
pass
1251
action = self.discover_action(R, S, op, r, s)
1252
action = self.verify_action(action, R, S, op)
1253
self._action_maps.set(R, S, op, action)
1254
return action
1255
1256
cpdef verify_action(self, action, R, S, op, bint fix=True):
1257
r"""
1258
Verify that ``action`` takes an element of R on the left and S
1259
on the right, raising an error if not.
1260
1261
This is used for consistency checking in the coercion model.
1262
1263
EXAMPLES::
1264
1265
sage: R.<x> = ZZ['x']
1266
sage: cm = sage.structure.element.get_coercion_model()
1267
sage: cm.verify_action(R.get_action(QQ), R, QQ, operator.mul)
1268
Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring
1269
sage: cm.verify_action(R.get_action(QQ), RDF, R, operator.mul)
1270
Traceback (most recent call last):
1271
...
1272
RuntimeError: There is a BUG in the coercion model:
1273
Action found for R <built-in function mul> S does not have the correct domains
1274
R = Real Double Field
1275
S = Univariate Polynomial Ring in x over Integer Ring
1276
(should be Univariate Polynomial Ring in x over Integer Ring, Rational Field)
1277
action = Right scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring (<type 'sage.structure.coerce_actions.RightModuleAction'>)
1278
"""
1279
if action is None:
1280
return action
1281
elif PY_TYPE_CHECK(action, IntegerMulAction):
1282
return action
1283
cdef bint ok = True
1284
try:
1285
if action.left_domain() is not R:
1286
ok &= PY_TYPE_CHECK(R, type) and action.left_domain()._type is R
1287
if action.right_domain() is not S:
1288
ok &= PY_TYPE_CHECK(S, type) and action.right_domain()._type is S
1289
except AttributeError:
1290
ok = False
1291
if not ok:
1292
if PY_TYPE_CHECK(R, type):
1293
R = Set_PythonType(R)
1294
if PY_TYPE_CHECK(S, type):
1295
S = Set_PythonType(S)
1296
1297
# Non-unique parents
1298
if fix and action.left_domain() is not R and action.left_domain() == R:
1299
action = PrecomposedAction(action, action.left_domain().coerce_map_from(R), None)
1300
if fix and action.right_domain() is not S and action.right_domain() == S:
1301
action = PrecomposedAction(action, None, action.right_domain().coerce_map_from(S))
1302
1303
if action.left_domain() is not R or action.right_domain() is not S:
1304
raise RuntimeError, """There is a BUG in the coercion model:
1305
Action found for R %s S does not have the correct domains
1306
R = %s
1307
S = %s
1308
(should be %s, %s)
1309
action = %s (%s)
1310
""" % (op, R, S, action.left_domain(), action.right_domain(), action, type(action))
1311
1312
return action
1313
1314
cpdef discover_action(self, R, S, op, r=None, s=None):
1315
"""
1316
INPUT
1317
1318
- ``R`` - the left Parent (or type)
1319
- ``S`` - the right Parent (or type)
1320
- ``op`` - the operand, typically an element of the operator module
1321
- ``r`` - (optional) element of R
1322
- ``s`` - (optional) element of S.
1323
1324
OUTPUT:
1325
1326
- An action A such that s op r is given by A(s,r).
1327
1328
The steps taken are illustrated below.
1329
1330
EXAMPLES::
1331
1332
sage: P.<x> = ZZ['x']
1333
sage: P.get_action(ZZ)
1334
Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring
1335
sage: ZZ.get_action(P) is None
1336
True
1337
sage: cm = sage.structure.element.get_coercion_model()
1338
1339
If R or S is a Parent, ask it for an action by/on R::
1340
1341
sage: cm.discover_action(ZZ, P, operator.mul)
1342
Left scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring
1343
1344
If R or S a type, recursively call get_action with the Sage versions of R and/or S::
1345
1346
sage: cm.discover_action(P, int, operator.mul)
1347
Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring
1348
with precomposition on right by Native morphism:
1349
From: Set of Python objects of type 'int'
1350
To: Integer Ring
1351
1352
If op in an inplace operation, look for the non-inplace action::
1353
1354
sage: cm.discover_action(P, ZZ, operator.imul)
1355
Right scalar multiplication by Integer Ring on Univariate Polynomial Ring in x over Integer Ring
1356
1357
If op is division, look for action on right by inverse::
1358
1359
sage: cm.discover_action(P, ZZ, operator.div)
1360
Right inverse action by Rational Field on Univariate Polynomial Ring in x over Integer Ring
1361
with precomposition on right by Natural morphism:
1362
From: Integer Ring
1363
To: Rational Field
1364
"""
1365
#print "looking", R, <int><void *>R, op, S, <int><void *>S
1366
1367
if PY_TYPE_CHECK(R, Parent):
1368
action = (<Parent>R).get_action(S, op, True, r, s)
1369
if action is not None:
1370
#print "found2", action
1371
return action
1372
1373
if PY_TYPE_CHECK(S, Parent):
1374
action = (<Parent>S).get_action(R, op, False, s, r)
1375
if action is not None:
1376
#print "found1", action
1377
return action
1378
1379
if PY_TYPE(R) == <void *>type:
1380
sageR = py_scalar_parent(R)
1381
if sageR is not None:
1382
action = self.discover_action(sageR, S, op, s=s)
1383
if action is not None:
1384
if not PY_TYPE_CHECK(action, IntegerMulAction):
1385
action = PrecomposedAction(action, sageR.coerce_map_from(R), None)
1386
return action
1387
1388
if PY_TYPE(S) == <void *>type:
1389
sageS = py_scalar_parent(S)
1390
if sageS is not None:
1391
action = self.discover_action(R, sageS, op, r=r)
1392
if action is not None:
1393
if not PY_TYPE_CHECK(action, IntegerMulAction):
1394
action = PrecomposedAction(action, None, sageS.coerce_map_from(S))
1395
return action
1396
1397
if op.__name__[0] == 'i':
1398
try:
1399
a = self.discover_action(R, S, no_inplace_op(op), r, s)
1400
if a is not None:
1401
is_inverse = isinstance(a, InverseAction)
1402
if is_inverse: a = ~a
1403
if a is not None and PY_TYPE_CHECK(a, RightModuleAction):
1404
# We want a new instance so that we don't alter the (potentially cached) original
1405
a = RightModuleAction(S, R, s, r)
1406
a.is_inplace = 1
1407
if is_inverse: a = ~a
1408
return a
1409
except KeyError:
1410
self._record_exception()
1411
1412
if op is div:
1413
# Division on right is the same acting on right by inverse, if it is so defined.
1414
# To return such an action, we need to verify that it would be an action for the mul
1415
# operator, but the action must be over a parent containing inverse elements.
1416
from sage.rings.ring import is_Ring
1417
if is_Ring(S):
1418
try:
1419
K = S._pseudo_fraction_field()
1420
except (TypeError, AttributeError, NotImplementedError):
1421
K = None
1422
elif PY_TYPE_CHECK(S, Parent):
1423
K = S
1424
else:
1425
# python scalar case handled recursively above
1426
K = None
1427
1428
if K is not None:
1429
action = self.get_action(R, K, mul)
1430
if action is not None and action.actor() is K:
1431
try:
1432
action = ~action
1433
if K is not S:
1434
action = PrecomposedAction(action, None, K.coerce_map_from(S))
1435
return action
1436
except TypeError: # action may not be invertible
1437
self._record_exception()
1438
1439
return None
1440
1441
def _coercion_error(self, x, x_map, x_elt, y, y_map, y_elt):
1442
"""
1443
This function is only called when someone has incorrectly implemented
1444
a user-defined part of the coercion system (usually, a morphism).
1445
1446
EXAMPLE::
1447
1448
sage: cm = sage.structure.element.get_coercion_model()
1449
sage: cm._coercion_error('a', 'f', 'f(a)', 'b', 'g', 'g(b)')
1450
Traceback (most recent call last):
1451
...
1452
RuntimeError: There is a bug in the coercion code in Sage.
1453
Both x (='f(a)') and y (='g(b)') are supposed to have identical parents but they don't.
1454
In fact, x has parent '<type 'str'>'
1455
whereas y has parent '<type 'str'>'
1456
Original elements 'a' (parent <type 'str'>) and 'b' (parent <type 'str'>) and maps
1457
<type 'str'> 'f'
1458
<type 'str'> 'g'
1459
"""
1460
raise RuntimeError, """There is a bug in the coercion code in Sage.
1461
Both x (=%r) and y (=%r) are supposed to have identical parents but they don't.
1462
In fact, x has parent '%s'
1463
whereas y has parent '%s'
1464
Original elements %r (parent %s) and %r (parent %s) and maps
1465
%s %r
1466
%s %r"""%( x_elt, y_elt, parent_c(x_elt), parent_c(y_elt),
1467
x, parent_c(x), y, parent_c(y),
1468
type(x_map), x_map, type(y_map), y_map)
1469
1470
1471
1472