passagemath-objects 10.6.46__cp314-cp314t-macosx_13_0_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-objects might be problematic. Click here for more details.
- passagemath_objects/.dylibs/libgmp.10.dylib +0 -0
- passagemath_objects/__init__.py +3 -0
- passagemath_objects-10.6.46.dist-info/METADATA +115 -0
- passagemath_objects-10.6.46.dist-info/RECORD +280 -0
- passagemath_objects-10.6.46.dist-info/WHEEL +6 -0
- passagemath_objects-10.6.46.dist-info/top_level.txt +3 -0
- sage/all__sagemath_objects.py +37 -0
- sage/arith/all__sagemath_objects.py +5 -0
- sage/arith/long.pxd +411 -0
- sage/arith/numerical_approx.cpython-314t-darwin.so +0 -0
- sage/arith/numerical_approx.pxd +35 -0
- sage/arith/numerical_approx.pyx +75 -0
- sage/arith/power.cpython-314t-darwin.so +0 -0
- sage/arith/power.pxd +31 -0
- sage/arith/power.pyx +127 -0
- sage/categories/action.cpython-314t-darwin.so +0 -0
- sage/categories/action.pxd +29 -0
- sage/categories/action.pyx +641 -0
- sage/categories/algebra_functor.py +745 -0
- sage/categories/all__sagemath_objects.py +33 -0
- sage/categories/basic.py +62 -0
- sage/categories/cartesian_product.py +295 -0
- sage/categories/category.py +3401 -0
- sage/categories/category_cy_helper.cpython-314t-darwin.so +0 -0
- sage/categories/category_cy_helper.pxd +8 -0
- sage/categories/category_cy_helper.pyx +322 -0
- sage/categories/category_singleton.cpython-314t-darwin.so +0 -0
- sage/categories/category_singleton.pxd +3 -0
- sage/categories/category_singleton.pyx +342 -0
- sage/categories/category_types.py +637 -0
- sage/categories/category_with_axiom.py +2876 -0
- sage/categories/covariant_functorial_construction.py +703 -0
- sage/categories/facade_sets.py +228 -0
- sage/categories/functor.cpython-314t-darwin.so +0 -0
- sage/categories/functor.pxd +7 -0
- sage/categories/functor.pyx +691 -0
- sage/categories/homset.py +1338 -0
- sage/categories/homsets.py +364 -0
- sage/categories/isomorphic_objects.py +73 -0
- sage/categories/map.cpython-314t-darwin.so +0 -0
- sage/categories/map.pxd +34 -0
- sage/categories/map.pyx +2106 -0
- sage/categories/morphism.cpython-314t-darwin.so +0 -0
- sage/categories/morphism.pxd +14 -0
- sage/categories/morphism.pyx +895 -0
- sage/categories/objects.py +167 -0
- sage/categories/primer.py +1696 -0
- sage/categories/pushout.py +4834 -0
- sage/categories/quotients.py +64 -0
- sage/categories/realizations.py +200 -0
- sage/categories/sets_cat.py +3290 -0
- sage/categories/sets_with_partial_maps.py +52 -0
- sage/categories/subobjects.py +64 -0
- sage/categories/subquotients.py +21 -0
- sage/categories/with_realizations.py +311 -0
- sage/cpython/__init__.py +19 -0
- sage/cpython/_py2_random.py +619 -0
- sage/cpython/all.py +3 -0
- sage/cpython/atexit.cpython-314t-darwin.so +0 -0
- sage/cpython/atexit.pyx +269 -0
- sage/cpython/builtin_types.cpython-314t-darwin.so +0 -0
- sage/cpython/builtin_types.pyx +7 -0
- sage/cpython/cython_metaclass.cpython-314t-darwin.so +0 -0
- sage/cpython/cython_metaclass.h +117 -0
- sage/cpython/cython_metaclass.pxd +3 -0
- sage/cpython/cython_metaclass.pyx +130 -0
- sage/cpython/debug.cpython-314t-darwin.so +0 -0
- sage/cpython/debug.pyx +302 -0
- sage/cpython/dict_del_by_value.cpython-314t-darwin.so +0 -0
- sage/cpython/dict_del_by_value.pxd +9 -0
- sage/cpython/dict_del_by_value.pyx +191 -0
- sage/cpython/dict_internal.h +245 -0
- sage/cpython/getattr.cpython-314t-darwin.so +0 -0
- sage/cpython/getattr.pxd +9 -0
- sage/cpython/getattr.pyx +439 -0
- sage/cpython/pycore_long.h +97 -0
- sage/cpython/pycore_long.pxd +10 -0
- sage/cpython/python_debug.h +44 -0
- sage/cpython/python_debug.pxd +47 -0
- sage/cpython/pyx_visit.h +13 -0
- sage/cpython/string.cpython-314t-darwin.so +0 -0
- sage/cpython/string.pxd +76 -0
- sage/cpython/string.pyx +34 -0
- sage/cpython/string_impl.h +60 -0
- sage/cpython/type.cpython-314t-darwin.so +0 -0
- sage/cpython/type.pxd +2 -0
- sage/cpython/type.pyx +40 -0
- sage/cpython/wrapperdescr.pxd +67 -0
- sage/ext/all__sagemath_objects.py +3 -0
- sage/ext/ccobject.h +64 -0
- sage/ext/cplusplus.pxd +17 -0
- sage/ext/mod_int.h +30 -0
- sage/ext/mod_int.pxd +24 -0
- sage/ext/stdsage.pxd +39 -0
- sage/groups/all__sagemath_objects.py +1 -0
- sage/groups/group.cpython-314t-darwin.so +0 -0
- sage/groups/group.pxd +14 -0
- sage/groups/group.pyx +322 -0
- sage/groups/old.cpython-314t-darwin.so +0 -0
- sage/groups/old.pxd +14 -0
- sage/groups/old.pyx +219 -0
- sage/libs/all__sagemath_objects.py +3 -0
- sage/libs/gmp/__init__.py +1 -0
- sage/libs/gmp/all.pxd +6 -0
- sage/libs/gmp/binop.pxd +23 -0
- sage/libs/gmp/misc.pxd +8 -0
- sage/libs/gmp/mpf.pxd +88 -0
- sage/libs/gmp/mpn.pxd +57 -0
- sage/libs/gmp/mpq.pxd +57 -0
- sage/libs/gmp/mpz.pxd +202 -0
- sage/libs/gmp/pylong.cpython-314t-darwin.so +0 -0
- sage/libs/gmp/pylong.pxd +12 -0
- sage/libs/gmp/pylong.pyx +150 -0
- sage/libs/gmp/random.pxd +25 -0
- sage/libs/gmp/randomize.pxd +59 -0
- sage/libs/gmp/types.pxd +53 -0
- sage/libs/gmpxx.pxd +19 -0
- sage/misc/abstract_method.py +276 -0
- sage/misc/all__sagemath_objects.py +43 -0
- sage/misc/bindable_class.py +253 -0
- sage/misc/c3_controlled.cpython-314t-darwin.so +0 -0
- sage/misc/c3_controlled.pxd +2 -0
- sage/misc/c3_controlled.pyx +1402 -0
- sage/misc/cachefunc.cpython-314t-darwin.so +0 -0
- sage/misc/cachefunc.pxd +43 -0
- sage/misc/cachefunc.pyx +3781 -0
- sage/misc/call.py +188 -0
- sage/misc/classcall_metaclass.cpython-314t-darwin.so +0 -0
- sage/misc/classcall_metaclass.pxd +14 -0
- sage/misc/classcall_metaclass.pyx +599 -0
- sage/misc/constant_function.cpython-314t-darwin.so +0 -0
- sage/misc/constant_function.pyx +130 -0
- sage/misc/decorators.py +747 -0
- sage/misc/fast_methods.cpython-314t-darwin.so +0 -0
- sage/misc/fast_methods.pxd +20 -0
- sage/misc/fast_methods.pyx +351 -0
- sage/misc/flatten.py +90 -0
- sage/misc/fpickle.cpython-314t-darwin.so +0 -0
- sage/misc/fpickle.pyx +177 -0
- sage/misc/function_mangling.cpython-314t-darwin.so +0 -0
- sage/misc/function_mangling.pxd +11 -0
- sage/misc/function_mangling.pyx +308 -0
- sage/misc/inherit_comparison.cpython-314t-darwin.so +0 -0
- sage/misc/inherit_comparison.pxd +5 -0
- sage/misc/inherit_comparison.pyx +105 -0
- sage/misc/instancedoc.cpython-314t-darwin.so +0 -0
- sage/misc/instancedoc.pyx +331 -0
- sage/misc/lazy_attribute.cpython-314t-darwin.so +0 -0
- sage/misc/lazy_attribute.pyx +607 -0
- sage/misc/lazy_format.py +135 -0
- sage/misc/lazy_import.cpython-314t-darwin.so +0 -0
- sage/misc/lazy_import.pyx +1299 -0
- sage/misc/lazy_import_cache.py +36 -0
- sage/misc/lazy_list.cpython-314t-darwin.so +0 -0
- sage/misc/lazy_list.pxd +19 -0
- sage/misc/lazy_list.pyx +1187 -0
- sage/misc/lazy_string.cpython-314t-darwin.so +0 -0
- sage/misc/lazy_string.pxd +7 -0
- sage/misc/lazy_string.pyx +546 -0
- sage/misc/misc.py +1066 -0
- sage/misc/misc_c.cpython-314t-darwin.so +0 -0
- sage/misc/misc_c.pxd +3 -0
- sage/misc/misc_c.pyx +766 -0
- sage/misc/namespace_package.py +37 -0
- sage/misc/nested_class.cpython-314t-darwin.so +0 -0
- sage/misc/nested_class.pxd +3 -0
- sage/misc/nested_class.pyx +394 -0
- sage/misc/persist.cpython-314t-darwin.so +0 -0
- sage/misc/persist.pyx +1251 -0
- sage/misc/prandom.py +418 -0
- sage/misc/randstate.cpython-314t-darwin.so +0 -0
- sage/misc/randstate.pxd +30 -0
- sage/misc/randstate.pyx +1059 -0
- sage/misc/repr.py +203 -0
- sage/misc/reset.cpython-314t-darwin.so +0 -0
- sage/misc/reset.pyx +196 -0
- sage/misc/sage_ostools.cpython-314t-darwin.so +0 -0
- sage/misc/sage_ostools.pyx +323 -0
- sage/misc/sage_timeit.py +275 -0
- sage/misc/sage_timeit_class.cpython-314t-darwin.so +0 -0
- sage/misc/sage_timeit_class.pyx +120 -0
- sage/misc/sage_unittest.py +637 -0
- sage/misc/sageinspect.py +2768 -0
- sage/misc/session.cpython-314t-darwin.so +0 -0
- sage/misc/session.pyx +392 -0
- sage/misc/superseded.py +557 -0
- sage/misc/test_nested_class.py +228 -0
- sage/misc/timing.py +264 -0
- sage/misc/unknown.py +222 -0
- sage/misc/verbose.py +253 -0
- sage/misc/weak_dict.cpython-314t-darwin.so +0 -0
- sage/misc/weak_dict.pxd +15 -0
- sage/misc/weak_dict.pyx +1231 -0
- sage/modules/all__sagemath_objects.py +1 -0
- sage/modules/module.cpython-314t-darwin.so +0 -0
- sage/modules/module.pxd +5 -0
- sage/modules/module.pyx +329 -0
- sage/rings/all__sagemath_objects.py +3 -0
- sage/rings/integer_fake.h +22 -0
- sage/rings/integer_fake.pxd +55 -0
- sage/sets/all__sagemath_objects.py +3 -0
- sage/sets/pythonclass.cpython-314t-darwin.so +0 -0
- sage/sets/pythonclass.pxd +9 -0
- sage/sets/pythonclass.pyx +247 -0
- sage/structure/__init__.py +4 -0
- sage/structure/all.py +30 -0
- sage/structure/category_object.cpython-314t-darwin.so +0 -0
- sage/structure/category_object.pxd +28 -0
- sage/structure/category_object.pyx +1087 -0
- sage/structure/coerce.cpython-314t-darwin.so +0 -0
- sage/structure/coerce.pxd +44 -0
- sage/structure/coerce.pyx +2107 -0
- sage/structure/coerce_actions.cpython-314t-darwin.so +0 -0
- sage/structure/coerce_actions.pxd +27 -0
- sage/structure/coerce_actions.pyx +988 -0
- sage/structure/coerce_dict.cpython-314t-darwin.so +0 -0
- sage/structure/coerce_dict.pxd +51 -0
- sage/structure/coerce_dict.pyx +1557 -0
- sage/structure/coerce_exceptions.py +23 -0
- sage/structure/coerce_maps.cpython-314t-darwin.so +0 -0
- sage/structure/coerce_maps.pxd +28 -0
- sage/structure/coerce_maps.pyx +718 -0
- sage/structure/debug_options.cpython-314t-darwin.so +0 -0
- sage/structure/debug_options.pxd +6 -0
- sage/structure/debug_options.pyx +54 -0
- sage/structure/dynamic_class.py +541 -0
- sage/structure/element.cpython-314t-darwin.so +0 -0
- sage/structure/element.pxd +272 -0
- sage/structure/element.pyx +4772 -0
- sage/structure/element_wrapper.cpython-314t-darwin.so +0 -0
- sage/structure/element_wrapper.pxd +12 -0
- sage/structure/element_wrapper.pyx +582 -0
- sage/structure/factorization.py +1422 -0
- sage/structure/factorization_integer.py +105 -0
- sage/structure/factory.cpython-314t-darwin.so +0 -0
- sage/structure/factory.pyx +786 -0
- sage/structure/formal_sum.py +489 -0
- sage/structure/gens_py.py +73 -0
- sage/structure/global_options.py +1743 -0
- sage/structure/indexed_generators.py +863 -0
- sage/structure/list_clone.cpython-314t-darwin.so +0 -0
- sage/structure/list_clone.pxd +65 -0
- sage/structure/list_clone.pyx +1867 -0
- sage/structure/list_clone_demo.cpython-314t-darwin.so +0 -0
- sage/structure/list_clone_demo.pyx +248 -0
- sage/structure/list_clone_timings.py +179 -0
- sage/structure/list_clone_timings_cy.cpython-314t-darwin.so +0 -0
- sage/structure/list_clone_timings_cy.pyx +86 -0
- sage/structure/mutability.cpython-314t-darwin.so +0 -0
- sage/structure/mutability.pxd +21 -0
- sage/structure/mutability.pyx +348 -0
- sage/structure/nonexact.py +69 -0
- sage/structure/parent.cpython-314t-darwin.so +0 -0
- sage/structure/parent.pxd +112 -0
- sage/structure/parent.pyx +3093 -0
- sage/structure/parent_base.cpython-314t-darwin.so +0 -0
- sage/structure/parent_base.pxd +13 -0
- sage/structure/parent_base.pyx +44 -0
- sage/structure/parent_gens.cpython-314t-darwin.so +0 -0
- sage/structure/parent_gens.pxd +22 -0
- sage/structure/parent_gens.pyx +377 -0
- sage/structure/parent_old.cpython-314t-darwin.so +0 -0
- sage/structure/parent_old.pxd +25 -0
- sage/structure/parent_old.pyx +294 -0
- sage/structure/proof/__init__.py +1 -0
- sage/structure/proof/all.py +243 -0
- sage/structure/proof/proof.py +300 -0
- sage/structure/richcmp.cpython-314t-darwin.so +0 -0
- sage/structure/richcmp.pxd +213 -0
- sage/structure/richcmp.pyx +495 -0
- sage/structure/sage_object.cpython-314t-darwin.so +0 -0
- sage/structure/sage_object.pxd +3 -0
- sage/structure/sage_object.pyx +988 -0
- sage/structure/sage_object_test.py +19 -0
- sage/structure/sequence.py +937 -0
- sage/structure/set_factories.py +1178 -0
- sage/structure/set_factories_example.py +527 -0
- sage/structure/support_view.py +179 -0
- sage/structure/test_factory.py +56 -0
- sage/structure/unique_representation.py +1359 -0
|
@@ -0,0 +1,3093 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-objects
|
|
2
|
+
r"""
|
|
3
|
+
Base class for parent objects
|
|
4
|
+
|
|
5
|
+
CLASS HIERARCHY::
|
|
6
|
+
|
|
7
|
+
SageObject
|
|
8
|
+
CategoryObject
|
|
9
|
+
Parent
|
|
10
|
+
|
|
11
|
+
A simple example of registering coercions::
|
|
12
|
+
|
|
13
|
+
sage: class A_class(Parent):
|
|
14
|
+
....: def __init__(self, name):
|
|
15
|
+
....: Parent.__init__(self)
|
|
16
|
+
....: self._populate_coercion_lists_()
|
|
17
|
+
....: self.rename(name)
|
|
18
|
+
....:
|
|
19
|
+
....: def category(self):
|
|
20
|
+
....: return Sets()
|
|
21
|
+
....:
|
|
22
|
+
....: def _element_constructor_(self, i):
|
|
23
|
+
....: assert(isinstance(i, (int, Integer)))
|
|
24
|
+
....: return ElementWrapper(self, i)
|
|
25
|
+
sage: A = A_class("A")
|
|
26
|
+
sage: B = A_class("B")
|
|
27
|
+
sage: C = A_class("C")
|
|
28
|
+
|
|
29
|
+
sage: def f(a):
|
|
30
|
+
....: return B(a.value+1)
|
|
31
|
+
sage: class MyMorphism(Morphism):
|
|
32
|
+
....: def __init__(self, domain, codomain):
|
|
33
|
+
....: Morphism.__init__(self, Hom(domain, codomain))
|
|
34
|
+
....:
|
|
35
|
+
....: def _call_(self, x):
|
|
36
|
+
....: return self.codomain()(x.value)
|
|
37
|
+
sage: f = MyMorphism(A,B)
|
|
38
|
+
sage: f
|
|
39
|
+
Generic morphism:
|
|
40
|
+
From: A
|
|
41
|
+
To: B
|
|
42
|
+
sage: B.register_coercion(f)
|
|
43
|
+
sage: C.register_coercion(MyMorphism(B,C))
|
|
44
|
+
sage: A(A(1)) == A(1)
|
|
45
|
+
True
|
|
46
|
+
sage: B(A(1)) == B(1)
|
|
47
|
+
True
|
|
48
|
+
sage: C(A(1)) == C(1)
|
|
49
|
+
True
|
|
50
|
+
|
|
51
|
+
sage: A(B(1))
|
|
52
|
+
Traceback (most recent call last):
|
|
53
|
+
...
|
|
54
|
+
AssertionError
|
|
55
|
+
|
|
56
|
+
When implementing an element of a ring, one would typically provide the
|
|
57
|
+
element class with ``_rmul_`` and/or ``_lmul_`` methods for the action of a
|
|
58
|
+
base ring, and with ``_mul_`` for the ring multiplication. However, prior to
|
|
59
|
+
:issue:`14249`, it would have been necessary to additionally define a method
|
|
60
|
+
``_an_element_()`` for the parent. But now, the following example works::
|
|
61
|
+
|
|
62
|
+
sage: from sage.structure.element import RingElement
|
|
63
|
+
sage: class MyElement(RingElement):
|
|
64
|
+
....: def __init__(self, parent, x, y):
|
|
65
|
+
....: RingElement.__init__(self, parent)
|
|
66
|
+
....: def _mul_(self, other):
|
|
67
|
+
....: return self
|
|
68
|
+
....: def _rmul_(self, other):
|
|
69
|
+
....: return self
|
|
70
|
+
....: def _lmul_(self, other):
|
|
71
|
+
....: return self
|
|
72
|
+
sage: class MyParent(Parent):
|
|
73
|
+
....: Element = MyElement
|
|
74
|
+
|
|
75
|
+
Now, we define ::
|
|
76
|
+
|
|
77
|
+
sage: P = MyParent(base=ZZ, category=Rings())
|
|
78
|
+
sage: a = P(1,2)
|
|
79
|
+
sage: a*a is a
|
|
80
|
+
True
|
|
81
|
+
sage: a*2 is a
|
|
82
|
+
True
|
|
83
|
+
sage: 2*a is a
|
|
84
|
+
True
|
|
85
|
+
|
|
86
|
+
TESTS:
|
|
87
|
+
|
|
88
|
+
This came up in some subtle bug once::
|
|
89
|
+
|
|
90
|
+
sage: gp(2) + gap(3) # needs sage.libs.gap sage.libs.pari
|
|
91
|
+
5
|
|
92
|
+
"""
|
|
93
|
+
# ****************************************************************************
|
|
94
|
+
# Copyright (C) 2009 Robert Bradshaw <robertwb@math.washington.edu>
|
|
95
|
+
# Copyright (C) 2008 Burcin Erocal <burcin@erocal.org>
|
|
96
|
+
# Copyright (C) 2008 Mike Hansen <mhansen@gmail.com>
|
|
97
|
+
# Copyright (C) 2008 David Roe <roed@math.harvard.edu>
|
|
98
|
+
# Copyright (C) 2007 William Stein <wstein@gmail.com>
|
|
99
|
+
#
|
|
100
|
+
# This program is free software: you can redistribute it and/or modify
|
|
101
|
+
# it under the terms of the GNU General Public License as published by
|
|
102
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
103
|
+
# (at your option) any later version.
|
|
104
|
+
# https://www.gnu.org/licenses/
|
|
105
|
+
# ****************************************************************************
|
|
106
|
+
|
|
107
|
+
from cpython.object cimport Py_EQ, Py_LE, Py_GE
|
|
108
|
+
from cpython.bool cimport *
|
|
109
|
+
|
|
110
|
+
from types import MethodType, BuiltinMethodType
|
|
111
|
+
import operator
|
|
112
|
+
from copy import copy
|
|
113
|
+
|
|
114
|
+
from sage.cpython.type cimport can_assign_class
|
|
115
|
+
cimport sage.categories.map as map
|
|
116
|
+
from sage.structure.debug_options cimport debug
|
|
117
|
+
from sage.structure.sage_object cimport SageObject
|
|
118
|
+
from sage.misc.cachefunc import cached_method
|
|
119
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
|
120
|
+
from sage.categories.sets_cat import Sets, EmptySetError
|
|
121
|
+
from sage.misc.lazy_string cimport _LazyString
|
|
122
|
+
from sage.sets.pythonclass cimport Set_PythonType_class
|
|
123
|
+
from sage.structure.category_object import CategoryObject
|
|
124
|
+
from sage.structure.coerce cimport coercion_model
|
|
125
|
+
from sage.structure.coerce cimport parent_is_integers
|
|
126
|
+
from sage.structure.coerce_exceptions import CoercionException
|
|
127
|
+
from sage.structure.coerce_maps cimport (NamedConvertMap, DefaultConvertMap,
|
|
128
|
+
DefaultConvertMap_unique, CallableConvertMap)
|
|
129
|
+
from sage.structure.element cimport parent
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
cdef _record_exception():
|
|
133
|
+
coercion_model._record_exception()
|
|
134
|
+
|
|
135
|
+
cdef object _Integer
|
|
136
|
+
cdef bint is_Integer(x) noexcept:
|
|
137
|
+
global _Integer
|
|
138
|
+
if _Integer is None:
|
|
139
|
+
from sage.rings.integer import Integer as _Integer
|
|
140
|
+
return type(x) is _Integer or type(x) is int
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def is_Parent(x):
|
|
144
|
+
"""
|
|
145
|
+
Return ``True`` if x is a parent object, i.e., derives from
|
|
146
|
+
sage.structure.parent.Parent and ``False`` otherwise.
|
|
147
|
+
|
|
148
|
+
EXAMPLES::
|
|
149
|
+
|
|
150
|
+
sage: from sage.structure.parent import is_Parent
|
|
151
|
+
sage: is_Parent(2/3)
|
|
152
|
+
doctest:warning...
|
|
153
|
+
DeprecationWarning: the function is_Parent is deprecated;
|
|
154
|
+
use 'isinstance(..., Parent)' instead
|
|
155
|
+
See https://github.com/sagemath/sage/issues/37922 for details.
|
|
156
|
+
False
|
|
157
|
+
sage: is_Parent(ZZ)
|
|
158
|
+
True
|
|
159
|
+
sage: is_Parent(Primes())
|
|
160
|
+
True
|
|
161
|
+
"""
|
|
162
|
+
from sage.misc.superseded import deprecation_cython
|
|
163
|
+
deprecation_cython(37922, "the function is_Parent is deprecated; use 'isinstance(..., Parent)' instead")
|
|
164
|
+
return isinstance(x, Parent)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
cdef bint guess_pass_parent(parent, element_constructor) noexcept:
|
|
168
|
+
# Returning True here is deprecated, see #26879
|
|
169
|
+
if isinstance(element_constructor, MethodType):
|
|
170
|
+
return False
|
|
171
|
+
elif isinstance(element_constructor, BuiltinMethodType):
|
|
172
|
+
return element_constructor.__self__ is not parent
|
|
173
|
+
else:
|
|
174
|
+
return True
|
|
175
|
+
|
|
176
|
+
from sage.categories.category import Category
|
|
177
|
+
from sage.structure.dynamic_class import dynamic_class
|
|
178
|
+
Sets_parent_class = Sets().parent_class
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
cdef inline bint good_as_coerce_domain(S) noexcept:
|
|
182
|
+
"""
|
|
183
|
+
Determine whether the input can be the domain of a map.
|
|
184
|
+
|
|
185
|
+
.. NOTE::
|
|
186
|
+
|
|
187
|
+
This is the same as being an object in a category, or
|
|
188
|
+
being a type. Namely, in Sage, we do consider coercion maps
|
|
189
|
+
from the type ``<int>`` to, say, `ZZ`.
|
|
190
|
+
|
|
191
|
+
TESTS:
|
|
192
|
+
|
|
193
|
+
If an instance `S` is not suitable as domain of a map, then
|
|
194
|
+
the non-existence of a coercion or conversion map from `S`
|
|
195
|
+
to some other parent is not cached, by :issue:`13378`::
|
|
196
|
+
|
|
197
|
+
sage: P.<x,y> = QQ[]
|
|
198
|
+
sage: P._is_coercion_cached(x)
|
|
199
|
+
False
|
|
200
|
+
sage: P.coerce_map_from(x)
|
|
201
|
+
sage: P._is_coercion_cached(x)
|
|
202
|
+
False
|
|
203
|
+
"""
|
|
204
|
+
return isinstance(S, (CategoryObject, type))
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
cdef inline bint good_as_convert_domain(S) noexcept:
|
|
208
|
+
return isinstance(S, (SageObject, type))
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
cdef class Parent(sage.structure.category_object.CategoryObject):
|
|
212
|
+
def __cinit__(self):
|
|
213
|
+
self._action_hash = TripleDict()
|
|
214
|
+
|
|
215
|
+
def __init__(self, base=None, *, category=None,
|
|
216
|
+
names=None, normalize=True, facade=None):
|
|
217
|
+
"""
|
|
218
|
+
Base class for all parents.
|
|
219
|
+
|
|
220
|
+
Parents are the Sage/mathematical analogues of container
|
|
221
|
+
objects in computer science.
|
|
222
|
+
|
|
223
|
+
INPUT:
|
|
224
|
+
|
|
225
|
+
- ``base`` -- an algebraic structure considered to be the "base" of
|
|
226
|
+
this parent (e.g. the base field for a vector space)
|
|
227
|
+
|
|
228
|
+
- ``category`` -- a category or list/tuple of categories. The category
|
|
229
|
+
in which this parent lies (or list or tuple thereof). Since
|
|
230
|
+
categories support more general super-categories, this should be the
|
|
231
|
+
most specific category possible. If category is a list or tuple, a
|
|
232
|
+
``JoinCategory`` is created out of them. If category is not
|
|
233
|
+
specified, the category will be guessed (see
|
|
234
|
+
:class:`~sage.structure.category_object.CategoryObject`), but will
|
|
235
|
+
not be used to inherit parent's or element's code from this category.
|
|
236
|
+
|
|
237
|
+
- ``names`` -- names of generators
|
|
238
|
+
|
|
239
|
+
- ``normalize`` -- whether to standardize the names (remove
|
|
240
|
+
punctuation, etc.)
|
|
241
|
+
|
|
242
|
+
- ``facade`` -- a parent, or tuple thereof, or ``True``
|
|
243
|
+
|
|
244
|
+
If ``facade`` is specified, then ``Sets().Facade()`` is added
|
|
245
|
+
to the categories of the parent. Furthermore, if ``facade`` is
|
|
246
|
+
not ``True``, the internal attribute ``_facade_for`` is set
|
|
247
|
+
accordingly for use by
|
|
248
|
+
:meth:`Sets.Facade.ParentMethods.facade_for`.
|
|
249
|
+
|
|
250
|
+
Internal invariants:
|
|
251
|
+
|
|
252
|
+
- ``self._element_init_pass_parent == guess_pass_parent(self,
|
|
253
|
+
self._element_constructor)`` Ensures that :meth:`__call__`
|
|
254
|
+
passes down the parent properly to
|
|
255
|
+
:meth:`_element_constructor`. See :issue:`5979`.
|
|
256
|
+
|
|
257
|
+
.. TODO::
|
|
258
|
+
|
|
259
|
+
Eventually, category should be
|
|
260
|
+
:class:`~sage.categories.sets_cat.Sets` by default.
|
|
261
|
+
|
|
262
|
+
TESTS:
|
|
263
|
+
|
|
264
|
+
We check that the facade option is compatible with specifying
|
|
265
|
+
categories as a tuple::
|
|
266
|
+
|
|
267
|
+
sage: class MyClass(Parent): pass
|
|
268
|
+
sage: P = MyClass(facade = ZZ, category = (Monoids(), CommutativeAdditiveMonoids()))
|
|
269
|
+
sage: P.category()
|
|
270
|
+
Join of Category of monoids and Category of commutative additive monoids and Category of facade sets
|
|
271
|
+
|
|
272
|
+
.. automethod:: __call__
|
|
273
|
+
.. automethod:: _populate_coercion_lists_
|
|
274
|
+
.. automethod:: __mul__
|
|
275
|
+
.. automethod:: __contains__
|
|
276
|
+
.. automethod:: _coerce_map_from_
|
|
277
|
+
.. automethod:: _convert_map_from_
|
|
278
|
+
.. automethod:: _get_action_
|
|
279
|
+
.. automethod:: _an_element_
|
|
280
|
+
.. automethod:: _repr_option
|
|
281
|
+
.. automethod:: _init_category_
|
|
282
|
+
.. automethod:: _is_coercion_cached
|
|
283
|
+
.. automethod:: _is_conversion_cached
|
|
284
|
+
"""
|
|
285
|
+
if isinstance(category, (tuple, list)):
|
|
286
|
+
category = Category.join(category)
|
|
287
|
+
if facade is not None and facade is not False:
|
|
288
|
+
if facade is not True:
|
|
289
|
+
if isinstance(facade, Parent):
|
|
290
|
+
self._facade_for = (facade,)
|
|
291
|
+
else:
|
|
292
|
+
self._facade_for = tuple(facade)
|
|
293
|
+
if category is None:
|
|
294
|
+
category = Sets().Facade()
|
|
295
|
+
else:
|
|
296
|
+
category = Category.join((category, Sets().Facade()))
|
|
297
|
+
|
|
298
|
+
CategoryObject.__init__(self, category, base)
|
|
299
|
+
|
|
300
|
+
if names is not None:
|
|
301
|
+
self._assign_names(names, normalize)
|
|
302
|
+
self._set_element_constructor()
|
|
303
|
+
self.init_coerce(False)
|
|
304
|
+
|
|
305
|
+
for cls in self.__class__.mro():
|
|
306
|
+
# this calls __init_extra__ if it is *defined* in cls (not in a super class)
|
|
307
|
+
if "__init_extra__" in cls.__dict__:
|
|
308
|
+
cls.__init_extra__(self)
|
|
309
|
+
|
|
310
|
+
def _init_category_(self, category):
|
|
311
|
+
"""
|
|
312
|
+
Initialize the category framework.
|
|
313
|
+
|
|
314
|
+
Most parents initialize their category upon construction, and
|
|
315
|
+
this is the recommended behavior. For example, this happens
|
|
316
|
+
when the constructor calls :meth:`Parent.__init__` directly or
|
|
317
|
+
indirectly. However, some parents defer this for performance
|
|
318
|
+
reasons. For example,
|
|
319
|
+
:mod:`sage.matrix.matrix_space.MatrixSpace` does not.
|
|
320
|
+
|
|
321
|
+
EXAMPLES::
|
|
322
|
+
|
|
323
|
+
sage: P = Parent()
|
|
324
|
+
sage: P.category()
|
|
325
|
+
Category of sets
|
|
326
|
+
sage: class MyParent(Parent):
|
|
327
|
+
....: def __init__(self):
|
|
328
|
+
....: self._init_category_(Groups())
|
|
329
|
+
sage: MyParent().category()
|
|
330
|
+
Category of groups
|
|
331
|
+
"""
|
|
332
|
+
CategoryObject._init_category_(self, category)
|
|
333
|
+
|
|
334
|
+
# This substitutes the class of this parent to a subclass
|
|
335
|
+
# which also subclasses the parent_class of the category.
|
|
336
|
+
|
|
337
|
+
# Some parent class may readily have their category classes attached
|
|
338
|
+
# TODO: assert that the category is consistent
|
|
339
|
+
if can_assign_class(self) and not isinstance(self, Sets_parent_class):
|
|
340
|
+
# Documentation transfer is handled by dynamic_class
|
|
341
|
+
self.__class__ = dynamic_class(
|
|
342
|
+
f"{type(self).__name__}_with_category",
|
|
343
|
+
(type(self), self._category.parent_class),
|
|
344
|
+
doccls=type(self))
|
|
345
|
+
|
|
346
|
+
def _refine_category_(self, category):
|
|
347
|
+
"""
|
|
348
|
+
Change the category of ``self`` into a subcategory.
|
|
349
|
+
|
|
350
|
+
INPUT:
|
|
351
|
+
|
|
352
|
+
- ``category`` -- a category or list or tuple thereof
|
|
353
|
+
|
|
354
|
+
The new category is obtained by adjoining ``category`` to the
|
|
355
|
+
current one.
|
|
356
|
+
|
|
357
|
+
.. NOTE::
|
|
358
|
+
|
|
359
|
+
The class of ``self`` might be replaced by a sub-class.
|
|
360
|
+
|
|
361
|
+
.. SEEALSO::
|
|
362
|
+
|
|
363
|
+
:meth:`CategoryObject._refine_category`
|
|
364
|
+
|
|
365
|
+
EXAMPLES::
|
|
366
|
+
|
|
367
|
+
sage: P.<x,y> = QQ[]
|
|
368
|
+
sage: Q = P.quotient(x^2 + 2)
|
|
369
|
+
sage: Q.category()
|
|
370
|
+
Join of
|
|
371
|
+
Category of commutative rings and
|
|
372
|
+
Category of subquotients of monoids and
|
|
373
|
+
Category of quotients of semigroups
|
|
374
|
+
sage: first_class = Q.__class__
|
|
375
|
+
sage: Q._refine_category_(Fields())
|
|
376
|
+
sage: Q.category()
|
|
377
|
+
Join of
|
|
378
|
+
Category of fields and
|
|
379
|
+
Category of subquotients of monoids and
|
|
380
|
+
Category of quotients of semigroups
|
|
381
|
+
sage: first_class == Q.__class__
|
|
382
|
+
False
|
|
383
|
+
sage: TestSuite(Q).run() # needs sage.libs.singular
|
|
384
|
+
|
|
385
|
+
TESTS:
|
|
386
|
+
|
|
387
|
+
Here is a test against :issue:`14471`. Refining the category will issue
|
|
388
|
+
a warning, if this change affects the hash value (note that this will
|
|
389
|
+
only be seen in doctest mode)::
|
|
390
|
+
|
|
391
|
+
sage: class MyParent(Parent):
|
|
392
|
+
....: def __hash__(self):
|
|
393
|
+
....: return hash(type(self)) # subtle mistake
|
|
394
|
+
sage: a = MyParent()
|
|
395
|
+
sage: h_a = hash(a)
|
|
396
|
+
sage: a._refine_category_(Algebras(QQ))
|
|
397
|
+
hash of <class '__main__.MyParent_with_category'> changed in
|
|
398
|
+
Parent._refine_category_ during initialisation
|
|
399
|
+
|
|
400
|
+
sage: b = MyParent(category=Rings())
|
|
401
|
+
sage: h_b = hash(b)
|
|
402
|
+
sage: h_a == h_b
|
|
403
|
+
False
|
|
404
|
+
sage: b._refine_category_(Algebras(QQ))
|
|
405
|
+
hash of <class '__main__.MyParent_with_category'> changed in
|
|
406
|
+
Parent._refine_category_ during refinement
|
|
407
|
+
sage: hash(a) == hash(b)
|
|
408
|
+
True
|
|
409
|
+
sage: hash(a) != h_a
|
|
410
|
+
True
|
|
411
|
+
"""
|
|
412
|
+
cdef Py_hash_t hash_old = -1
|
|
413
|
+
if debug.refine_category_hash_check:
|
|
414
|
+
# check that the hash stays the same after refinement
|
|
415
|
+
hash_old = hash(self)
|
|
416
|
+
|
|
417
|
+
if self._category is None:
|
|
418
|
+
self._init_category_(category)
|
|
419
|
+
if hash_old != -1 and hash_old != hash(self):
|
|
420
|
+
print(f'hash of {type(self)} changed in Parent._refine_category_ during initialisation')
|
|
421
|
+
return
|
|
422
|
+
if category is self._category:
|
|
423
|
+
return
|
|
424
|
+
CategoryObject._refine_category_(self, category)
|
|
425
|
+
category = self._category
|
|
426
|
+
|
|
427
|
+
# This substitutes the class of this parent to a subclass
|
|
428
|
+
# which also subclasses the parent_class of the category.
|
|
429
|
+
# However, we only do so if we do not have an extension class.
|
|
430
|
+
if can_assign_class(self):
|
|
431
|
+
# We tested in the very beginning that this parent
|
|
432
|
+
# had its category initialised. Hence, the class
|
|
433
|
+
# is already a dynamic class.
|
|
434
|
+
base = self.__class__.__base__
|
|
435
|
+
# documentation transfer is handled by dynamic_class
|
|
436
|
+
self.__class__ = dynamic_class(
|
|
437
|
+
"%s_with_category" % base.__name__,
|
|
438
|
+
(base, category.parent_class),
|
|
439
|
+
doccls=base)
|
|
440
|
+
# If the element class has already been assigned, it
|
|
441
|
+
# needs to be erased now.
|
|
442
|
+
try:
|
|
443
|
+
del self.__dict__['element_class']
|
|
444
|
+
del self.__dict__['_abstract_element_class']
|
|
445
|
+
except (AttributeError, KeyError):
|
|
446
|
+
pass
|
|
447
|
+
if hash_old != -1 and hash_old != hash(self):
|
|
448
|
+
print(f'hash of {type(self)} changed in Parent._refine_category_ during refinement')
|
|
449
|
+
|
|
450
|
+
def _unset_category(self):
|
|
451
|
+
"""
|
|
452
|
+
Remove the information on ``self``'s category.
|
|
453
|
+
|
|
454
|
+
.. NOTE::
|
|
455
|
+
|
|
456
|
+
This may change ``self``'s class!
|
|
457
|
+
|
|
458
|
+
EXAMPLES:
|
|
459
|
+
|
|
460
|
+
Let us create a parent in the category of rings::
|
|
461
|
+
|
|
462
|
+
sage: class MyParent(Parent):
|
|
463
|
+
....: def __init__(self):
|
|
464
|
+
....: Parent.__init__(self, category=Rings())
|
|
465
|
+
....:
|
|
466
|
+
sage: P = MyParent()
|
|
467
|
+
sage: P.category()
|
|
468
|
+
Category of rings
|
|
469
|
+
|
|
470
|
+
Of course, its category is initialised::
|
|
471
|
+
|
|
472
|
+
sage: P._is_category_initialized()
|
|
473
|
+
True
|
|
474
|
+
|
|
475
|
+
We may now refine the category to the category of fields.
|
|
476
|
+
Note that this changes the class::
|
|
477
|
+
|
|
478
|
+
sage: C = type(P)
|
|
479
|
+
sage: C == MyParent
|
|
480
|
+
False
|
|
481
|
+
sage: P._refine_category_(Fields())
|
|
482
|
+
sage: P.category()
|
|
483
|
+
Category of fields
|
|
484
|
+
sage: C == type(P)
|
|
485
|
+
False
|
|
486
|
+
|
|
487
|
+
Now we may have noticed that the category refinement was a
|
|
488
|
+
mistake. We do not need to worry, because we can undo category
|
|
489
|
+
initialisation totally::
|
|
490
|
+
|
|
491
|
+
sage: P._unset_category()
|
|
492
|
+
sage: P._is_category_initialized()
|
|
493
|
+
False
|
|
494
|
+
sage: type(P) == MyParent
|
|
495
|
+
True
|
|
496
|
+
|
|
497
|
+
Hence, we can now initialise the parent again in the original
|
|
498
|
+
category, i.e., the category of rings. We find that not only
|
|
499
|
+
the category, but also the class of the parent is brought back
|
|
500
|
+
to what it was after the original category initialisation::
|
|
501
|
+
|
|
502
|
+
sage: P._init_category_(Rings())
|
|
503
|
+
sage: type(P) == C
|
|
504
|
+
True
|
|
505
|
+
"""
|
|
506
|
+
self._category = None
|
|
507
|
+
if can_assign_class(self):
|
|
508
|
+
while issubclass(self.__class__, Sets_parent_class):
|
|
509
|
+
self.__class__ = self.__class__.__base__
|
|
510
|
+
|
|
511
|
+
@lazy_attribute
|
|
512
|
+
def _abstract_element_class(self):
|
|
513
|
+
"""
|
|
514
|
+
An abstract class for the elements of this parent.
|
|
515
|
+
|
|
516
|
+
By default, this is the element class provided by the category
|
|
517
|
+
of the parent.
|
|
518
|
+
|
|
519
|
+
.. SEEALSO::
|
|
520
|
+
|
|
521
|
+
- :meth:`sage.categories.homset.Homset._abstract_element_class`
|
|
522
|
+
- :meth:`element_class`
|
|
523
|
+
- :meth:`Element.__getattr__`
|
|
524
|
+
|
|
525
|
+
EXAMPLES::
|
|
526
|
+
|
|
527
|
+
sage: S = Semigroups().example()
|
|
528
|
+
sage: S.category()
|
|
529
|
+
Category of semigroups
|
|
530
|
+
sage: S._abstract_element_class
|
|
531
|
+
<class 'sage.categories.semigroups.Semigroups.element_class'>
|
|
532
|
+
"""
|
|
533
|
+
return self.category().element_class
|
|
534
|
+
|
|
535
|
+
# This probably should go into Sets().Parent
|
|
536
|
+
@lazy_attribute
|
|
537
|
+
def element_class(self):
|
|
538
|
+
"""
|
|
539
|
+
The (default) class for the elements of this parent.
|
|
540
|
+
|
|
541
|
+
FIXME's and design issues:
|
|
542
|
+
|
|
543
|
+
- If self.Element is "trivial enough", should we optimize it away with:
|
|
544
|
+
self.element_class = dynamic_class("%s.element_class"%self.__class__.__name__, (category.element_class,), self.Element)
|
|
545
|
+
- This should lookup for Element classes in all super classes
|
|
546
|
+
"""
|
|
547
|
+
try: # if hasattr(self, 'Element'):
|
|
548
|
+
return self.__make_element_class__(self.Element,
|
|
549
|
+
name="%s.element_class" % self.__class__.__name__,
|
|
550
|
+
module=self.__class__.__module__)
|
|
551
|
+
except AttributeError: # else:
|
|
552
|
+
return NotImplemented
|
|
553
|
+
|
|
554
|
+
def __make_element_class__(self, cls, name=None, module=None, inherit=None):
|
|
555
|
+
"""
|
|
556
|
+
A utility to construct classes for the elements of this
|
|
557
|
+
parent, with appropriate inheritance from the element class of
|
|
558
|
+
the category.
|
|
559
|
+
|
|
560
|
+
It used to be the case that this did not work for extension
|
|
561
|
+
types, which used to never support a ``__dict__`` for instances.
|
|
562
|
+
So for backwards compatibility, we only use dynamic classes by
|
|
563
|
+
default if the class has a nonzero ``__dictoffset__``. But it
|
|
564
|
+
works regardless: just pass ``inherit=True`` to
|
|
565
|
+
``__make_element_class__``. See also :issue:`24715`.
|
|
566
|
+
|
|
567
|
+
When we do not use a dynamic element class, the ``__getattr__``
|
|
568
|
+
implementation from :class:`Element` provides fake
|
|
569
|
+
inheritance from categories.
|
|
570
|
+
"""
|
|
571
|
+
if not isinstance(cls, type):
|
|
572
|
+
raise TypeError(f"element class {cls!r} should be a type")
|
|
573
|
+
if inherit is None:
|
|
574
|
+
inherit = (cls.__dictoffset__ != 0)
|
|
575
|
+
if inherit:
|
|
576
|
+
if name is None:
|
|
577
|
+
name = "%s_with_category" % cls.__name__
|
|
578
|
+
cls = dynamic_class(name, (cls, self._abstract_element_class))
|
|
579
|
+
if module is not None:
|
|
580
|
+
cls.__module__ = module
|
|
581
|
+
return cls
|
|
582
|
+
|
|
583
|
+
def _set_element_constructor(self):
|
|
584
|
+
"""
|
|
585
|
+
This function is used in translating from the old to the new coercion model.
|
|
586
|
+
|
|
587
|
+
It is called from sage.structure.parent_old.Parent.__init__
|
|
588
|
+
when an old style parent provides a _element_constructor_ method.
|
|
589
|
+
|
|
590
|
+
It just asserts that this _element_constructor_ is callable and
|
|
591
|
+
also sets self._element_init_pass_parent
|
|
592
|
+
|
|
593
|
+
EXAMPLES::
|
|
594
|
+
|
|
595
|
+
sage: k = GF(5)
|
|
596
|
+
sage: k._set_element_constructor()
|
|
597
|
+
"""
|
|
598
|
+
try:
|
|
599
|
+
_element_constructor_ = self._element_constructor_
|
|
600
|
+
except (AttributeError, TypeError):
|
|
601
|
+
# Remark: A TypeError can actually occur;
|
|
602
|
+
# it is a possible reason for "hasattr" to return False
|
|
603
|
+
return
|
|
604
|
+
assert callable(_element_constructor_)
|
|
605
|
+
self._element_constructor = _element_constructor_
|
|
606
|
+
self._element_init_pass_parent = guess_pass_parent(self, self._element_constructor)
|
|
607
|
+
|
|
608
|
+
def category(self):
|
|
609
|
+
"""
|
|
610
|
+
EXAMPLES::
|
|
611
|
+
|
|
612
|
+
sage: P = Parent()
|
|
613
|
+
sage: P.category()
|
|
614
|
+
Category of sets
|
|
615
|
+
sage: class MyParent(Parent):
|
|
616
|
+
....: def __init__(self): pass
|
|
617
|
+
sage: MyParent().category()
|
|
618
|
+
Category of sets
|
|
619
|
+
"""
|
|
620
|
+
if self._category is None:
|
|
621
|
+
# COERCE TODO: we should not need this
|
|
622
|
+
self._category = Sets()
|
|
623
|
+
return self._category
|
|
624
|
+
|
|
625
|
+
def _test_category(self, **options):
|
|
626
|
+
"""
|
|
627
|
+
Run generic tests on the method :meth:`.category`.
|
|
628
|
+
|
|
629
|
+
See also: :class:`TestSuite`.
|
|
630
|
+
|
|
631
|
+
EXAMPLES::
|
|
632
|
+
|
|
633
|
+
sage: C = Sets().example()
|
|
634
|
+
sage: C._test_category()
|
|
635
|
+
|
|
636
|
+
Let us now write a parent with broken categories:
|
|
637
|
+
|
|
638
|
+
sage: class MyParent(Parent):
|
|
639
|
+
....: def __init__(self):
|
|
640
|
+
....: pass
|
|
641
|
+
sage: P = MyParent()
|
|
642
|
+
sage: P._test_category()
|
|
643
|
+
Traceback (most recent call last):
|
|
644
|
+
...
|
|
645
|
+
AssertionError: category of <__main__.MyParent object ...> improperly initialized
|
|
646
|
+
|
|
647
|
+
To fix this, :meth:`MyParent.__init__` should initialize the
|
|
648
|
+
category of ``self`` by calling :meth:`._init_category` or
|
|
649
|
+
``Parent.__init__(self, category = ...)``.
|
|
650
|
+
"""
|
|
651
|
+
tester = self._tester(**options)
|
|
652
|
+
SageObject._test_category(self, tester=tester)
|
|
653
|
+
category = self.category()
|
|
654
|
+
tester.assertTrue(category.is_subcategory(Sets()))
|
|
655
|
+
# Tests that self inherits methods from the categories
|
|
656
|
+
if can_assign_class(self):
|
|
657
|
+
# For usual Python classes, that should be done with
|
|
658
|
+
# standard inheritance
|
|
659
|
+
tester.assertTrue(isinstance(self, category.parent_class),
|
|
660
|
+
_LazyString("category of %s improperly initialized", (self,), {}))
|
|
661
|
+
else:
|
|
662
|
+
# For extension types we just check that inheritance
|
|
663
|
+
# occurs on one specific method.
|
|
664
|
+
# _test_an_element from Sets().ParentMethods is a good
|
|
665
|
+
# candidate because it's unlikely to be overriden in self.
|
|
666
|
+
tester.assertTrue(hasattr(self, "_test_an_element"),
|
|
667
|
+
_LazyString("category of %s improperly initialized", (self,), {}))
|
|
668
|
+
|
|
669
|
+
def _test_eq(self, **options):
|
|
670
|
+
"""
|
|
671
|
+
Test that ``self`` is equal to ``self`` and different to ``None``.
|
|
672
|
+
|
|
673
|
+
See also: :class:`TestSuite`.
|
|
674
|
+
|
|
675
|
+
TESTS::
|
|
676
|
+
|
|
677
|
+
sage: O = Parent()
|
|
678
|
+
sage: O._test_eq()
|
|
679
|
+
|
|
680
|
+
Let us now write a broken class method::
|
|
681
|
+
|
|
682
|
+
sage: class CCls(Parent):
|
|
683
|
+
....: def __eq__(self, other):
|
|
684
|
+
....: return True
|
|
685
|
+
sage: CCls()._test_eq()
|
|
686
|
+
Traceback (most recent call last):
|
|
687
|
+
...
|
|
688
|
+
AssertionError: broken equality: <__main__.CCls object at ...> == None
|
|
689
|
+
|
|
690
|
+
Let us now break inequality::
|
|
691
|
+
|
|
692
|
+
sage: class CCls(Parent):
|
|
693
|
+
....: def __ne__(self, other):
|
|
694
|
+
....: return True
|
|
695
|
+
sage: CCls()._test_eq()
|
|
696
|
+
Traceback (most recent call last):
|
|
697
|
+
...
|
|
698
|
+
AssertionError: broken non-equality: <__main__.CCls object at ...> != itself
|
|
699
|
+
"""
|
|
700
|
+
tester = self._tester(**options)
|
|
701
|
+
|
|
702
|
+
# We do not use assertEqual / assertNonEqual in order to be
|
|
703
|
+
# 100% sure we indeed call the operators == and !=, whatever
|
|
704
|
+
# the version of Python is (see #11236)
|
|
705
|
+
tester.assertTrue(self == self,
|
|
706
|
+
_LazyString("broken equality: %s == itself is False", (self,), {}))
|
|
707
|
+
tester.assertFalse(self == None,
|
|
708
|
+
_LazyString("broken equality: %s == None", (self,), {}))
|
|
709
|
+
tester.assertFalse(self != self,
|
|
710
|
+
_LazyString("broken non-equality: %s != itself", (self,), {}))
|
|
711
|
+
tester.assertTrue(self != None,
|
|
712
|
+
_LazyString("broken non-equality: %s != None is False", (self,), {}))
|
|
713
|
+
|
|
714
|
+
cdef int init_coerce(self, bint warn=True) except -1:
|
|
715
|
+
if self._coerce_from_hash is None:
|
|
716
|
+
if warn:
|
|
717
|
+
raise AssertionError(f"unexpected call of init_coerce() for {type(self)}")
|
|
718
|
+
self._initial_coerce_list = []
|
|
719
|
+
self._initial_action_list = []
|
|
720
|
+
self._initial_convert_list = []
|
|
721
|
+
self._coerce_from_list = []
|
|
722
|
+
self._registered_domains = []
|
|
723
|
+
self._coerce_from_hash = MonoDict()
|
|
724
|
+
self._action_list = []
|
|
725
|
+
self._convert_from_list = []
|
|
726
|
+
self._convert_from_hash = MonoDict()
|
|
727
|
+
self._embedding = None
|
|
728
|
+
|
|
729
|
+
def _introspect_coerce(self):
|
|
730
|
+
"""
|
|
731
|
+
Used for debugging the coercion model.
|
|
732
|
+
|
|
733
|
+
EXAMPLES::
|
|
734
|
+
|
|
735
|
+
sage: sorted(QQ._introspect_coerce().items())
|
|
736
|
+
[('_action_list', []),
|
|
737
|
+
('_coerce_from_hash', <sage.structure.coerce_dict.MonoDict object at ...>),
|
|
738
|
+
('_coerce_from_list', []),
|
|
739
|
+
('_convert_from_hash', <sage.structure.coerce_dict.MonoDict object at ...>),
|
|
740
|
+
('_convert_from_list', [...]),
|
|
741
|
+
('_element_init_pass_parent', False),
|
|
742
|
+
('_embedding', None),
|
|
743
|
+
('_initial_action_list', []),
|
|
744
|
+
('_initial_coerce_list', []),
|
|
745
|
+
('_initial_convert_list', [])]
|
|
746
|
+
"""
|
|
747
|
+
return {
|
|
748
|
+
'_coerce_from_list': self._coerce_from_list,
|
|
749
|
+
'_coerce_from_hash': self._coerce_from_hash,
|
|
750
|
+
'_action_list': self._action_list,
|
|
751
|
+
'_convert_from_list': self._convert_from_list,
|
|
752
|
+
'_convert_from_hash': self._convert_from_hash,
|
|
753
|
+
'_embedding': self._embedding,
|
|
754
|
+
'_initial_coerce_list': self._initial_coerce_list,
|
|
755
|
+
'_initial_action_list': self._initial_action_list,
|
|
756
|
+
'_initial_convert_list': self._initial_convert_list,
|
|
757
|
+
'_element_init_pass_parent': self._element_init_pass_parent,
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
def __getstate__(self):
|
|
761
|
+
"""
|
|
762
|
+
Used for pickling.
|
|
763
|
+
|
|
764
|
+
TESTS::
|
|
765
|
+
|
|
766
|
+
sage: loads(dumps(RR['x'])) == RR['x']
|
|
767
|
+
True
|
|
768
|
+
"""
|
|
769
|
+
d = CategoryObject.__getstate__(self)
|
|
770
|
+
d['_embedding'] = self._embedding
|
|
771
|
+
d['_element_constructor'] = self._element_constructor
|
|
772
|
+
d['_convert_method_name'] = self._convert_method_name
|
|
773
|
+
d['_element_init_pass_parent'] = self._element_init_pass_parent
|
|
774
|
+
d['_initial_coerce_list'] = self._initial_coerce_list
|
|
775
|
+
d['_initial_action_list'] = self._initial_action_list
|
|
776
|
+
d['_initial_convert_list'] = self._initial_convert_list
|
|
777
|
+
return d
|
|
778
|
+
|
|
779
|
+
def __setstate__(self, d):
|
|
780
|
+
"""
|
|
781
|
+
Used for pickling.
|
|
782
|
+
|
|
783
|
+
TESTS::
|
|
784
|
+
|
|
785
|
+
sage: loads(dumps(CDF['x'])) == CDF['x'] # needs sage.rings.complex_double
|
|
786
|
+
True
|
|
787
|
+
"""
|
|
788
|
+
CategoryObject.__setstate__(self, d)
|
|
789
|
+
try:
|
|
790
|
+
version = d['_pickle_version']
|
|
791
|
+
except KeyError:
|
|
792
|
+
version = 0
|
|
793
|
+
if version == 1:
|
|
794
|
+
self.init_coerce(False) # Really, do we want to init this with the same initial data as before?
|
|
795
|
+
self._populate_coercion_lists_(coerce_list=d['_initial_coerce_list'] or [],
|
|
796
|
+
action_list=d['_initial_action_list'] or [],
|
|
797
|
+
convert_list=d['_initial_convert_list'] or [],
|
|
798
|
+
embedding=d['_embedding'],
|
|
799
|
+
convert_method_name=d['_convert_method_name'],
|
|
800
|
+
element_constructor=d['_element_constructor'],
|
|
801
|
+
init_no_parent=not d['_element_init_pass_parent'],
|
|
802
|
+
unpickling=True)
|
|
803
|
+
|
|
804
|
+
def _repr_option(self, key):
|
|
805
|
+
"""
|
|
806
|
+
Metadata about the :meth:`_repr_` output.
|
|
807
|
+
|
|
808
|
+
INPUT:
|
|
809
|
+
|
|
810
|
+
- ``key`` -- string; a key for different metadata informations
|
|
811
|
+
that can be inquired about
|
|
812
|
+
|
|
813
|
+
Valid ``key`` arguments are:
|
|
814
|
+
|
|
815
|
+
- ``'ascii_art'``: The :meth:`_repr_` output is multi-line
|
|
816
|
+
ascii art and each line must be printed starting at the same
|
|
817
|
+
column, or the meaning is lost.
|
|
818
|
+
|
|
819
|
+
- ``'element_ascii_art'``: same but for the output of the
|
|
820
|
+
elements. Used in :mod:`sage.repl.display.formatter`.
|
|
821
|
+
|
|
822
|
+
- ``'element_is_atomic'``: the elements print atomically, that
|
|
823
|
+
is, parenthesis are not required when *printing* out any of
|
|
824
|
+
`x - y`, `x + y`, `x^y` and `x/y`.
|
|
825
|
+
|
|
826
|
+
OUTPUT: boolean
|
|
827
|
+
|
|
828
|
+
EXAMPLES::
|
|
829
|
+
|
|
830
|
+
sage: ZZ._repr_option('ascii_art')
|
|
831
|
+
False
|
|
832
|
+
sage: MatrixSpace(ZZ, 2)._repr_option('element_ascii_art') # needs sage.modules
|
|
833
|
+
True
|
|
834
|
+
"""
|
|
835
|
+
if not isinstance(key, str):
|
|
836
|
+
raise ValueError('key must be a string')
|
|
837
|
+
defaults = {'ascii_art': False,
|
|
838
|
+
'element_ascii_art': False,
|
|
839
|
+
'element_is_atomic': False}
|
|
840
|
+
return defaults[key]
|
|
841
|
+
|
|
842
|
+
def __call__(self, x=0, *args, **kwds):
|
|
843
|
+
"""
|
|
844
|
+
This is the generic call method for all parents.
|
|
845
|
+
|
|
846
|
+
When called, it will find a map based on the Parent (or type) of x.
|
|
847
|
+
If a coercion exists, it will always be chosen. This map will
|
|
848
|
+
then be called (with the arguments and keywords if any).
|
|
849
|
+
|
|
850
|
+
By default this will dispatch as quickly as possible to
|
|
851
|
+
:meth:`_element_constructor_` though faster pathways are
|
|
852
|
+
possible if so desired.
|
|
853
|
+
|
|
854
|
+
TESTS:
|
|
855
|
+
|
|
856
|
+
We check that the invariant
|
|
857
|
+
|
|
858
|
+
::
|
|
859
|
+
|
|
860
|
+
self._element_init_pass_parent == guess_pass_parent(self, self._element_constructor)
|
|
861
|
+
|
|
862
|
+
is preserved (see :issue:`5979`)::
|
|
863
|
+
|
|
864
|
+
sage: class MyParent(Parent):
|
|
865
|
+
....: def _element_constructor_(self, x):
|
|
866
|
+
....: print("{} {}".format(self, x))
|
|
867
|
+
....: return sage.structure.element.Element(parent = self)
|
|
868
|
+
....: def _repr_(self):
|
|
869
|
+
....: return "my_parent"
|
|
870
|
+
sage: my_parent = MyParent()
|
|
871
|
+
sage: x = my_parent("bla")
|
|
872
|
+
my_parent bla
|
|
873
|
+
sage: x.parent() # indirect doctest
|
|
874
|
+
my_parent
|
|
875
|
+
|
|
876
|
+
sage: x = my_parent() # shouldn't this one raise an error?
|
|
877
|
+
my_parent 0
|
|
878
|
+
sage: x = my_parent(3) # todo: not implemented why does this one fail???
|
|
879
|
+
my_parent 3
|
|
880
|
+
"""
|
|
881
|
+
if self._element_constructor is None:
|
|
882
|
+
raise NotImplementedError(f"cannot construct elements of {self}")
|
|
883
|
+
cdef R = parent(x)
|
|
884
|
+
cdef bint no_extra_args = (not args and not kwds)
|
|
885
|
+
if R is self and no_extra_args:
|
|
886
|
+
return x
|
|
887
|
+
|
|
888
|
+
# Here we inline the first part of convert_map_from for speed.
|
|
889
|
+
# (Yes, the virtual function overhead can matter.)
|
|
890
|
+
if self._convert_from_hash is None: # this is because parent.__init__() does not always get called
|
|
891
|
+
self.init_coerce()
|
|
892
|
+
cdef map.Map mor
|
|
893
|
+
try:
|
|
894
|
+
mor = <map.Map> self._convert_from_hash.get(R)
|
|
895
|
+
except KeyError:
|
|
896
|
+
mor = <map.Map> self._internal_convert_map_from(R)
|
|
897
|
+
|
|
898
|
+
if mor is not None:
|
|
899
|
+
if no_extra_args:
|
|
900
|
+
return mor._call_(x)
|
|
901
|
+
else:
|
|
902
|
+
return mor._call_with_args(x, args, kwds)
|
|
903
|
+
|
|
904
|
+
raise TypeError(_LazyString("No conversion defined from %s to %s", (R, self), {}))
|
|
905
|
+
|
|
906
|
+
def __mul__(self, x):
|
|
907
|
+
"""
|
|
908
|
+
This is a multiplication method that more or less directly
|
|
909
|
+
calls another attribute ``_mul_`` (single underscore). This
|
|
910
|
+
is because ``__mul__`` cannot be implemented via inheritance
|
|
911
|
+
from the parent methods of the category, but ``_mul_`` can
|
|
912
|
+
be inherited. This is, e.g., used when creating twosided
|
|
913
|
+
ideals of matrix algebras. See :issue:`7797`.
|
|
914
|
+
|
|
915
|
+
EXAMPLES::
|
|
916
|
+
|
|
917
|
+
sage: MS = MatrixSpace(QQ, 2, 2) # needs sage.modules
|
|
918
|
+
|
|
919
|
+
This matrix space is in fact an algebra, and in particular
|
|
920
|
+
it is a ring, from the point of view of categories::
|
|
921
|
+
|
|
922
|
+
sage: MS.category() # needs sage.modules
|
|
923
|
+
Category of infinite finite dimensional algebras with basis
|
|
924
|
+
over (number fields and quotient fields and metric spaces)
|
|
925
|
+
sage: MS in Rings() # needs sage.modules
|
|
926
|
+
True
|
|
927
|
+
|
|
928
|
+
However, its class does not inherit from the base class
|
|
929
|
+
``Ring``::
|
|
930
|
+
|
|
931
|
+
sage: isinstance(MS, Ring) # needs sage.modules
|
|
932
|
+
False
|
|
933
|
+
|
|
934
|
+
Its ``_mul_`` method is inherited from the category, and
|
|
935
|
+
can be used to create a left or right ideal::
|
|
936
|
+
|
|
937
|
+
sage: # needs sage.modules
|
|
938
|
+
sage: MS._mul_.__module__
|
|
939
|
+
'sage.categories.rings'
|
|
940
|
+
sage: MS * MS.1 # indirect doctest
|
|
941
|
+
Left Ideal
|
|
942
|
+
(
|
|
943
|
+
[0 1]
|
|
944
|
+
[0 0]
|
|
945
|
+
)
|
|
946
|
+
of Full MatrixSpace of 2 by 2 dense matrices over Rational Field
|
|
947
|
+
sage: MS * [MS.1, 2]
|
|
948
|
+
Left Ideal
|
|
949
|
+
(
|
|
950
|
+
[0 1]
|
|
951
|
+
[0 0],
|
|
952
|
+
<BLANKLINE>
|
|
953
|
+
[2 0]
|
|
954
|
+
[0 2]
|
|
955
|
+
)
|
|
956
|
+
of Full MatrixSpace of 2 by 2 dense matrices over Rational Field
|
|
957
|
+
sage: MS.1 * MS
|
|
958
|
+
Right Ideal
|
|
959
|
+
(
|
|
960
|
+
[0 1]
|
|
961
|
+
[0 0]
|
|
962
|
+
)
|
|
963
|
+
of Full MatrixSpace of 2 by 2 dense matrices over Rational Field
|
|
964
|
+
sage: [MS.1, 2] * MS
|
|
965
|
+
Right Ideal
|
|
966
|
+
(
|
|
967
|
+
[0 1]
|
|
968
|
+
[0 0],
|
|
969
|
+
<BLANKLINE>
|
|
970
|
+
[2 0]
|
|
971
|
+
[0 2]
|
|
972
|
+
)
|
|
973
|
+
of Full MatrixSpace of 2 by 2 dense matrices over Rational Field
|
|
974
|
+
"""
|
|
975
|
+
# generic multiplication method. It defers to
|
|
976
|
+
# _mul_, which may be defined via categories.
|
|
977
|
+
_mul_ = None
|
|
978
|
+
switch = False
|
|
979
|
+
try:
|
|
980
|
+
if isinstance(self, Parent):
|
|
981
|
+
_mul_ = self._mul_
|
|
982
|
+
except AttributeError:
|
|
983
|
+
pass
|
|
984
|
+
if _mul_ is None:
|
|
985
|
+
try:
|
|
986
|
+
if isinstance(x, Parent):
|
|
987
|
+
_mul_ = x._mul_
|
|
988
|
+
switch = True
|
|
989
|
+
except AttributeError:
|
|
990
|
+
pass
|
|
991
|
+
if _mul_ is None:
|
|
992
|
+
raise TypeError(_LazyString("For implementing multiplication, provide the method '_mul_' for %s resp. %s", (self, x), {}))
|
|
993
|
+
if switch:
|
|
994
|
+
return _mul_(self, switch_sides=True)
|
|
995
|
+
return _mul_(x)
|
|
996
|
+
|
|
997
|
+
def __pow__(self, x, mod):
|
|
998
|
+
"""
|
|
999
|
+
Power function.
|
|
1000
|
+
|
|
1001
|
+
The default implementation of ``__pow__`` on parent redirects to the
|
|
1002
|
+
super class (in case of multiple inheritance) or to the category. This
|
|
1003
|
+
redirection is necessary when the parent is a Cython class (aka
|
|
1004
|
+
extension class) because in that case the parent class does not inherit
|
|
1005
|
+
from the ``ParentMethods`` of the category.
|
|
1006
|
+
|
|
1007
|
+
Concrete implementations of parents can freely overwrite this default
|
|
1008
|
+
method.
|
|
1009
|
+
|
|
1010
|
+
TESTS::
|
|
1011
|
+
|
|
1012
|
+
sage: # needs sage.modules
|
|
1013
|
+
sage: ZZ^3
|
|
1014
|
+
Ambient free module of rank 3 over the principal ideal domain
|
|
1015
|
+
Integer Ring
|
|
1016
|
+
sage: QQ^3
|
|
1017
|
+
Vector space of dimension 3 over Rational Field
|
|
1018
|
+
sage: QQ['x']^3
|
|
1019
|
+
Ambient free module of rank 3 over the principal ideal domain
|
|
1020
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
1021
|
+
sage: IntegerModRing(6)^3
|
|
1022
|
+
Ambient free module of rank 3 over Ring of integers modulo 6
|
|
1023
|
+
|
|
1024
|
+
sage: 3^ZZ
|
|
1025
|
+
Traceback (most recent call last):
|
|
1026
|
+
...
|
|
1027
|
+
TypeError: unsupported operand parent(s) for ^: 'Integer Ring' and '<class 'sage.rings.integer_ring.IntegerRing_class'>'
|
|
1028
|
+
sage: Partitions(3)^3 # needs sage.modules
|
|
1029
|
+
Traceback (most recent call last):
|
|
1030
|
+
...
|
|
1031
|
+
TypeError: unsupported operand type(s) for ** or pow(): 'Partitions_n_with_category' and 'int'
|
|
1032
|
+
|
|
1033
|
+
Check multiple inheritance::
|
|
1034
|
+
|
|
1035
|
+
sage: class A:
|
|
1036
|
+
....: def __pow__(self, n):
|
|
1037
|
+
....: return 'Apow'
|
|
1038
|
+
sage: class MyParent(A, Parent):
|
|
1039
|
+
....: pass
|
|
1040
|
+
sage: MyParent()^2
|
|
1041
|
+
'Apow'
|
|
1042
|
+
"""
|
|
1043
|
+
if mod is not None or not isinstance(self, Parent):
|
|
1044
|
+
return NotImplemented
|
|
1045
|
+
try:
|
|
1046
|
+
# get __pow__ from super class
|
|
1047
|
+
meth = super().__pow__
|
|
1048
|
+
except AttributeError:
|
|
1049
|
+
# get __pow__ from category in case the parent is a Cython class
|
|
1050
|
+
try:
|
|
1051
|
+
meth = (<Parent> self).getattr_from_category('__pow__')
|
|
1052
|
+
except AttributeError:
|
|
1053
|
+
return NotImplemented
|
|
1054
|
+
return meth(x)
|
|
1055
|
+
|
|
1056
|
+
#############################################################################
|
|
1057
|
+
# Containment testing
|
|
1058
|
+
#############################################################################
|
|
1059
|
+
def __contains__(self, x):
|
|
1060
|
+
r"""
|
|
1061
|
+
``True`` if there is an element of ``self`` that is equal to ``x``
|
|
1062
|
+
under ``==``, or if ``x`` is already an element of ``self``. Also,
|
|
1063
|
+
``True`` in other cases involving the Symbolic Ring, which is handled
|
|
1064
|
+
specially.
|
|
1065
|
+
|
|
1066
|
+
For many structures we test this by using :meth:`__call__` and
|
|
1067
|
+
then testing equality between ``x`` and the result.
|
|
1068
|
+
|
|
1069
|
+
The Symbolic Ring is treated differently because it is
|
|
1070
|
+
ultra-permissive about letting other rings coerce in, but
|
|
1071
|
+
ultra-strict about doing comparisons.
|
|
1072
|
+
|
|
1073
|
+
EXAMPLES::
|
|
1074
|
+
|
|
1075
|
+
sage: 2 in Integers(7)
|
|
1076
|
+
True
|
|
1077
|
+
sage: 2 in ZZ
|
|
1078
|
+
True
|
|
1079
|
+
sage: Integers(7)(3) in ZZ
|
|
1080
|
+
True
|
|
1081
|
+
sage: 3/1 in ZZ
|
|
1082
|
+
True
|
|
1083
|
+
sage: 5 in QQ
|
|
1084
|
+
True
|
|
1085
|
+
sage: I in RR # needs sage.rings.real_mpfr sage.symbolic
|
|
1086
|
+
False
|
|
1087
|
+
sage: RIF(1, 2) in RIF # needs sage.rings.real_interval_field
|
|
1088
|
+
True
|
|
1089
|
+
|
|
1090
|
+
sage: # needs sage.symbolic
|
|
1091
|
+
sage: SR(2) in ZZ
|
|
1092
|
+
True
|
|
1093
|
+
sage: pi in RIF # there is no element of RIF equal to pi
|
|
1094
|
+
False
|
|
1095
|
+
sage: sqrt(2) in CC
|
|
1096
|
+
True
|
|
1097
|
+
sage: pi in RR
|
|
1098
|
+
True
|
|
1099
|
+
sage: pi in CC
|
|
1100
|
+
True
|
|
1101
|
+
sage: pi in RDF
|
|
1102
|
+
True
|
|
1103
|
+
sage: pi in CDF
|
|
1104
|
+
True
|
|
1105
|
+
|
|
1106
|
+
Note that we have
|
|
1107
|
+
|
|
1108
|
+
::
|
|
1109
|
+
|
|
1110
|
+
sage: 3/2 in RIF # needs sage.rings.real_interval_field
|
|
1111
|
+
True
|
|
1112
|
+
|
|
1113
|
+
because ``3/2`` has an exact representation in ``RIF`` (i.e. can be
|
|
1114
|
+
represented as an interval that contains exactly one value)::
|
|
1115
|
+
|
|
1116
|
+
sage: RIF(3/2).is_exact() # needs sage.rings.real_interval_field
|
|
1117
|
+
True
|
|
1118
|
+
|
|
1119
|
+
On the other hand, we have
|
|
1120
|
+
|
|
1121
|
+
::
|
|
1122
|
+
|
|
1123
|
+
sage: 2/3 in RIF # needs sage.rings.real_interval_field
|
|
1124
|
+
False
|
|
1125
|
+
|
|
1126
|
+
because ``2/3`` has no exact representation in ``RIF``. Since
|
|
1127
|
+
``RIF(2/3)`` is a nontrivial interval, it cannot be equal to anything
|
|
1128
|
+
(not even itself)::
|
|
1129
|
+
|
|
1130
|
+
sage: RIF(2/3).is_exact() # needs sage.rings.real_interval_field
|
|
1131
|
+
False
|
|
1132
|
+
sage: RIF(2/3).endpoints() # needs sage.rings.real_interval_field
|
|
1133
|
+
(0.666666666666666, 0.666666666666667)
|
|
1134
|
+
sage: RIF(2/3) == RIF(2/3) # needs sage.rings.real_interval_field
|
|
1135
|
+
False
|
|
1136
|
+
|
|
1137
|
+
TESTS:
|
|
1138
|
+
|
|
1139
|
+
Check that :issue:`13824` is fixed::
|
|
1140
|
+
|
|
1141
|
+
sage: 4/3 in GF(3)
|
|
1142
|
+
False
|
|
1143
|
+
sage: 15/50 in GF(25, 'a') # needs sage.rings.finite_rings
|
|
1144
|
+
False
|
|
1145
|
+
sage: 7/4 in Integers(4)
|
|
1146
|
+
False
|
|
1147
|
+
sage: 15/36 in Integers(6)
|
|
1148
|
+
False
|
|
1149
|
+
|
|
1150
|
+
Check that :issue:`32078` is fixed::
|
|
1151
|
+
|
|
1152
|
+
sage: P = Frac(ZZ['x,y'])
|
|
1153
|
+
sage: P(1) in ZZ # needs sage.libs.singular
|
|
1154
|
+
True
|
|
1155
|
+
sage: P(1/2) in ZZ # needs sage.libs.singular
|
|
1156
|
+
False
|
|
1157
|
+
|
|
1158
|
+
Check that :issue:`24209` is fixed::
|
|
1159
|
+
|
|
1160
|
+
sage: I in QQbar # needs sage.rings.number_field
|
|
1161
|
+
True
|
|
1162
|
+
sage: sqrt(-1) in QQbar # needs sage.rings.number_field sage.symbolic
|
|
1163
|
+
True
|
|
1164
|
+
"""
|
|
1165
|
+
P = parent(x)
|
|
1166
|
+
if P is self or P == self:
|
|
1167
|
+
return True
|
|
1168
|
+
try:
|
|
1169
|
+
x2 = self(x)
|
|
1170
|
+
EQ = (x2 == x)
|
|
1171
|
+
if EQ is True:
|
|
1172
|
+
return True
|
|
1173
|
+
elif EQ is False:
|
|
1174
|
+
return False
|
|
1175
|
+
elif EQ:
|
|
1176
|
+
return True
|
|
1177
|
+
else:
|
|
1178
|
+
from sage.structure.element import Expression
|
|
1179
|
+
return isinstance(EQ, Expression)
|
|
1180
|
+
# if comparing gives an Expression, then it must be an equation.
|
|
1181
|
+
# We return *true* here, even though the equation
|
|
1182
|
+
# EQ must have evaluated to False for us to get to
|
|
1183
|
+
# this point. The reason is because... in practice
|
|
1184
|
+
# SR is ultra-permissive about letting other rings
|
|
1185
|
+
# coerce in, but ultra-strict about doing
|
|
1186
|
+
# comparisons.
|
|
1187
|
+
except (TypeError, ValueError, ArithmeticError):
|
|
1188
|
+
return False
|
|
1189
|
+
|
|
1190
|
+
cpdef coerce(self, x):
|
|
1191
|
+
"""
|
|
1192
|
+
Return x as an element of ``self``, if and only if there is a
|
|
1193
|
+
canonical coercion from the parent of x to ``self``.
|
|
1194
|
+
|
|
1195
|
+
EXAMPLES::
|
|
1196
|
+
|
|
1197
|
+
sage: QQ.coerce(ZZ(2))
|
|
1198
|
+
2
|
|
1199
|
+
sage: ZZ.coerce(QQ(2))
|
|
1200
|
+
Traceback (most recent call last):
|
|
1201
|
+
...
|
|
1202
|
+
TypeError: no canonical coercion from Rational Field to Integer Ring
|
|
1203
|
+
|
|
1204
|
+
We make an exception for zero::
|
|
1205
|
+
|
|
1206
|
+
sage: V = GF(7)^7 # needs sage.modules
|
|
1207
|
+
sage: V.coerce(0) # needs sage.modules
|
|
1208
|
+
(0, 0, 0, 0, 0, 0, 0)
|
|
1209
|
+
"""
|
|
1210
|
+
cdef R = parent(x)
|
|
1211
|
+
if R is self:
|
|
1212
|
+
return x
|
|
1213
|
+
mor = self._internal_coerce_map_from(R)
|
|
1214
|
+
if mor is None:
|
|
1215
|
+
if is_Integer(x) and not x:
|
|
1216
|
+
try:
|
|
1217
|
+
return self(0)
|
|
1218
|
+
except Exception:
|
|
1219
|
+
_record_exception()
|
|
1220
|
+
raise TypeError(_LazyString("no canonical coercion from %s to %s", (parent(x), self), {}))
|
|
1221
|
+
else:
|
|
1222
|
+
return (<map.Map>mor)._call_(x)
|
|
1223
|
+
|
|
1224
|
+
def __bool__(self):
|
|
1225
|
+
"""
|
|
1226
|
+
By default, all Parents are treated as ``True`` when used in an if
|
|
1227
|
+
statement. Override this method if other behavior is desired
|
|
1228
|
+
(for example, for empty sets).
|
|
1229
|
+
|
|
1230
|
+
EXAMPLES::
|
|
1231
|
+
|
|
1232
|
+
sage: if ZZ: print("Yes")
|
|
1233
|
+
Yes
|
|
1234
|
+
"""
|
|
1235
|
+
return True
|
|
1236
|
+
|
|
1237
|
+
# Should be moved and merged into the EnumeratedSets() category (#12955)
|
|
1238
|
+
def __getitem__(self, n):
|
|
1239
|
+
"""
|
|
1240
|
+
Return the `n`-th item or slice `n` of ``self``,
|
|
1241
|
+
by getting ``self`` as a list.
|
|
1242
|
+
|
|
1243
|
+
EXAMPLES::
|
|
1244
|
+
|
|
1245
|
+
sage: VectorSpace(GF(7), 3)[:10] # needs sage.modules
|
|
1246
|
+
[(0, 0, 0),
|
|
1247
|
+
(1, 0, 0),
|
|
1248
|
+
(2, 0, 0),
|
|
1249
|
+
(3, 0, 0),
|
|
1250
|
+
(4, 0, 0),
|
|
1251
|
+
(5, 0, 0),
|
|
1252
|
+
(6, 0, 0),
|
|
1253
|
+
(0, 1, 0),
|
|
1254
|
+
(1, 1, 0),
|
|
1255
|
+
(2, 1, 0)]
|
|
1256
|
+
|
|
1257
|
+
TESTS:
|
|
1258
|
+
|
|
1259
|
+
We test the workaround described in :issue:`12956` to let categories
|
|
1260
|
+
override this default implementation::
|
|
1261
|
+
|
|
1262
|
+
sage: class As(Category):
|
|
1263
|
+
....: def super_categories(self): return [Sets()]
|
|
1264
|
+
....: class ParentMethods:
|
|
1265
|
+
....: def __getitem__(self, n):
|
|
1266
|
+
....: return 'coucou'
|
|
1267
|
+
sage: class A(Parent):
|
|
1268
|
+
....: def __init__(self):
|
|
1269
|
+
....: Parent.__init__(self, category=As())
|
|
1270
|
+
sage: a = A()
|
|
1271
|
+
sage: a[1]
|
|
1272
|
+
'coucou'
|
|
1273
|
+
"""
|
|
1274
|
+
try:
|
|
1275
|
+
meth = super().__getitem__
|
|
1276
|
+
except AttributeError:
|
|
1277
|
+
# needed when self is a Cython object
|
|
1278
|
+
try:
|
|
1279
|
+
meth = self.getattr_from_category('__getitem__')
|
|
1280
|
+
except AttributeError:
|
|
1281
|
+
return self.list()[n]
|
|
1282
|
+
return meth(n)
|
|
1283
|
+
|
|
1284
|
+
#########################################################################
|
|
1285
|
+
# Generators and Homomorphisms
|
|
1286
|
+
#########################################################################
|
|
1287
|
+
|
|
1288
|
+
def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None):
|
|
1289
|
+
r"""
|
|
1290
|
+
Return ``True`` if ``im_gens`` defines a valid homomorphism
|
|
1291
|
+
from ``self`` to ``codomain``; otherwise return ``False``.
|
|
1292
|
+
|
|
1293
|
+
If determining whether or not a homomorphism is valid has not
|
|
1294
|
+
been implemented for this ring, then a :exc:`NotImplementedError`
|
|
1295
|
+
exception is raised.
|
|
1296
|
+
"""
|
|
1297
|
+
raise NotImplementedError("Verification of correctness of homomorphisms from %s not yet implemented." % self)
|
|
1298
|
+
|
|
1299
|
+
def Hom(self, codomain, category=None):
|
|
1300
|
+
r"""
|
|
1301
|
+
Return the homspace ``Hom(self, codomain, category)``.
|
|
1302
|
+
|
|
1303
|
+
INPUT:
|
|
1304
|
+
|
|
1305
|
+
- ``codomain`` -- a parent
|
|
1306
|
+
- ``category`` -- a category or ``None`` (default: ``None``)
|
|
1307
|
+
If ``None``, the meet of the category of ``self`` and
|
|
1308
|
+
``codomain`` is used.
|
|
1309
|
+
|
|
1310
|
+
OUTPUT:
|
|
1311
|
+
|
|
1312
|
+
The homspace of all homomorphisms from ``self`` to
|
|
1313
|
+
``codomain`` in the category ``category``.
|
|
1314
|
+
|
|
1315
|
+
.. SEEALSO:: :func:`~sage.categories.homset.Hom`
|
|
1316
|
+
|
|
1317
|
+
EXAMPLES::
|
|
1318
|
+
|
|
1319
|
+
sage: R.<x,y> = PolynomialRing(QQ, 2)
|
|
1320
|
+
sage: R.Hom(QQ)
|
|
1321
|
+
Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Rational Field
|
|
1322
|
+
|
|
1323
|
+
Homspaces are defined for very general Sage objects, even elements of familiar rings::
|
|
1324
|
+
|
|
1325
|
+
sage: n = 5; Hom(n,7)
|
|
1326
|
+
Set of Morphisms from 5 to 7 in Category of elements of Integer Ring
|
|
1327
|
+
sage: z=(2/3); Hom(z,8/1)
|
|
1328
|
+
Set of Morphisms from 2/3 to 8 in Category of elements of Rational Field
|
|
1329
|
+
|
|
1330
|
+
This example illustrates the optional third argument::
|
|
1331
|
+
|
|
1332
|
+
sage: QQ.Hom(ZZ, Sets())
|
|
1333
|
+
Set of Morphisms from Rational Field to Integer Ring in Category of sets
|
|
1334
|
+
|
|
1335
|
+
A parent may specify how to construct certain homsets by
|
|
1336
|
+
implementing a method :meth:`_Hom_`(codomain, category).
|
|
1337
|
+
See :func:`~sage.categories.homset.Hom` for details.
|
|
1338
|
+
"""
|
|
1339
|
+
from sage.categories.homset import Hom
|
|
1340
|
+
return Hom(self, codomain, category)
|
|
1341
|
+
|
|
1342
|
+
def hom(self, im_gens, codomain=None, check=None, base_map=None, category=None, **kwds):
|
|
1343
|
+
r"""
|
|
1344
|
+
Return the unique homomorphism from ``self`` to ``codomain`` that
|
|
1345
|
+
sends ``self.gens()`` to the entries of ``im_gens``.
|
|
1346
|
+
|
|
1347
|
+
This raises a :exc:`TypeError` if there is no such homomorphism.
|
|
1348
|
+
|
|
1349
|
+
INPUT:
|
|
1350
|
+
|
|
1351
|
+
- ``im_gens`` -- the images in the codomain of the generators
|
|
1352
|
+
of this object under the homomorphism
|
|
1353
|
+
|
|
1354
|
+
- ``codomain`` -- the codomain of the homomorphism
|
|
1355
|
+
|
|
1356
|
+
- ``base_map`` -- a map from the base ring to the codomain; if not
|
|
1357
|
+
given, coercion is used
|
|
1358
|
+
|
|
1359
|
+
- ``check`` -- whether to verify that the images of generators
|
|
1360
|
+
extend to define a map (using only canonical coercions)
|
|
1361
|
+
|
|
1362
|
+
OUTPUT: a homomorphism ``self --> codomain``
|
|
1363
|
+
|
|
1364
|
+
.. NOTE::
|
|
1365
|
+
|
|
1366
|
+
As a shortcut, one can also give an object X instead of
|
|
1367
|
+
``im_gens``, in which case return the (if it exists)
|
|
1368
|
+
natural map to X.
|
|
1369
|
+
|
|
1370
|
+
EXAMPLES:
|
|
1371
|
+
|
|
1372
|
+
Polynomial Ring: We first illustrate construction of a few
|
|
1373
|
+
homomorphisms involving a polynomial ring::
|
|
1374
|
+
|
|
1375
|
+
sage: R.<x> = PolynomialRing(ZZ)
|
|
1376
|
+
sage: f = R.hom([5], QQ)
|
|
1377
|
+
sage: f(x^2 - 19)
|
|
1378
|
+
6
|
|
1379
|
+
|
|
1380
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
1381
|
+
sage: f = R.hom([5], GF(7))
|
|
1382
|
+
Traceback (most recent call last):
|
|
1383
|
+
...
|
|
1384
|
+
ValueError: relations do not all (canonically) map to 0
|
|
1385
|
+
under map determined by images of generators
|
|
1386
|
+
|
|
1387
|
+
sage: # needs sage.rings.finite_rings
|
|
1388
|
+
sage: R.<x> = PolynomialRing(GF(7))
|
|
1389
|
+
sage: f = R.hom([3], GF(49,'a'))
|
|
1390
|
+
sage: f
|
|
1391
|
+
Ring morphism:
|
|
1392
|
+
From: Univariate Polynomial Ring in x over Finite Field of size 7
|
|
1393
|
+
To: Finite Field in a of size 7^2
|
|
1394
|
+
Defn: x |--> 3
|
|
1395
|
+
sage: f(x + 6)
|
|
1396
|
+
2
|
|
1397
|
+
sage: f(x^2 + 1)
|
|
1398
|
+
3
|
|
1399
|
+
|
|
1400
|
+
Natural morphism::
|
|
1401
|
+
|
|
1402
|
+
sage: f = ZZ.hom(GF(5))
|
|
1403
|
+
sage: f(7)
|
|
1404
|
+
2
|
|
1405
|
+
sage: f
|
|
1406
|
+
Natural morphism:
|
|
1407
|
+
From: Integer Ring
|
|
1408
|
+
To: Finite Field of size 5
|
|
1409
|
+
|
|
1410
|
+
There might not be a natural morphism, in which case a
|
|
1411
|
+
:exc:`TypeError` is raised::
|
|
1412
|
+
|
|
1413
|
+
sage: QQ.hom(ZZ)
|
|
1414
|
+
Traceback (most recent call last):
|
|
1415
|
+
...
|
|
1416
|
+
TypeError: natural coercion morphism from Rational Field to Integer Ring not defined
|
|
1417
|
+
"""
|
|
1418
|
+
if isinstance(im_gens, Parent):
|
|
1419
|
+
return self.Hom(im_gens).natural_map()
|
|
1420
|
+
from sage.structure.sequence import Sequence_generic, Sequence
|
|
1421
|
+
if codomain is None:
|
|
1422
|
+
im_gens = Sequence(im_gens)
|
|
1423
|
+
codomain = im_gens.universe()
|
|
1424
|
+
if isinstance(im_gens, Sequence_generic):
|
|
1425
|
+
im_gens = list(im_gens)
|
|
1426
|
+
# Not all homsets accept category/check/base_map as arguments
|
|
1427
|
+
if check is not None:
|
|
1428
|
+
kwds['check'] = check
|
|
1429
|
+
if base_map is not None:
|
|
1430
|
+
# Ideally we would have machinery here to determine
|
|
1431
|
+
# how the base map affects the category of the resulting
|
|
1432
|
+
# morphism. But for now it's not clear how to do this,
|
|
1433
|
+
# so we leave the category as the default for now.
|
|
1434
|
+
kwds['base_map'] = base_map
|
|
1435
|
+
Hom_kwds = {} if category is None else {'category': category}
|
|
1436
|
+
return self.Hom(codomain, **Hom_kwds)(im_gens, **kwds)
|
|
1437
|
+
|
|
1438
|
+
#################################################################################
|
|
1439
|
+
# New Coercion support functionality
|
|
1440
|
+
#################################################################################
|
|
1441
|
+
|
|
1442
|
+
def _populate_coercion_lists_(self,
|
|
1443
|
+
coerce_list=[],
|
|
1444
|
+
action_list=[],
|
|
1445
|
+
convert_list=[],
|
|
1446
|
+
embedding=None,
|
|
1447
|
+
convert_method_name=None,
|
|
1448
|
+
element_constructor=None,
|
|
1449
|
+
init_no_parent=None,
|
|
1450
|
+
bint unpickling=False):
|
|
1451
|
+
"""
|
|
1452
|
+
This function allows one to specify coercions, actions, conversions
|
|
1453
|
+
and embeddings involving this parent.
|
|
1454
|
+
|
|
1455
|
+
IT SHOULD ONLY BE CALLED DURING THE __INIT__ method, often at the end.
|
|
1456
|
+
|
|
1457
|
+
INPUT:
|
|
1458
|
+
|
|
1459
|
+
- ``coerce_list`` -- list of coercion Morphisms to ``self`` and
|
|
1460
|
+
parents with canonical coercions to ``self``
|
|
1461
|
+
|
|
1462
|
+
- ``action_list`` -- list of actions on and by ``self``
|
|
1463
|
+
|
|
1464
|
+
- ``convert_list`` -- list of conversion Maps to ``self`` and
|
|
1465
|
+
parents with conversions to ``self``
|
|
1466
|
+
|
|
1467
|
+
- ``embedding`` -- a single Morphism from ``self``
|
|
1468
|
+
|
|
1469
|
+
- ``convert_method_name`` -- a name to look for that other elements
|
|
1470
|
+
can implement to create elements of ``self`` (e.g. ``_integer_``)
|
|
1471
|
+
|
|
1472
|
+
- ``init_no_parent`` -- if ``True`` omit passing ``self`` in as the
|
|
1473
|
+
first argument of element_constructor for conversion. This
|
|
1474
|
+
is useful if parents are unique, or element_constructor is a
|
|
1475
|
+
bound method (this latter case can be detected automatically).
|
|
1476
|
+
"""
|
|
1477
|
+
self.init_coerce(False)
|
|
1478
|
+
|
|
1479
|
+
if not unpickling:
|
|
1480
|
+
if element_constructor is not None:
|
|
1481
|
+
raise ValueError("element_constructor can only be given when unpickling is True")
|
|
1482
|
+
try:
|
|
1483
|
+
element_constructor = self._element_constructor_
|
|
1484
|
+
except AttributeError:
|
|
1485
|
+
raise RuntimeError("an _element_constructor_ method must be defined")
|
|
1486
|
+
self._element_constructor = element_constructor
|
|
1487
|
+
self._element_init_pass_parent = guess_pass_parent(self, element_constructor)
|
|
1488
|
+
|
|
1489
|
+
if not isinstance(coerce_list, list):
|
|
1490
|
+
raise ValueError(_LazyString("%s_populate_coercion_lists_: coerce_list is type %s, must be list", (type(coerce_list), type(self)), {}))
|
|
1491
|
+
if not isinstance(action_list, list):
|
|
1492
|
+
raise ValueError(_LazyString("%s_populate_coercion_lists_: action_list is type %s, must be list", (type(action_list), type(self)), {}))
|
|
1493
|
+
if not isinstance(convert_list, list):
|
|
1494
|
+
raise ValueError(_LazyString("%s_populate_coercion_lists_: convert_list is type %s, must be list", (type(convert_list), type(self)), {}))
|
|
1495
|
+
|
|
1496
|
+
self._initial_coerce_list = copy(coerce_list)
|
|
1497
|
+
self._initial_action_list = copy(action_list)
|
|
1498
|
+
self._initial_convert_list = copy(convert_list)
|
|
1499
|
+
|
|
1500
|
+
self._convert_method_name = convert_method_name
|
|
1501
|
+
if init_no_parent is not None:
|
|
1502
|
+
self._element_init_pass_parent = not init_no_parent
|
|
1503
|
+
|
|
1504
|
+
for mor in coerce_list:
|
|
1505
|
+
self.register_coercion(mor)
|
|
1506
|
+
for action in action_list:
|
|
1507
|
+
self.register_action(action)
|
|
1508
|
+
for mor in convert_list:
|
|
1509
|
+
self.register_conversion(mor)
|
|
1510
|
+
if embedding is not None:
|
|
1511
|
+
self.register_embedding(embedding)
|
|
1512
|
+
|
|
1513
|
+
def _unset_coercions_used(self):
|
|
1514
|
+
r"""
|
|
1515
|
+
Pretend that this parent has never been interrogated by the coercion
|
|
1516
|
+
model, so that it is possible to add coercions, conversions, and
|
|
1517
|
+
actions. Does not remove any existing embedding.
|
|
1518
|
+
|
|
1519
|
+
WARNING::
|
|
1520
|
+
|
|
1521
|
+
For internal use only!
|
|
1522
|
+
"""
|
|
1523
|
+
self._coercions_used = False
|
|
1524
|
+
coercion_model.reset_cache()
|
|
1525
|
+
|
|
1526
|
+
def _unset_embedding(self):
|
|
1527
|
+
r"""
|
|
1528
|
+
Pretend that this parent has never been interrogated by the
|
|
1529
|
+
coercion model, and remove any existing embedding.
|
|
1530
|
+
|
|
1531
|
+
WARNING::
|
|
1532
|
+
|
|
1533
|
+
This does *not* make it safe to add an entirely new embedding! It
|
|
1534
|
+
is possible that a `Parent` has cached information about the
|
|
1535
|
+
existing embedding; that cached information *is not* removed by
|
|
1536
|
+
this call.
|
|
1537
|
+
|
|
1538
|
+
For internal use only!
|
|
1539
|
+
"""
|
|
1540
|
+
self._embedding = None
|
|
1541
|
+
self._unset_coercions_used()
|
|
1542
|
+
|
|
1543
|
+
def _is_coercion_cached(self, domain):
|
|
1544
|
+
r"""
|
|
1545
|
+
Test whether the coercion from ``domain`` is already cached.
|
|
1546
|
+
|
|
1547
|
+
EXAMPLES::
|
|
1548
|
+
|
|
1549
|
+
sage: R.<XX> = QQ
|
|
1550
|
+
sage: R._remove_from_coerce_cache(QQ)
|
|
1551
|
+
sage: R._is_coercion_cached(QQ)
|
|
1552
|
+
False
|
|
1553
|
+
sage: _ = R.coerce_map_from(QQ)
|
|
1554
|
+
sage: R._is_coercion_cached(QQ)
|
|
1555
|
+
True
|
|
1556
|
+
"""
|
|
1557
|
+
return domain in self._coerce_from_hash
|
|
1558
|
+
|
|
1559
|
+
def _is_conversion_cached(self, domain):
|
|
1560
|
+
r"""
|
|
1561
|
+
Test whether the conversion from ``domain`` is already set.
|
|
1562
|
+
|
|
1563
|
+
EXAMPLES::
|
|
1564
|
+
|
|
1565
|
+
sage: P = Parent()
|
|
1566
|
+
sage: P._is_conversion_cached(P)
|
|
1567
|
+
False
|
|
1568
|
+
sage: P.convert_map_from(P)
|
|
1569
|
+
Identity endomorphism of <sage.structure.parent.Parent object at ...>
|
|
1570
|
+
sage: P._is_conversion_cached(P)
|
|
1571
|
+
True
|
|
1572
|
+
"""
|
|
1573
|
+
return domain in self._convert_from_hash
|
|
1574
|
+
|
|
1575
|
+
def _remove_from_coerce_cache(self, domain):
|
|
1576
|
+
r"""
|
|
1577
|
+
Remove the coercion and the conversion from ``domain`` to ``self`` from
|
|
1578
|
+
the cache.
|
|
1579
|
+
|
|
1580
|
+
EXAMPLES::
|
|
1581
|
+
|
|
1582
|
+
sage: R.<XX> = QQ
|
|
1583
|
+
sage: R._remove_from_coerce_cache(QQ)
|
|
1584
|
+
sage: R._is_coercion_cached(QQ)
|
|
1585
|
+
False
|
|
1586
|
+
sage: _ = R.coerce_map_from(QQ)
|
|
1587
|
+
sage: R._is_coercion_cached(QQ)
|
|
1588
|
+
True
|
|
1589
|
+
sage: R._remove_from_coerce_cache(QQ)
|
|
1590
|
+
sage: R._is_coercion_cached(QQ)
|
|
1591
|
+
False
|
|
1592
|
+
sage: R._is_conversion_cached(QQ)
|
|
1593
|
+
False
|
|
1594
|
+
"""
|
|
1595
|
+
try:
|
|
1596
|
+
del self._coerce_from_hash[domain]
|
|
1597
|
+
except KeyError:
|
|
1598
|
+
pass
|
|
1599
|
+
try:
|
|
1600
|
+
del self._convert_from_hash[domain]
|
|
1601
|
+
except KeyError:
|
|
1602
|
+
pass
|
|
1603
|
+
|
|
1604
|
+
cpdef register_coercion(self, mor):
|
|
1605
|
+
r"""
|
|
1606
|
+
Update the coercion model to use `mor : P \to \text{self}` to coerce
|
|
1607
|
+
from a parent ``P`` into ``self``.
|
|
1608
|
+
|
|
1609
|
+
For safety, an error is raised if another coercion has already
|
|
1610
|
+
been registered or discovered between ``P`` and ``self``.
|
|
1611
|
+
|
|
1612
|
+
EXAMPLES::
|
|
1613
|
+
|
|
1614
|
+
sage: K.<a> = ZZ['a']
|
|
1615
|
+
sage: L.<b> = ZZ['b']
|
|
1616
|
+
sage: L_into_K = L.hom([-a]) # non-trivial automorphism
|
|
1617
|
+
sage: K.register_coercion(L_into_K)
|
|
1618
|
+
|
|
1619
|
+
sage: K(0) + b
|
|
1620
|
+
-a
|
|
1621
|
+
sage: a + b
|
|
1622
|
+
0
|
|
1623
|
+
sage: K(b) # check that convert calls coerce first; normally this is just a
|
|
1624
|
+
-a
|
|
1625
|
+
|
|
1626
|
+
sage: L(0) + a in K # this goes through the coercion mechanism of K
|
|
1627
|
+
True
|
|
1628
|
+
sage: L(a) in L # this still goes through the convert mechanism of L
|
|
1629
|
+
True
|
|
1630
|
+
|
|
1631
|
+
sage: K.register_coercion(L_into_K)
|
|
1632
|
+
Traceback (most recent call last):
|
|
1633
|
+
...
|
|
1634
|
+
AssertionError: coercion from Univariate Polynomial Ring in b over Integer Ring to Univariate Polynomial Ring in a over Integer Ring already registered or discovered
|
|
1635
|
+
|
|
1636
|
+
TESTS:
|
|
1637
|
+
|
|
1638
|
+
We check that :issue:`29517` has been fixed::
|
|
1639
|
+
|
|
1640
|
+
sage: A.<x> = ZZ[]
|
|
1641
|
+
sage: B.<y> = ZZ[]
|
|
1642
|
+
sage: B.has_coerce_map_from(A)
|
|
1643
|
+
False
|
|
1644
|
+
sage: B.register_coercion(A.hom([y]))
|
|
1645
|
+
sage: x + y
|
|
1646
|
+
2*y
|
|
1647
|
+
"""
|
|
1648
|
+
if isinstance(mor, map.Map):
|
|
1649
|
+
if mor.codomain() is not self:
|
|
1650
|
+
raise ValueError(_LazyString("Map's codomain must be self (%s) is not (%s)", (self, mor.codomain()), {}))
|
|
1651
|
+
elif isinstance(mor, (type, Parent)):
|
|
1652
|
+
mor = self._generic_coerce_map(mor)
|
|
1653
|
+
else:
|
|
1654
|
+
raise TypeError(_LazyString("coercions must be parents or maps (got %s)", (mor,), {}))
|
|
1655
|
+
D = mor.domain()
|
|
1656
|
+
|
|
1657
|
+
assert not (self._coercions_used and D in self._coerce_from_hash and
|
|
1658
|
+
self._coerce_from_hash.get(D) is not None), "coercion from {} to {} already registered or discovered".format(D, self)
|
|
1659
|
+
assert not (self._coercions_used and D in self._convert_from_hash), "conversion from %s to %s already registered or discovered" % (D, self)
|
|
1660
|
+
|
|
1661
|
+
mor._is_coercion = True
|
|
1662
|
+
self._coerce_from_list.append(mor)
|
|
1663
|
+
self._registered_domains.append(D)
|
|
1664
|
+
self._coerce_from_hash.set(D, mor)
|
|
1665
|
+
|
|
1666
|
+
cpdef register_action(self, action):
|
|
1667
|
+
r"""
|
|
1668
|
+
Update the coercion model to use ``action`` to act on ``self``.
|
|
1669
|
+
|
|
1670
|
+
``action`` should be of type ``sage.categories.action.Action``.
|
|
1671
|
+
|
|
1672
|
+
EXAMPLES::
|
|
1673
|
+
|
|
1674
|
+
sage: import sage.categories.action
|
|
1675
|
+
sage: import operator
|
|
1676
|
+
|
|
1677
|
+
sage: class SymmetricGroupAction(sage.categories.action.Action):
|
|
1678
|
+
....: "Act on a multivariate polynomial ring by permuting the generators."
|
|
1679
|
+
....: def __init__(self, G, M, is_left=True):
|
|
1680
|
+
....: sage.categories.action.Action.__init__(self, G, M, is_left, operator.mul)
|
|
1681
|
+
....:
|
|
1682
|
+
....: def _act_(self, g, a):
|
|
1683
|
+
....: D = {}
|
|
1684
|
+
....: for k, v in a.monomial_coefficients().items():
|
|
1685
|
+
....: nk = [0]*len(k)
|
|
1686
|
+
....: for i in range(len(k)):
|
|
1687
|
+
....: nk[g(i+1)-1] = k[i]
|
|
1688
|
+
....: D[tuple(nk)] = v
|
|
1689
|
+
....: return a.parent()(D)
|
|
1690
|
+
|
|
1691
|
+
sage: # needs sage.groups
|
|
1692
|
+
sage: R.<x, y, z> = QQ['x, y, z']
|
|
1693
|
+
sage: G = SymmetricGroup(3)
|
|
1694
|
+
sage: act = SymmetricGroupAction(G, R)
|
|
1695
|
+
sage: t = x + 2*y + 3*z
|
|
1696
|
+
|
|
1697
|
+
sage: # needs sage.groups
|
|
1698
|
+
sage: act(G((1, 2)), t)
|
|
1699
|
+
2*x + y + 3*z
|
|
1700
|
+
sage: act(G((2, 3)), t)
|
|
1701
|
+
x + 3*y + 2*z
|
|
1702
|
+
sage: act(G((1, 2, 3)), t)
|
|
1703
|
+
3*x + y + 2*z
|
|
1704
|
+
|
|
1705
|
+
This should fail, since we have not registered the left
|
|
1706
|
+
action::
|
|
1707
|
+
|
|
1708
|
+
sage: G((1,2)) * t # needs sage.groups
|
|
1709
|
+
Traceback (most recent call last):
|
|
1710
|
+
...
|
|
1711
|
+
TypeError: ...
|
|
1712
|
+
|
|
1713
|
+
Now let's make it work::
|
|
1714
|
+
|
|
1715
|
+
sage: # needs sage.groups
|
|
1716
|
+
sage: R._unset_coercions_used()
|
|
1717
|
+
sage: R.register_action(act)
|
|
1718
|
+
sage: G((1, 2)) * t
|
|
1719
|
+
2*x + y + 3*z
|
|
1720
|
+
"""
|
|
1721
|
+
if self._coercions_used:
|
|
1722
|
+
raise RuntimeError("actions and coercions must be registered before use")
|
|
1723
|
+
from sage.categories.action import Action
|
|
1724
|
+
if not isinstance(action, Action):
|
|
1725
|
+
raise TypeError("actions must be actions")
|
|
1726
|
+
if action.actor() is not self and action.domain() is not self:
|
|
1727
|
+
raise ValueError("action must involve self")
|
|
1728
|
+
self._action_list.append(action)
|
|
1729
|
+
|
|
1730
|
+
cpdef register_conversion(self, mor):
|
|
1731
|
+
r"""
|
|
1732
|
+
Update the coercion model to use `\text{mor} : P \to \text{self}` to convert
|
|
1733
|
+
from ``P`` into ``self``.
|
|
1734
|
+
|
|
1735
|
+
EXAMPLES::
|
|
1736
|
+
|
|
1737
|
+
sage: K.<a> = ZZ['a']
|
|
1738
|
+
sage: M.<c> = ZZ['c']
|
|
1739
|
+
sage: M_into_K = M.hom([a]) # trivial automorphism
|
|
1740
|
+
sage: K._unset_coercions_used()
|
|
1741
|
+
sage: K.register_conversion(M_into_K)
|
|
1742
|
+
|
|
1743
|
+
sage: K(c)
|
|
1744
|
+
a
|
|
1745
|
+
sage: K(0) + c
|
|
1746
|
+
Traceback (most recent call last):
|
|
1747
|
+
...
|
|
1748
|
+
TypeError: ...
|
|
1749
|
+
"""
|
|
1750
|
+
assert not (self._coercions_used and mor.domain() in self._convert_from_hash), "conversion from %s to %s already registered or discovered" % (mor.domain(), self)
|
|
1751
|
+
if isinstance(mor, map.Map):
|
|
1752
|
+
if mor.codomain() is not self:
|
|
1753
|
+
raise ValueError("Map's codomain must be self")
|
|
1754
|
+
self._convert_from_list.append(mor)
|
|
1755
|
+
self._convert_from_hash.set(mor.domain(), mor)
|
|
1756
|
+
elif isinstance(mor, (Parent, type)):
|
|
1757
|
+
t = mor
|
|
1758
|
+
mor = self._generic_convert_map(mor)
|
|
1759
|
+
self._convert_from_list.append(mor)
|
|
1760
|
+
self._convert_from_hash.set(t, mor)
|
|
1761
|
+
self._convert_from_hash.set(mor.domain(), mor)
|
|
1762
|
+
else:
|
|
1763
|
+
raise TypeError("conversions must be parents or maps")
|
|
1764
|
+
|
|
1765
|
+
cpdef register_embedding(self, embedding):
|
|
1766
|
+
r"""
|
|
1767
|
+
Add embedding to coercion model.
|
|
1768
|
+
|
|
1769
|
+
This method updates the coercion model to use
|
|
1770
|
+
`\text{embedding} : \text{self} \to P` to embed ``self`` into
|
|
1771
|
+
the parent ``P``.
|
|
1772
|
+
|
|
1773
|
+
There can only be one embedding registered; it can only be registered
|
|
1774
|
+
once; and it must be registered before using this parent in the
|
|
1775
|
+
coercion model.
|
|
1776
|
+
|
|
1777
|
+
EXAMPLES::
|
|
1778
|
+
|
|
1779
|
+
sage: S3 = AlternatingGroup(3) # needs sage.groups
|
|
1780
|
+
sage: G = SL(3, QQ) # needs sage.groups sage.modules
|
|
1781
|
+
sage: p = S3[2]; p.matrix() # needs sage.groups sage.modules
|
|
1782
|
+
[0 0 1]
|
|
1783
|
+
[1 0 0]
|
|
1784
|
+
[0 1 0]
|
|
1785
|
+
|
|
1786
|
+
In general one cannot mix matrices and permutations::
|
|
1787
|
+
|
|
1788
|
+
sage: # needs sage.groups sage.modules
|
|
1789
|
+
sage: G(p)
|
|
1790
|
+
Traceback (most recent call last):
|
|
1791
|
+
...
|
|
1792
|
+
TypeError: unable to convert (1,3,2) to a rational
|
|
1793
|
+
sage: phi = S3.hom(lambda p: G(p.matrix()), codomain=G)
|
|
1794
|
+
sage: phi(p)
|
|
1795
|
+
[0 0 1]
|
|
1796
|
+
[1 0 0]
|
|
1797
|
+
[0 1 0]
|
|
1798
|
+
sage: S3._unset_coercions_used()
|
|
1799
|
+
sage: S3.register_embedding(phi)
|
|
1800
|
+
|
|
1801
|
+
By :issue:`14711`, coerce maps should be copied when using outside of
|
|
1802
|
+
the coercion system::
|
|
1803
|
+
|
|
1804
|
+
sage: phi = copy(S3.coerce_embedding()); phi # needs sage.groups sage.modules
|
|
1805
|
+
Generic morphism:
|
|
1806
|
+
From: Alternating group of order 3!/2 as a permutation group
|
|
1807
|
+
To: Special Linear Group of degree 3 over Rational Field
|
|
1808
|
+
sage: phi(p) # needs sage.groups sage.modules
|
|
1809
|
+
[0 0 1]
|
|
1810
|
+
[1 0 0]
|
|
1811
|
+
[0 1 0]
|
|
1812
|
+
|
|
1813
|
+
This does not work since matrix groups are still old-style
|
|
1814
|
+
parents (see :issue:`14014`)::
|
|
1815
|
+
|
|
1816
|
+
sage: G(p) # not implemented # needs sage.groups
|
|
1817
|
+
|
|
1818
|
+
Though one can have a permutation act on the rows of a matrix::
|
|
1819
|
+
|
|
1820
|
+
sage: G(1) * p # needs sage.groups sage.modules
|
|
1821
|
+
[0 0 1]
|
|
1822
|
+
[1 0 0]
|
|
1823
|
+
[0 1 0]
|
|
1824
|
+
|
|
1825
|
+
Some more advanced examples::
|
|
1826
|
+
|
|
1827
|
+
sage: # needs sage.rings.number_field
|
|
1828
|
+
sage: x = QQ['x'].0
|
|
1829
|
+
sage: t = abs(ZZ.random_element(10^6))
|
|
1830
|
+
sage: K = NumberField(x^2 + 2*3*7*11, "a"+str(t))
|
|
1831
|
+
sage: a = K.gen()
|
|
1832
|
+
sage: K_into_MS = K.hom([a.matrix()])
|
|
1833
|
+
sage: K._unset_coercions_used()
|
|
1834
|
+
sage: K.register_embedding(K_into_MS)
|
|
1835
|
+
|
|
1836
|
+
sage: # needs sage.rings.number_field
|
|
1837
|
+
sage: L = NumberField(x^2 + 2*3*7*11*19*31,
|
|
1838
|
+
....: "b" + str(abs(ZZ.random_element(10^6))))
|
|
1839
|
+
sage: b = L.gen()
|
|
1840
|
+
sage: L_into_MS = L.hom([b.matrix()])
|
|
1841
|
+
sage: L._unset_coercions_used()
|
|
1842
|
+
sage: L.register_embedding(L_into_MS)
|
|
1843
|
+
|
|
1844
|
+
sage: K.coerce_embedding()(a) # needs sage.rings.number_field
|
|
1845
|
+
[ 0 1]
|
|
1846
|
+
[-462 0]
|
|
1847
|
+
sage: L.coerce_embedding()(b) # needs sage.rings.number_field
|
|
1848
|
+
[ 0 1]
|
|
1849
|
+
[-272118 0]
|
|
1850
|
+
|
|
1851
|
+
sage: a.matrix() * b.matrix() # needs sage.rings.number_field
|
|
1852
|
+
[-272118 0]
|
|
1853
|
+
[ 0 -462]
|
|
1854
|
+
sage: a.matrix() * b.matrix() # needs sage.rings.number_field
|
|
1855
|
+
[-272118 0]
|
|
1856
|
+
[ 0 -462]
|
|
1857
|
+
"""
|
|
1858
|
+
assert not self._coercions_used, "coercions must all be registered up before use"
|
|
1859
|
+
assert self._embedding is None, "only one embedding allowed"
|
|
1860
|
+
|
|
1861
|
+
if isinstance(embedding, map.Map):
|
|
1862
|
+
if embedding.domain() is not self:
|
|
1863
|
+
raise ValueError("embedding's domain must be self")
|
|
1864
|
+
self._embedding = embedding
|
|
1865
|
+
elif isinstance(embedding, Parent):
|
|
1866
|
+
self._embedding = embedding._generic_coerce_map(self)
|
|
1867
|
+
elif embedding is not None:
|
|
1868
|
+
raise TypeError("embedding must be a parent or map")
|
|
1869
|
+
self._embedding._make_weak_references()
|
|
1870
|
+
|
|
1871
|
+
def coerce_embedding(self):
|
|
1872
|
+
"""
|
|
1873
|
+
Return the embedding of ``self`` into some other parent, if such a
|
|
1874
|
+
parent exists.
|
|
1875
|
+
|
|
1876
|
+
This does not mean that there are no coercion maps from ``self`` into
|
|
1877
|
+
other fields, this is simply a specific morphism specified out of
|
|
1878
|
+
``self`` and usually denotes a special relationship (e.g. sub-objects,
|
|
1879
|
+
choice of completion, etc.)
|
|
1880
|
+
|
|
1881
|
+
EXAMPLES::
|
|
1882
|
+
|
|
1883
|
+
sage: # needs sage.rings.number_field
|
|
1884
|
+
sage: x = polygen(ZZ, 'x')
|
|
1885
|
+
sage: K.<a> = NumberField(x^3 + x^2 + 1, embedding=1)
|
|
1886
|
+
sage: K.coerce_embedding()
|
|
1887
|
+
Generic morphism:
|
|
1888
|
+
From: Number Field in a with defining polynomial x^3 + x^2 + 1
|
|
1889
|
+
with a = -1.465571231876768?
|
|
1890
|
+
To: Real Lazy Field
|
|
1891
|
+
Defn: a -> -1.465571231876768?
|
|
1892
|
+
sage: K.<a> = NumberField(x^3 + x^2 + 1, embedding=CC.gen())
|
|
1893
|
+
sage: K.coerce_embedding()
|
|
1894
|
+
Generic morphism:
|
|
1895
|
+
From: Number Field in a with defining polynomial x^3 + x^2 + 1
|
|
1896
|
+
with a = 0.2327856159383841? + 0.7925519925154479?*I
|
|
1897
|
+
To: Complex Lazy Field
|
|
1898
|
+
Defn: a -> 0.2327856159383841? + 0.7925519925154479?*I
|
|
1899
|
+
"""
|
|
1900
|
+
return copy(self._embedding) # It might be overkill to make a copy here
|
|
1901
|
+
|
|
1902
|
+
cpdef _generic_coerce_map(self, S):
|
|
1903
|
+
r"""
|
|
1904
|
+
Return a default coercion map based on the data provided to
|
|
1905
|
+
:meth:`_populate_coercion_lists_`.
|
|
1906
|
+
|
|
1907
|
+
This method differs from :meth:`_generic_convert_map` only in setting
|
|
1908
|
+
the category for the map to the meet of the category of this parent
|
|
1909
|
+
and ``S``.
|
|
1910
|
+
|
|
1911
|
+
EXAMPLES::
|
|
1912
|
+
|
|
1913
|
+
sage: QQ['x']._generic_coerce_map(ZZ)
|
|
1914
|
+
Conversion map:
|
|
1915
|
+
From: Integer Ring
|
|
1916
|
+
To: Univariate Polynomial Ring in x over Rational Field
|
|
1917
|
+
|
|
1918
|
+
TESTS:
|
|
1919
|
+
|
|
1920
|
+
We check that :issue:`23184` has been resolved::
|
|
1921
|
+
|
|
1922
|
+
sage: QQ['x', 'y']._generic_coerce_map(QQ).category_for()
|
|
1923
|
+
Category of infinite unique factorization domains
|
|
1924
|
+
sage: QQ[['x']].coerce_map_from(QQ).category_for()
|
|
1925
|
+
Category of euclidean domains
|
|
1926
|
+
"""
|
|
1927
|
+
if isinstance(S, type):
|
|
1928
|
+
category = None
|
|
1929
|
+
else:
|
|
1930
|
+
category = self.category()._meet_(S.category())
|
|
1931
|
+
return self._generic_convert_map(S, category=category)
|
|
1932
|
+
|
|
1933
|
+
cpdef _generic_convert_map(self, S, category=None):
|
|
1934
|
+
r"""
|
|
1935
|
+
Return the default conversion map based on the data provided to
|
|
1936
|
+
:meth:`_populate_coercion_lists_`.
|
|
1937
|
+
|
|
1938
|
+
This is called when :meth:`_coerce_map_from_` returns ``True``.
|
|
1939
|
+
|
|
1940
|
+
If a ``convert_method_name`` is provided, it creates a
|
|
1941
|
+
``NamedConvertMap``, otherwise it creates a
|
|
1942
|
+
``DefaultConvertMap`` or ``DefaultConvertMap_unique``
|
|
1943
|
+
depending on whether or not init_no_parent is set.
|
|
1944
|
+
|
|
1945
|
+
EXAMPLES::
|
|
1946
|
+
|
|
1947
|
+
sage: QQ['x']._generic_convert_map(SR) # needs sage.symbolic
|
|
1948
|
+
Conversion via _polynomial_ method map:
|
|
1949
|
+
From: Symbolic Ring
|
|
1950
|
+
To: Univariate Polynomial Ring in x over Rational Field
|
|
1951
|
+
sage: GF(11)._generic_convert_map(GF(7))
|
|
1952
|
+
Conversion map:
|
|
1953
|
+
From: Finite Field of size 7
|
|
1954
|
+
To: Finite Field of size 11
|
|
1955
|
+
sage: ZZ._generic_convert_map(RDF)
|
|
1956
|
+
Conversion via _integer_ method map:
|
|
1957
|
+
From: Real Double Field
|
|
1958
|
+
To: Integer Ring
|
|
1959
|
+
|
|
1960
|
+
TESTS:
|
|
1961
|
+
|
|
1962
|
+
We check that :issue:`23184` has been resolved::
|
|
1963
|
+
|
|
1964
|
+
sage: QQ[['x']].coerce_map_from(QQ).category_for()
|
|
1965
|
+
Category of euclidean domains
|
|
1966
|
+
"""
|
|
1967
|
+
m = self._convert_method_name
|
|
1968
|
+
if m is not None:
|
|
1969
|
+
f = self.convert_method_map(S, m)
|
|
1970
|
+
if f is not None:
|
|
1971
|
+
return f
|
|
1972
|
+
if self._element_init_pass_parent:
|
|
1973
|
+
# deprecation(26879)
|
|
1974
|
+
return DefaultConvertMap(S, self, category=category)
|
|
1975
|
+
else:
|
|
1976
|
+
return DefaultConvertMap_unique(S, self, category=category)
|
|
1977
|
+
|
|
1978
|
+
def _convert_method_map(self, S, method_name=None):
|
|
1979
|
+
"""
|
|
1980
|
+
Return a map to convert from ``S`` to ``self`` using a convert
|
|
1981
|
+
method like ``_integer_`` on elements of ``S``.
|
|
1982
|
+
|
|
1983
|
+
OUTPUT: either an instance of :class:`NamedConvertMap` or
|
|
1984
|
+
``None`` if ``S`` does not have the method.
|
|
1985
|
+
"""
|
|
1986
|
+
# NOTE: in Cython code, call convert_method_map() directly
|
|
1987
|
+
if method_name is None:
|
|
1988
|
+
method_name = self._convert_method_name
|
|
1989
|
+
return self.convert_method_map(S, method_name)
|
|
1990
|
+
|
|
1991
|
+
cdef convert_method_map(self, S, method_name):
|
|
1992
|
+
# Cython implementation of _convert_method_map()
|
|
1993
|
+
cdef Parent P
|
|
1994
|
+
if isinstance(S, Parent):
|
|
1995
|
+
P = <Parent>S
|
|
1996
|
+
try:
|
|
1997
|
+
element_cls = P.Element
|
|
1998
|
+
except AttributeError:
|
|
1999
|
+
element_cls = type(P.an_element())
|
|
2000
|
+
else:
|
|
2001
|
+
element_cls = S
|
|
2002
|
+
if hasattr(element_cls, method_name):
|
|
2003
|
+
return NamedConvertMap(S, self, method_name)
|
|
2004
|
+
else:
|
|
2005
|
+
return None
|
|
2006
|
+
|
|
2007
|
+
def _coerce_map_via(self, v, S):
|
|
2008
|
+
"""
|
|
2009
|
+
This attempts to construct a morphism from ``S`` to ``self`` by passing
|
|
2010
|
+
through one of the items in ``v`` (tried in order).
|
|
2011
|
+
|
|
2012
|
+
``S`` may appear in the list, in which case algorithm will never
|
|
2013
|
+
progress beyond that point.
|
|
2014
|
+
|
|
2015
|
+
This is useful when defining ``_coerce_map_from_``.
|
|
2016
|
+
|
|
2017
|
+
INPUT:
|
|
2018
|
+
|
|
2019
|
+
- ``v`` -- list (iterator) of parents with coercions into ``self``;
|
|
2020
|
+
there *must* be maps provided from each item in the list to ``self``
|
|
2021
|
+
|
|
2022
|
+
- ``S`` -- the starting parent
|
|
2023
|
+
|
|
2024
|
+
EXAMPLES:
|
|
2025
|
+
|
|
2026
|
+
By :issue:`14711`, coerce maps should be copied for usage outside
|
|
2027
|
+
of the coercion system::
|
|
2028
|
+
|
|
2029
|
+
sage: copy(CDF._coerce_map_via([ZZ, RR, CC], int)) # needs sage.rings.complex_double
|
|
2030
|
+
Composite map:
|
|
2031
|
+
From: Set of Python objects of class 'int'
|
|
2032
|
+
To: Complex Double Field
|
|
2033
|
+
Defn: Native morphism:
|
|
2034
|
+
From: Set of Python objects of class 'int'
|
|
2035
|
+
To: Integer Ring
|
|
2036
|
+
then
|
|
2037
|
+
Native morphism:
|
|
2038
|
+
From: Integer Ring
|
|
2039
|
+
To: Complex Double Field
|
|
2040
|
+
|
|
2041
|
+
sage: copy(CDF._coerce_map_via([ZZ, RR, CC], QQ)) # needs sage.rings.complex_double
|
|
2042
|
+
Composite map:
|
|
2043
|
+
From: Rational Field
|
|
2044
|
+
To: Complex Double Field
|
|
2045
|
+
Defn: Generic map:
|
|
2046
|
+
From: Rational Field
|
|
2047
|
+
To: Real Field with 53 bits of precision
|
|
2048
|
+
then
|
|
2049
|
+
Native morphism:
|
|
2050
|
+
From: Real Field with 53 bits of precision
|
|
2051
|
+
To: Complex Double Field
|
|
2052
|
+
|
|
2053
|
+
sage: copy(CDF._coerce_map_via([ZZ, RR, CC], CC)) # needs sage.rings.complex_double
|
|
2054
|
+
Generic map:
|
|
2055
|
+
From: Complex Field with 53 bits of precision
|
|
2056
|
+
To: Complex Double Field
|
|
2057
|
+
"""
|
|
2058
|
+
cdef Parent R
|
|
2059
|
+
for R in v:
|
|
2060
|
+
if R is None:
|
|
2061
|
+
continue
|
|
2062
|
+
if R is S:
|
|
2063
|
+
return self._internal_coerce_map_from(R)
|
|
2064
|
+
connecting = R._internal_coerce_map_from(S)
|
|
2065
|
+
if connecting is not None:
|
|
2066
|
+
return self._internal_coerce_map_from(R) * connecting
|
|
2067
|
+
|
|
2068
|
+
cpdef bint has_coerce_map_from(self, S) except -2:
|
|
2069
|
+
"""
|
|
2070
|
+
Return ``True`` if there is a natural map from ``S`` to ``self``.
|
|
2071
|
+
Otherwise, return ``False``.
|
|
2072
|
+
|
|
2073
|
+
EXAMPLES::
|
|
2074
|
+
|
|
2075
|
+
sage: RDF.has_coerce_map_from(QQ)
|
|
2076
|
+
True
|
|
2077
|
+
sage: RDF.has_coerce_map_from(QQ['x'])
|
|
2078
|
+
False
|
|
2079
|
+
sage: RDF['x'].has_coerce_map_from(QQ['x'])
|
|
2080
|
+
True
|
|
2081
|
+
sage: RDF['x,y'].has_coerce_map_from(QQ['x'])
|
|
2082
|
+
True
|
|
2083
|
+
"""
|
|
2084
|
+
if S is self:
|
|
2085
|
+
return True
|
|
2086
|
+
elif S == self:
|
|
2087
|
+
if debug.unique_parent_warnings:
|
|
2088
|
+
print("Warning: non-unique parents %s" % (type(S)))
|
|
2089
|
+
return True
|
|
2090
|
+
return self._internal_coerce_map_from(S) is not None
|
|
2091
|
+
|
|
2092
|
+
cpdef _coerce_map_from_(self, S):
|
|
2093
|
+
"""
|
|
2094
|
+
Override this method to specify coercions beyond those specified
|
|
2095
|
+
in ``coerce_list``.
|
|
2096
|
+
|
|
2097
|
+
If no such coercion exists, return ``None`` or ``False``. Otherwise, it
|
|
2098
|
+
may return either an actual Map to use for the coercion, a callable
|
|
2099
|
+
(in which case it will be wrapped in a Map), or ``True`` (in which case
|
|
2100
|
+
a generic map will be provided).
|
|
2101
|
+
"""
|
|
2102
|
+
try:
|
|
2103
|
+
# Try possible _coerce_map_from_() methods defined in
|
|
2104
|
+
# ParentMethods classes of categories.
|
|
2105
|
+
return super(Parent, self)._coerce_map_from_(S)
|
|
2106
|
+
except AttributeError:
|
|
2107
|
+
return None
|
|
2108
|
+
|
|
2109
|
+
cpdef coerce_map_from(self, S):
|
|
2110
|
+
"""
|
|
2111
|
+
Return a :class:`Map` object to coerce from ``S`` to ``self`` if one
|
|
2112
|
+
exists, or ``None`` if no such coercion exists.
|
|
2113
|
+
|
|
2114
|
+
EXAMPLES:
|
|
2115
|
+
|
|
2116
|
+
By :issue:`12313`, a special kind of weak key dictionary is used to
|
|
2117
|
+
store coercion and conversion maps, namely
|
|
2118
|
+
:class:`~sage.structure.coerce_dict.MonoDict`. In that way, a memory
|
|
2119
|
+
leak was fixed that would occur in the following test::
|
|
2120
|
+
|
|
2121
|
+
sage: import gc
|
|
2122
|
+
sage: _ = gc.collect()
|
|
2123
|
+
sage: K = GF(1<<55,'t') # needs sage.rings.finite_rings
|
|
2124
|
+
sage: for i in range(50): # needs sage.rings.finite_rings sage.schemes
|
|
2125
|
+
....: a = K.random_element()
|
|
2126
|
+
....: E = EllipticCurve(j=a)
|
|
2127
|
+
....: b = K.has_coerce_map_from(E)
|
|
2128
|
+
sage: _ = gc.collect()
|
|
2129
|
+
sage: len([x for x in gc.get_objects() if isinstance(x, type(E))]) # needs sage.rings.finite_rings sage.schemes
|
|
2130
|
+
1
|
|
2131
|
+
|
|
2132
|
+
TESTS:
|
|
2133
|
+
|
|
2134
|
+
The following was fixed in :issue:`12969`::
|
|
2135
|
+
|
|
2136
|
+
sage: # needs sage.combinat sage.modules
|
|
2137
|
+
sage: R = QQ['q,t'].fraction_field()
|
|
2138
|
+
sage: Sym = SymmetricFunctions(R)
|
|
2139
|
+
sage: H = Sym.macdonald().H()
|
|
2140
|
+
sage: P = Sym.macdonald().P()
|
|
2141
|
+
sage: m = Sym.monomial()
|
|
2142
|
+
sage: Ht = Sym.macdonald().Ht()
|
|
2143
|
+
sage: phi = m.coerce_map_from(P)
|
|
2144
|
+
"""
|
|
2145
|
+
return copy(self._internal_coerce_map_from(S))
|
|
2146
|
+
|
|
2147
|
+
cpdef _internal_coerce_map_from(self, S):
|
|
2148
|
+
"""
|
|
2149
|
+
Return the :class:`Map` object to coerce from ``S`` to ``self`` that
|
|
2150
|
+
is used internally by the coercion system if one exists, or ``None``
|
|
2151
|
+
if no such coercion exists.
|
|
2152
|
+
|
|
2153
|
+
EXAMPLES:
|
|
2154
|
+
|
|
2155
|
+
By :issue:`14711`, coerce maps should be copied when using them
|
|
2156
|
+
outside of the coercion system, because they may become defunct
|
|
2157
|
+
by garbage collection::
|
|
2158
|
+
|
|
2159
|
+
sage: ZZ._internal_coerce_map_from(int)
|
|
2160
|
+
(map internal to coercion system -- copy before use)
|
|
2161
|
+
Native morphism:
|
|
2162
|
+
From: Set of Python objects of class 'int'
|
|
2163
|
+
To: Integer Ring
|
|
2164
|
+
sage: copy(ZZ._internal_coerce_map_from(int))
|
|
2165
|
+
Native morphism:
|
|
2166
|
+
From: Set of Python objects of class 'int'
|
|
2167
|
+
To: Integer Ring
|
|
2168
|
+
sage: copy(QQ._internal_coerce_map_from(ZZ))
|
|
2169
|
+
Natural morphism:
|
|
2170
|
+
From: Integer Ring
|
|
2171
|
+
To: Rational Field
|
|
2172
|
+
|
|
2173
|
+
sage: # needs sage.combinat sage.modules
|
|
2174
|
+
sage: R = QQ['q,t'].fraction_field()
|
|
2175
|
+
sage: Sym = SymmetricFunctions(R)
|
|
2176
|
+
sage: P = Sym.macdonald().P()
|
|
2177
|
+
sage: Ht = Sym.macdonald().Ht()
|
|
2178
|
+
sage: Ht._internal_coerce_map_from(P)
|
|
2179
|
+
(map internal to coercion system -- copy before use)
|
|
2180
|
+
Composite map:
|
|
2181
|
+
From: Symmetric Functions over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field in the Macdonald P basis
|
|
2182
|
+
To: Symmetric Functions over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field in the Macdonald Ht basis
|
|
2183
|
+
sage: copy(Ht._internal_coerce_map_from(P))
|
|
2184
|
+
Composite map:
|
|
2185
|
+
From: Symmetric Functions over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field in the Macdonald P basis
|
|
2186
|
+
To: Symmetric Functions over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field in the Macdonald Ht basis
|
|
2187
|
+
Defn: Generic morphism:
|
|
2188
|
+
From: Symmetric Functions over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field in the Macdonald P basis
|
|
2189
|
+
To: Symmetric Functions over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field in the Macdonald J basis
|
|
2190
|
+
then
|
|
2191
|
+
Generic morphism:
|
|
2192
|
+
From: Symmetric Functions over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field in the Macdonald J basis
|
|
2193
|
+
To: Symmetric Functions over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field in the Schur basis
|
|
2194
|
+
then
|
|
2195
|
+
Generic morphism:
|
|
2196
|
+
From: Symmetric Functions over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field in the Schur basis
|
|
2197
|
+
To: Symmetric Functions over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field in the Macdonald Ht basis
|
|
2198
|
+
|
|
2199
|
+
The following was fixed in :issue:`4740`::
|
|
2200
|
+
|
|
2201
|
+
sage: F = GF(13)
|
|
2202
|
+
sage: F._internal_coerce_map_from(F) is F._internal_coerce_map_from(F)
|
|
2203
|
+
True
|
|
2204
|
+
"""
|
|
2205
|
+
if not good_as_coerce_domain(S):
|
|
2206
|
+
return None
|
|
2207
|
+
self._coercions_used = True
|
|
2208
|
+
cdef map.Map mor
|
|
2209
|
+
|
|
2210
|
+
if isinstance(S, Set_PythonType_class):
|
|
2211
|
+
return self._internal_coerce_map_from(S._type)
|
|
2212
|
+
if self._coerce_from_hash is None: # this is because parent.__init__() does not always get called
|
|
2213
|
+
self.init_coerce(False)
|
|
2214
|
+
|
|
2215
|
+
try:
|
|
2216
|
+
return self._coerce_from_hash.get(S)
|
|
2217
|
+
except KeyError:
|
|
2218
|
+
pass
|
|
2219
|
+
|
|
2220
|
+
if S is self:
|
|
2221
|
+
from sage.categories.homset import Hom
|
|
2222
|
+
mor = Hom(self, self).identity()
|
|
2223
|
+
mor._is_coercion = True
|
|
2224
|
+
self._coerce_from_hash.set(S, mor)
|
|
2225
|
+
return mor
|
|
2226
|
+
|
|
2227
|
+
if S == self:
|
|
2228
|
+
# non-unique parents
|
|
2229
|
+
if debug.unique_parent_warnings:
|
|
2230
|
+
print("Warning: non-unique parents %s" % (type(S)))
|
|
2231
|
+
mor = self._generic_coerce_map(S)
|
|
2232
|
+
mor._is_coercion = True
|
|
2233
|
+
self._coerce_from_hash.set(S, mor)
|
|
2234
|
+
mor._make_weak_references()
|
|
2235
|
+
return mor
|
|
2236
|
+
|
|
2237
|
+
try:
|
|
2238
|
+
_register_pair(self, S, "coerce")
|
|
2239
|
+
mor = self.discover_coerce_map_from(S)
|
|
2240
|
+
# if mor is not None:
|
|
2241
|
+
# # Need to check that this morphism does not connect previously unconnected parts of the coercion diagram
|
|
2242
|
+
# if self._embedding is not None and not self._embedding.codomain().has_coerce_map_from(S):
|
|
2243
|
+
# # The following if statement may call this function with self and S. If so, we want to return None,
|
|
2244
|
+
# # so that it does not use this path for the existence of a coercion path.
|
|
2245
|
+
# # We disable this for now because it is too strict
|
|
2246
|
+
# pass
|
|
2247
|
+
# # mor = None
|
|
2248
|
+
# if mor is not None:
|
|
2249
|
+
# # NOTE: this line is what makes the coercion detection stateful
|
|
2250
|
+
# # self._coerce_from_list.append(mor)
|
|
2251
|
+
# pass
|
|
2252
|
+
# It may be that the only coercion from S to self is
|
|
2253
|
+
# via another parent X. But if the pair (S,X) is temporarily
|
|
2254
|
+
# disregarded (using _register_pair, to avoid infinite recursion)
|
|
2255
|
+
# then we are not allowed to cache the absence of a coercion
|
|
2256
|
+
# from S to self. See #12969
|
|
2257
|
+
if (mor is not None) or _may_cache_none(self, S, "coerce"):
|
|
2258
|
+
self._coerce_from_hash.set(S, mor)
|
|
2259
|
+
if mor is not None:
|
|
2260
|
+
mor._is_coercion = True
|
|
2261
|
+
mor._make_weak_references()
|
|
2262
|
+
return mor
|
|
2263
|
+
except CoercionException as ex:
|
|
2264
|
+
_record_exception()
|
|
2265
|
+
return None
|
|
2266
|
+
finally:
|
|
2267
|
+
_unregister_pair(self, S, "coerce")
|
|
2268
|
+
|
|
2269
|
+
cdef discover_coerce_map_from(self, S):
|
|
2270
|
+
"""
|
|
2271
|
+
Precedence for discovering a coercion ``S -> self`` goes as follows:
|
|
2272
|
+
|
|
2273
|
+
1. If ``S`` has an embedding into ``self``, return that embedding.
|
|
2274
|
+
|
|
2275
|
+
2. If ``self._coerce_map_from_(S)`` is not exactly one of
|
|
2276
|
+
|
|
2277
|
+
- DefaultConvertMap
|
|
2278
|
+
- DefaultConvertMap_unique
|
|
2279
|
+
- NamedConvertMap
|
|
2280
|
+
|
|
2281
|
+
return this map.
|
|
2282
|
+
|
|
2283
|
+
3. Traverse the coercion lists looking for another map
|
|
2284
|
+
returning the map from step (2) if none is found.
|
|
2285
|
+
|
|
2286
|
+
4. If ``S`` has an embedding into some parent ``T``, look for
|
|
2287
|
+
``T -> self`` and return composition.
|
|
2288
|
+
|
|
2289
|
+
In the future, multiple paths may be discovered and compared.
|
|
2290
|
+
|
|
2291
|
+
TESTS:
|
|
2292
|
+
|
|
2293
|
+
Regression test for :issue:`12919` (probably not 100% robust)::
|
|
2294
|
+
|
|
2295
|
+
sage: class P(Parent):
|
|
2296
|
+
....: def __init__(self):
|
|
2297
|
+
....: Parent.__init__(self, category=Sets())
|
|
2298
|
+
....: Element=ElementWrapper
|
|
2299
|
+
sage: A = P(); a = A('a')
|
|
2300
|
+
sage: B = P(); b = B('b')
|
|
2301
|
+
sage: C = P(); c = C('c')
|
|
2302
|
+
sage: D = P(); d = D('d')
|
|
2303
|
+
sage: Hom(A, B)(lambda x: b).register_as_coercion()
|
|
2304
|
+
sage: Hom(B, A)(lambda x: a).register_as_coercion()
|
|
2305
|
+
sage: Hom(C, B)(lambda x: b).register_as_coercion()
|
|
2306
|
+
sage: Hom(D, C)(lambda x: c).register_as_coercion()
|
|
2307
|
+
sage: A(d)
|
|
2308
|
+
'a'
|
|
2309
|
+
|
|
2310
|
+
Another test::
|
|
2311
|
+
|
|
2312
|
+
sage: # needs sage.rings.number_field
|
|
2313
|
+
sage: x = polygen(ZZ, 'x')
|
|
2314
|
+
sage: K = NumberField([x^2 - 2, x^2 - 3], 'a,b')
|
|
2315
|
+
sage: M = K.absolute_field('c')
|
|
2316
|
+
sage: M_to_K, K_to_M = M.structure()
|
|
2317
|
+
sage: M.register_coercion(K_to_M)
|
|
2318
|
+
sage: K.register_coercion(M_to_K)
|
|
2319
|
+
sage: phi = M.coerce_map_from(QQ)
|
|
2320
|
+
sage: p = QQ.random_element()
|
|
2321
|
+
sage: c = phi(p) - p; c
|
|
2322
|
+
0
|
|
2323
|
+
sage: c.parent() is M
|
|
2324
|
+
True
|
|
2325
|
+
sage: K.coerce_map_from(QQ)
|
|
2326
|
+
Coercion map:
|
|
2327
|
+
From: Rational Field
|
|
2328
|
+
To: Number Field in a with defining polynomial x^2 - 2 over its base field
|
|
2329
|
+
|
|
2330
|
+
Test that :issue:`17981` is fixed::
|
|
2331
|
+
|
|
2332
|
+
sage: class P(Parent):
|
|
2333
|
+
....: def __init__(self):
|
|
2334
|
+
....: Parent.__init__(self, category=Sets())
|
|
2335
|
+
....: def _coerce_map_from_(self, A):
|
|
2336
|
+
....: if A == ZZ:
|
|
2337
|
+
....: return lambda x: self.element_class(self, x)
|
|
2338
|
+
....: return False
|
|
2339
|
+
....: Element=ElementWrapper
|
|
2340
|
+
sage: X = P()
|
|
2341
|
+
sage: X.has_coerce_map_from(ZZ)
|
|
2342
|
+
True
|
|
2343
|
+
|
|
2344
|
+
Check that :issue:`14982` is fixed, and more generally that we discover
|
|
2345
|
+
sensible coercion paths in the presence of embeddings::
|
|
2346
|
+
|
|
2347
|
+
sage: # needs sage.rings.number_field
|
|
2348
|
+
sage: K.<a> = NumberField(x^2 + 1/2, embedding=CC(0, 1))
|
|
2349
|
+
sage: L = NumberField(x^2 + 2, 'b', embedding=1/a)
|
|
2350
|
+
sage: PolynomialRing(L, 'x').coerce_map_from(L)
|
|
2351
|
+
Polynomial base injection morphism:
|
|
2352
|
+
From: Number Field in b with defining polynomial x^2 + 2 with b = -2*a
|
|
2353
|
+
To: Univariate Polynomial Ring in x over Number Field in b
|
|
2354
|
+
with defining polynomial x^2 + 2 with b = -2*a
|
|
2355
|
+
sage: PolynomialRing(K, 'x').coerce_map_from(L)
|
|
2356
|
+
Composite map:
|
|
2357
|
+
From: Number Field in b with defining polynomial x^2 + 2 with b = -2*a
|
|
2358
|
+
To: Univariate Polynomial Ring in x over Number Field in a
|
|
2359
|
+
with defining polynomial x^2 + 1/2 with a = 0.7071067811865475?*I
|
|
2360
|
+
Defn: Generic morphism:
|
|
2361
|
+
From: Number Field in b with defining polynomial x^2 + 2 with b = -2*a
|
|
2362
|
+
To: Number Field in a with defining polynomial x^2 + 1/2 with a = 0.7071067811865475?*I
|
|
2363
|
+
Defn: b -> -2*a
|
|
2364
|
+
then
|
|
2365
|
+
Polynomial base injection morphism:
|
|
2366
|
+
From: Number Field in a with defining polynomial x^2 + 1/2 with a = 0.7071067811865475?*I
|
|
2367
|
+
To: Univariate Polynomial Ring in x over Number Field in a
|
|
2368
|
+
with defining polynomial x^2 + 1/2 with a = 0.7071067811865475?*I
|
|
2369
|
+
sage: MatrixSpace(L, 2, 2).coerce_map_from(L)
|
|
2370
|
+
Coercion map:
|
|
2371
|
+
From: Number Field in b with defining polynomial x^2 + 2 with b = -2*a
|
|
2372
|
+
To: Full MatrixSpace of 2 by 2 dense matrices over Number Field in b
|
|
2373
|
+
with defining polynomial x^2 + 2 with b = -2*a
|
|
2374
|
+
sage: PowerSeriesRing(L, 'x').coerce_map_from(L)
|
|
2375
|
+
Coercion map:
|
|
2376
|
+
From: Number Field in b with defining polynomial x^2 + 2 with b = -2*a
|
|
2377
|
+
To: Power Series Ring in x over Number Field in b
|
|
2378
|
+
with defining polynomial x^2 + 2 with b = -2*a
|
|
2379
|
+
"""
|
|
2380
|
+
if isinstance(S, Parent) and (<Parent>S)._embedding is not None:
|
|
2381
|
+
if (<Parent>S)._embedding.codomain() is self:
|
|
2382
|
+
return (<Parent>S)._embedding
|
|
2383
|
+
|
|
2384
|
+
user_provided_mor = self._coerce_map_from_(S)
|
|
2385
|
+
|
|
2386
|
+
if user_provided_mor is None or user_provided_mor is False:
|
|
2387
|
+
best_mor = None
|
|
2388
|
+
elif user_provided_mor is True:
|
|
2389
|
+
best_mor = self._generic_coerce_map(S)
|
|
2390
|
+
if not isinstance(best_mor, DefaultConvertMap):
|
|
2391
|
+
return best_mor
|
|
2392
|
+
# Continue searching for better maps. If there is something
|
|
2393
|
+
# better in the list, return that instead. This is so, for
|
|
2394
|
+
# example, _coerce_map_from_ can return True but still take
|
|
2395
|
+
# advantage of the _populate_coercion_lists_ data.
|
|
2396
|
+
elif isinstance(user_provided_mor, map.Map):
|
|
2397
|
+
return user_provided_mor
|
|
2398
|
+
elif callable(user_provided_mor):
|
|
2399
|
+
return CallableConvertMap(S, self, user_provided_mor)
|
|
2400
|
+
else:
|
|
2401
|
+
raise TypeError(
|
|
2402
|
+
_LazyString("_coerce_map_from_ must return None, a boolean, a callable, or an explicit Map (called on %s, got %s)",
|
|
2403
|
+
(type(self), type(user_provided_mor)), {}))
|
|
2404
|
+
|
|
2405
|
+
from sage.categories.homset import Hom
|
|
2406
|
+
|
|
2407
|
+
cdef map.Map mor
|
|
2408
|
+
cdef int num_paths = 1
|
|
2409
|
+
# this is the number of paths we find before settling on the best (the one with lowest coerce_cost).
|
|
2410
|
+
# setting this to 1 will make it return the first path found.
|
|
2411
|
+
|
|
2412
|
+
cdef int mor_found = 0
|
|
2413
|
+
cdef Parent D
|
|
2414
|
+
# Recurse. Note that if S is the domain of one of the maps in self._coerce_from_list,
|
|
2415
|
+
# we will have stuck the map into _coerce_map_hash and thus returned it already.
|
|
2416
|
+
for mor in self._coerce_from_list:
|
|
2417
|
+
D = mor.domain()
|
|
2418
|
+
if D is self:
|
|
2419
|
+
continue
|
|
2420
|
+
if D is S:
|
|
2421
|
+
if best_mor is None or mor._coerce_cost < best_mor._coerce_cost:
|
|
2422
|
+
best_mor = mor
|
|
2423
|
+
mor_found += 1
|
|
2424
|
+
if mor_found >= num_paths:
|
|
2425
|
+
return best_mor
|
|
2426
|
+
else:
|
|
2427
|
+
connecting = None
|
|
2428
|
+
if EltPair(D, S, "coerce") not in _coerce_test_dict:
|
|
2429
|
+
connecting = D._internal_coerce_map_from(S)
|
|
2430
|
+
if connecting is not None:
|
|
2431
|
+
mor = mor * connecting
|
|
2432
|
+
if best_mor is None or mor._coerce_cost < best_mor._coerce_cost:
|
|
2433
|
+
best_mor = mor
|
|
2434
|
+
mor_found += 1
|
|
2435
|
+
if mor_found >= num_paths:
|
|
2436
|
+
return best_mor
|
|
2437
|
+
|
|
2438
|
+
if best_mor is not None:
|
|
2439
|
+
return best_mor
|
|
2440
|
+
|
|
2441
|
+
if isinstance(S, Parent) and (<Parent>S)._embedding is not None:
|
|
2442
|
+
connecting = self._internal_coerce_map_from((<Parent>S)._embedding.codomain())
|
|
2443
|
+
if connecting is not None:
|
|
2444
|
+
return (<Parent>S)._embedding.post_compose(connecting)
|
|
2445
|
+
|
|
2446
|
+
cpdef convert_map_from(self, S):
|
|
2447
|
+
"""
|
|
2448
|
+
This function returns a :class:`Map` from `S` to ``self``,
|
|
2449
|
+
which may or may not succeed on all inputs.
|
|
2450
|
+
If a coercion map from S to ``self`` exists,
|
|
2451
|
+
then the it will be returned. If a coercion from ``self`` to `S` exists,
|
|
2452
|
+
then it will attempt to return a section of that map.
|
|
2453
|
+
|
|
2454
|
+
Under the new coercion model, this is the fastest way to convert
|
|
2455
|
+
elements of `S` to elements of ``self`` (short of manually constructing
|
|
2456
|
+
the elements) and is used by :meth:`__call__`.
|
|
2457
|
+
|
|
2458
|
+
EXAMPLES::
|
|
2459
|
+
|
|
2460
|
+
sage: m = ZZ.convert_map_from(QQ)
|
|
2461
|
+
sage: m
|
|
2462
|
+
Generic map:
|
|
2463
|
+
From: Rational Field
|
|
2464
|
+
To: Integer Ring
|
|
2465
|
+
sage: m(-35/7)
|
|
2466
|
+
-5
|
|
2467
|
+
sage: parent(m(-35/7))
|
|
2468
|
+
Integer Ring
|
|
2469
|
+
"""
|
|
2470
|
+
return copy(self._internal_convert_map_from(S))
|
|
2471
|
+
|
|
2472
|
+
cpdef _internal_convert_map_from(self, S):
|
|
2473
|
+
"""
|
|
2474
|
+
This function returns a :class:`Map` from `S` to ``self``,
|
|
2475
|
+
which may or may not succeed on all inputs.
|
|
2476
|
+
If a coercion map from S to ``self`` exists,
|
|
2477
|
+
then the it will be returned. If a coercion from ``self`` to `S` exists,
|
|
2478
|
+
then it will attempt to return a section of that map.
|
|
2479
|
+
|
|
2480
|
+
Under the new coercion model, this is the fastest way to convert
|
|
2481
|
+
elements of `S` to elements of ``self`` (short of manually constructing
|
|
2482
|
+
the elements) and is used by :func:`__call__`.
|
|
2483
|
+
|
|
2484
|
+
EXAMPLES::
|
|
2485
|
+
|
|
2486
|
+
sage: m = ZZ._internal_convert_map_from(QQ)
|
|
2487
|
+
sage: m
|
|
2488
|
+
(map internal to coercion system -- copy before use)
|
|
2489
|
+
Generic map:
|
|
2490
|
+
From: Rational Field
|
|
2491
|
+
To: Integer Ring
|
|
2492
|
+
sage: m(-35/7)
|
|
2493
|
+
-5
|
|
2494
|
+
sage: parent(m(-35/7))
|
|
2495
|
+
Integer Ring
|
|
2496
|
+
"""
|
|
2497
|
+
if not good_as_convert_domain(S):
|
|
2498
|
+
return None
|
|
2499
|
+
if self._convert_from_hash is None: # this is because parent.__init__() does not always get called
|
|
2500
|
+
self.init_coerce()
|
|
2501
|
+
try:
|
|
2502
|
+
return self._convert_from_hash.get(S)
|
|
2503
|
+
except KeyError:
|
|
2504
|
+
mor = self.discover_convert_map_from(S)
|
|
2505
|
+
# Before Issue #14711, the morphism has been
|
|
2506
|
+
# put both into _convert_from_list and into
|
|
2507
|
+
# _convert_from_hash. But there is no reason
|
|
2508
|
+
# to have a double book-keeping, specifically
|
|
2509
|
+
# if one of them is by strong references!
|
|
2510
|
+
self._convert_from_hash.set(S, mor)
|
|
2511
|
+
# Moreover, again by #14711, the morphism should
|
|
2512
|
+
# only keep weak references to domain and codomain,
|
|
2513
|
+
# to allow them being garbage collected.
|
|
2514
|
+
if mor is not None:
|
|
2515
|
+
mor._make_weak_references()
|
|
2516
|
+
return mor
|
|
2517
|
+
|
|
2518
|
+
cdef discover_convert_map_from(self, S):
|
|
2519
|
+
|
|
2520
|
+
cdef map.Map mor = self._internal_coerce_map_from(S)
|
|
2521
|
+
if mor is not None:
|
|
2522
|
+
return mor
|
|
2523
|
+
|
|
2524
|
+
if isinstance(S, Parent):
|
|
2525
|
+
mor = S._internal_coerce_map_from(self)
|
|
2526
|
+
if mor is not None:
|
|
2527
|
+
mor = mor.section()
|
|
2528
|
+
if mor is not None:
|
|
2529
|
+
return mor
|
|
2530
|
+
|
|
2531
|
+
user_provided_mor = self._convert_map_from_(S)
|
|
2532
|
+
|
|
2533
|
+
if user_provided_mor is not None:
|
|
2534
|
+
if isinstance(user_provided_mor, map.Map):
|
|
2535
|
+
return user_provided_mor
|
|
2536
|
+
elif callable(user_provided_mor):
|
|
2537
|
+
return CallableConvertMap(S, self, user_provided_mor)
|
|
2538
|
+
else:
|
|
2539
|
+
raise TypeError(
|
|
2540
|
+
_LazyString("_convert_map_from_ must return a map or callable (called on %s, got %s)",
|
|
2541
|
+
(type(self), type(user_provided_mor)), {}))
|
|
2542
|
+
|
|
2543
|
+
mor = self._generic_convert_map(S)
|
|
2544
|
+
return mor
|
|
2545
|
+
|
|
2546
|
+
cpdef _convert_map_from_(self, S):
|
|
2547
|
+
"""
|
|
2548
|
+
Override this method to provide additional conversions beyond those
|
|
2549
|
+
given in ``convert_list``.
|
|
2550
|
+
|
|
2551
|
+
This function is called after coercions are attempted. If there is a
|
|
2552
|
+
coercion morphism in the opposite direction, one should consider
|
|
2553
|
+
adding a section method to that.
|
|
2554
|
+
|
|
2555
|
+
This MUST return a Map from ``S`` to ``self``, or ``None``. If ``None``
|
|
2556
|
+
is returned then a generic map will be provided.
|
|
2557
|
+
"""
|
|
2558
|
+
return None
|
|
2559
|
+
|
|
2560
|
+
cpdef get_action(self, S, op=operator.mul, bint self_on_left=True, self_el=None, S_el=None):
|
|
2561
|
+
"""
|
|
2562
|
+
Return an action of ``self`` on ``S`` or ``S`` on ``self``.
|
|
2563
|
+
|
|
2564
|
+
To provide additional actions, override :meth:`_get_action_`.
|
|
2565
|
+
|
|
2566
|
+
.. WARNING::
|
|
2567
|
+
|
|
2568
|
+
This is not the method that you typically want to call.
|
|
2569
|
+
Instead, call ``coercion_model.get_action(...)`` which
|
|
2570
|
+
caches results (this ``Parent.get_action`` method does not).
|
|
2571
|
+
|
|
2572
|
+
TESTS::
|
|
2573
|
+
|
|
2574
|
+
sage: M = QQ['y']^3 # needs sage.modules
|
|
2575
|
+
sage: M.get_action(ZZ['x']['y']) # needs sage.modules
|
|
2576
|
+
Right scalar multiplication
|
|
2577
|
+
by Univariate Polynomial Ring in y
|
|
2578
|
+
over Univariate Polynomial Ring in x over Integer Ring
|
|
2579
|
+
on Ambient free module of rank 3 over the principal ideal domain
|
|
2580
|
+
Univariate Polynomial Ring in y over Rational Field
|
|
2581
|
+
sage: print(M.get_action(ZZ['x'])) # needs sage.modules
|
|
2582
|
+
None
|
|
2583
|
+
"""
|
|
2584
|
+
action = self._get_action_(S, op, self_on_left)
|
|
2585
|
+
if action is None:
|
|
2586
|
+
action = self.discover_action(S, op, self_on_left, self_el, S_el)
|
|
2587
|
+
|
|
2588
|
+
if action is not None:
|
|
2589
|
+
from sage.categories.action import Action
|
|
2590
|
+
if not isinstance(action, Action):
|
|
2591
|
+
raise TypeError("_get_action_ must return None or an Action")
|
|
2592
|
+
|
|
2593
|
+
self._action_hash.set(S, op, self_on_left, action)
|
|
2594
|
+
return action
|
|
2595
|
+
|
|
2596
|
+
cdef discover_action(self, S, op, bint self_on_left, self_el=None, S_el=None):
|
|
2597
|
+
"""
|
|
2598
|
+
TESTS::
|
|
2599
|
+
|
|
2600
|
+
sage: # needs sage.schemes
|
|
2601
|
+
sage: E = EllipticCurve([1,0])
|
|
2602
|
+
sage: coercion_model.get_action(E, ZZ, operator.mul)
|
|
2603
|
+
Right action by Integer Ring on Elliptic Curve defined by y^2 = x^3 + x over Rational Field
|
|
2604
|
+
sage: coercion_model.get_action(ZZ, E, operator.mul)
|
|
2605
|
+
Left action by Integer Ring on Elliptic Curve defined by y^2 = x^3 + x over Rational Field
|
|
2606
|
+
sage: coercion_model.get_action(E, int, operator.mul)
|
|
2607
|
+
Right action by Integer Ring on Elliptic Curve defined by y^2 = x^3 + x over Rational Field
|
|
2608
|
+
with precomposition on right by Native morphism:
|
|
2609
|
+
From: Set of Python objects of class 'int'
|
|
2610
|
+
To: Integer Ring
|
|
2611
|
+
sage: coercion_model.get_action(int, E, operator.mul)
|
|
2612
|
+
Left action by Integer Ring on Elliptic Curve defined by y^2 = x^3 + x over Rational Field
|
|
2613
|
+
with precomposition on left by Native morphism:
|
|
2614
|
+
From: Set of Python objects of class 'int'
|
|
2615
|
+
To: Integer Ring
|
|
2616
|
+
|
|
2617
|
+
::
|
|
2618
|
+
|
|
2619
|
+
sage: # needs sage.rings.complex_double
|
|
2620
|
+
sage: R.<x> = CDF[]
|
|
2621
|
+
sage: coercion_model.get_action(R, ZZ, operator.pow)
|
|
2622
|
+
Right Integer Powering by Integer Ring
|
|
2623
|
+
on Univariate Polynomial Ring in x over Complex Double Field
|
|
2624
|
+
sage: print(coercion_model.get_action(ZZ, R, operator.pow))
|
|
2625
|
+
None
|
|
2626
|
+
sage: coercion_model.get_action(R, int, operator.pow)
|
|
2627
|
+
Right Integer Powering by Set of Python objects of class 'int'
|
|
2628
|
+
on Univariate Polynomial Ring in x over Complex Double Field
|
|
2629
|
+
sage: print(coercion_model.get_action(int, R, operator.pow))
|
|
2630
|
+
None
|
|
2631
|
+
sage: coercion_model.get_action(R, IntegerModRing(7), operator.pow)
|
|
2632
|
+
Right Integer Powering by Ring of integers modulo 7
|
|
2633
|
+
on Univariate Polynomial Ring in x over Complex Double Field
|
|
2634
|
+
|
|
2635
|
+
::
|
|
2636
|
+
|
|
2637
|
+
sage: print(coercion_model.get_action(E, ZZ, operator.pow)) # needs sage.schemes
|
|
2638
|
+
None
|
|
2639
|
+
|
|
2640
|
+
::
|
|
2641
|
+
|
|
2642
|
+
With Pull Request #37369, registered multiplication actions by
|
|
2643
|
+
`ZZ` are also discovered and used when a Python ``int`` is multiplied.
|
|
2644
|
+
Previously, it was only discovering the generic Integer Multiplication
|
|
2645
|
+
Action that all additive groups have. As a result, optimised
|
|
2646
|
+
implementations, such as the use of Pari for scalar multiplication of points
|
|
2647
|
+
on elliptic curves over Finite Fields, was not used if an ``int``
|
|
2648
|
+
multiplied a point, resulting in a 10x slowdown for large characteristic::
|
|
2649
|
+
|
|
2650
|
+
sage: # needs sage.schemes
|
|
2651
|
+
sage: E = EllipticCurve(GF(17),[1,1])
|
|
2652
|
+
sage: coercion_model.discover_action(ZZ, E, operator.mul)
|
|
2653
|
+
Left action by Integer Ring on Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 17
|
|
2654
|
+
sage: coercion_model.discover_action(int, E, operator.mul)
|
|
2655
|
+
Left action by Integer Ring on Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 17
|
|
2656
|
+
with precomposition on left by Native morphism:
|
|
2657
|
+
From: Set of Python objects of class 'int'
|
|
2658
|
+
To: Integer Ring
|
|
2659
|
+
"""
|
|
2660
|
+
# G acts on S, G -> G', R -> S => G' acts on R (?)
|
|
2661
|
+
# NO! ZZ[x,y] acts on Matrices(ZZ[x]) but ZZ[y] does not.
|
|
2662
|
+
# What may be true is that if the action's destination is S, then this can be allowed.
|
|
2663
|
+
# Note: a is either None or a sample elements of self.
|
|
2664
|
+
# If needed, it will be passed to Left/RightModuleAction.
|
|
2665
|
+
from sage.categories.action import Action, PrecomposedAction
|
|
2666
|
+
from sage.categories.homset import Hom
|
|
2667
|
+
cdef Parent R
|
|
2668
|
+
|
|
2669
|
+
for action in self._action_list:
|
|
2670
|
+
if isinstance(action, Action) and action.operation() is op:
|
|
2671
|
+
if self_on_left:
|
|
2672
|
+
if action.left_domain() is not self:
|
|
2673
|
+
continue
|
|
2674
|
+
R = action.right_domain()
|
|
2675
|
+
else:
|
|
2676
|
+
if action.right_domain() is not self:
|
|
2677
|
+
continue
|
|
2678
|
+
R = action.left_domain()
|
|
2679
|
+
else:
|
|
2680
|
+
continue
|
|
2681
|
+
if R is S:
|
|
2682
|
+
return action
|
|
2683
|
+
else:
|
|
2684
|
+
connecting = R._internal_coerce_map_from(S) # S -> R
|
|
2685
|
+
if connecting is not None:
|
|
2686
|
+
if self_on_left:
|
|
2687
|
+
return PrecomposedAction(action, None, connecting)
|
|
2688
|
+
else:
|
|
2689
|
+
return PrecomposedAction(action, connecting, None)
|
|
2690
|
+
|
|
2691
|
+
if op is operator.mul: # elements define special action methods.
|
|
2692
|
+
try:
|
|
2693
|
+
_register_pair(self, S, "action") # avoid possible infinite loops
|
|
2694
|
+
|
|
2695
|
+
# detect actions defined by _rmul_, _lmul_, _act_on_, and _acted_upon_ methods
|
|
2696
|
+
from sage.structure.coerce_actions import detect_element_action
|
|
2697
|
+
action = detect_element_action(self, S, self_on_left, self_el, S_el)
|
|
2698
|
+
if action is not None:
|
|
2699
|
+
return action
|
|
2700
|
+
|
|
2701
|
+
if parent_is_integers(S) and not self.has_coerce_map_from(S):
|
|
2702
|
+
# Try the above again, but first coerce integer-like type to Integer
|
|
2703
|
+
# with a connecting coercion
|
|
2704
|
+
global _Integer
|
|
2705
|
+
if _Integer is None:
|
|
2706
|
+
from sage.rings.integer import Integer as _Integer
|
|
2707
|
+
ZZ_el = _Integer(S_el)
|
|
2708
|
+
ZZ = ZZ_el.parent()
|
|
2709
|
+
|
|
2710
|
+
# Now we check if there's an element action from Integers
|
|
2711
|
+
action = detect_element_action(self, ZZ, self_on_left, self_el, ZZ_el)
|
|
2712
|
+
|
|
2713
|
+
# When this is not None, we can do the Precomposed action
|
|
2714
|
+
if action is not None:
|
|
2715
|
+
# Compute the coercion from whatever S is to the Integer class
|
|
2716
|
+
# This should always work because parent_is_integers(S) is True
|
|
2717
|
+
# but it fails when S is gmpy2.mpz.
|
|
2718
|
+
# TODO: should we also patch _internal_coerce_map_from so that
|
|
2719
|
+
# there's a map from gmpy2.mpz to ZZ?
|
|
2720
|
+
connecting = ZZ._internal_coerce_map_from(S)
|
|
2721
|
+
if connecting is not None:
|
|
2722
|
+
if self_on_left:
|
|
2723
|
+
action = PrecomposedAction(action, None, connecting)
|
|
2724
|
+
else:
|
|
2725
|
+
action = PrecomposedAction(action, connecting, None)
|
|
2726
|
+
return action
|
|
2727
|
+
|
|
2728
|
+
# Otherwise, we do the most basic IntegerMulAction
|
|
2729
|
+
from sage.structure.coerce_actions import IntegerMulAction
|
|
2730
|
+
try:
|
|
2731
|
+
return IntegerMulAction(S, self, not self_on_left, self_el)
|
|
2732
|
+
except TypeError:
|
|
2733
|
+
_record_exception()
|
|
2734
|
+
finally:
|
|
2735
|
+
_unregister_pair(self, S, "action")
|
|
2736
|
+
elif self_on_left and op is operator.pow:
|
|
2737
|
+
S_is_int = parent_is_integers(S)
|
|
2738
|
+
if not S_is_int:
|
|
2739
|
+
from sage.rings.abc import IntegerModRing
|
|
2740
|
+
if isinstance(S, IntegerModRing):
|
|
2741
|
+
# We allow powering by an IntegerMod by treating it
|
|
2742
|
+
# as an integer.
|
|
2743
|
+
#
|
|
2744
|
+
# TODO: this makes sense in a few cases that we want
|
|
2745
|
+
# to support. But in general this should not be
|
|
2746
|
+
# allowed. See Issue #15709
|
|
2747
|
+
S_is_int = True
|
|
2748
|
+
if S_is_int:
|
|
2749
|
+
from sage.structure.coerce_actions import IntegerPowAction
|
|
2750
|
+
try:
|
|
2751
|
+
return IntegerPowAction(S, self, False, self_el)
|
|
2752
|
+
except TypeError:
|
|
2753
|
+
_record_exception()
|
|
2754
|
+
|
|
2755
|
+
cpdef _get_action_(self, S, op, bint self_on_left):
|
|
2756
|
+
"""
|
|
2757
|
+
Override this method to provide an action of ``self`` on ``S`` or ``S``
|
|
2758
|
+
on ``self`` beyond what was specified in ``action_list``.
|
|
2759
|
+
|
|
2760
|
+
This must return an action which accepts an element of ``self`` and an
|
|
2761
|
+
element of ``S`` (in the order specified by ``self_on_left``).
|
|
2762
|
+
"""
|
|
2763
|
+
return None
|
|
2764
|
+
|
|
2765
|
+
# TODO: remove once all parents in Sage will inherit properly from
|
|
2766
|
+
# Sets().ParentMethods.an_element
|
|
2767
|
+
cpdef an_element(self):
|
|
2768
|
+
r"""
|
|
2769
|
+
Return a (preferably typical) element of this parent.
|
|
2770
|
+
|
|
2771
|
+
This is used both for illustration and testing purposes. If
|
|
2772
|
+
the set ``self`` is empty, :meth:`an_element` raises the
|
|
2773
|
+
exception :exc:`EmptySetError`.
|
|
2774
|
+
|
|
2775
|
+
This calls :meth:`_an_element_` (which see), and caches the
|
|
2776
|
+
result. Parent are thus encouraged to override :meth:`_an_element_`.
|
|
2777
|
+
|
|
2778
|
+
EXAMPLES::
|
|
2779
|
+
|
|
2780
|
+
sage: CDF.an_element() # needs sage.rings.complex_double
|
|
2781
|
+
1.0*I
|
|
2782
|
+
sage: ZZ[['t']].an_element()
|
|
2783
|
+
t
|
|
2784
|
+
|
|
2785
|
+
In case the set is empty, an :exc:`EmptySetError` is raised::
|
|
2786
|
+
|
|
2787
|
+
sage: Set([]).an_element()
|
|
2788
|
+
Traceback (most recent call last):
|
|
2789
|
+
...
|
|
2790
|
+
EmptySetError
|
|
2791
|
+
"""
|
|
2792
|
+
# _cache_an_element, not _cache__an_element, to prevent a possible
|
|
2793
|
+
# conflict with @cached_method
|
|
2794
|
+
if self._cache_an_element is None:
|
|
2795
|
+
self._cache_an_element = self._an_element_()
|
|
2796
|
+
return self._cache_an_element
|
|
2797
|
+
|
|
2798
|
+
def _an_element_(self):
|
|
2799
|
+
"""
|
|
2800
|
+
Return an element of ``self``.
|
|
2801
|
+
|
|
2802
|
+
Want it in sufficient generality
|
|
2803
|
+
that poorly-written functions will not work when they are not
|
|
2804
|
+
supposed to. This is cached so does not have to be super fast.
|
|
2805
|
+
|
|
2806
|
+
EXAMPLES::
|
|
2807
|
+
|
|
2808
|
+
sage: QQ._an_element_()
|
|
2809
|
+
1/2
|
|
2810
|
+
sage: ZZ['x,y,z']._an_element_()
|
|
2811
|
+
x
|
|
2812
|
+
|
|
2813
|
+
TESTS:
|
|
2814
|
+
|
|
2815
|
+
Since ``Parent`` comes before the parent classes provided by
|
|
2816
|
+
categories in the hierarchy of classes, we make sure that this
|
|
2817
|
+
default implementation of :meth:`_an_element_` does not
|
|
2818
|
+
override some provided by the categories. Eventually, this
|
|
2819
|
+
default implementation should be moved into the categories to
|
|
2820
|
+
avoid this workaround::
|
|
2821
|
+
|
|
2822
|
+
sage: S = FiniteEnumeratedSet([1,2,3])
|
|
2823
|
+
sage: S.category()
|
|
2824
|
+
Category of facade finite enumerated sets
|
|
2825
|
+
sage: super(Parent, S)._an_element_
|
|
2826
|
+
Cached version of <function ..._an_element_from_iterator at ...>
|
|
2827
|
+
sage: S._an_element_()
|
|
2828
|
+
1
|
|
2829
|
+
sage: S = FiniteEnumeratedSet([])
|
|
2830
|
+
sage: S._an_element_()
|
|
2831
|
+
Traceback (most recent call last):
|
|
2832
|
+
...
|
|
2833
|
+
EmptySetError
|
|
2834
|
+
"""
|
|
2835
|
+
try:
|
|
2836
|
+
return super()._an_element_()
|
|
2837
|
+
except EmptySetError:
|
|
2838
|
+
raise
|
|
2839
|
+
except Exception:
|
|
2840
|
+
_record_exception()
|
|
2841
|
+
pass
|
|
2842
|
+
|
|
2843
|
+
try:
|
|
2844
|
+
return self.gen(0)
|
|
2845
|
+
except Exception:
|
|
2846
|
+
_record_exception()
|
|
2847
|
+
pass
|
|
2848
|
+
|
|
2849
|
+
try:
|
|
2850
|
+
return self.gen()
|
|
2851
|
+
except Exception:
|
|
2852
|
+
_record_exception()
|
|
2853
|
+
pass
|
|
2854
|
+
|
|
2855
|
+
from sage.rings.infinity import infinity
|
|
2856
|
+
for x in ['_an_element_', 'pi', 1.2, 2, 1, 0, infinity]:
|
|
2857
|
+
# This weird looking list is to try to get an element
|
|
2858
|
+
# which does not coerce other places.
|
|
2859
|
+
try:
|
|
2860
|
+
return self(x)
|
|
2861
|
+
except (TypeError, NameError, NotImplementedError, AttributeError, ValueError):
|
|
2862
|
+
_record_exception()
|
|
2863
|
+
|
|
2864
|
+
raise NotImplementedError(_LazyString("please implement _an_element_ for %s", (self,), {}))
|
|
2865
|
+
|
|
2866
|
+
cpdef bint is_exact(self) except -2:
|
|
2867
|
+
"""
|
|
2868
|
+
Test whether elements of this parent are represented exactly.
|
|
2869
|
+
|
|
2870
|
+
.. NOTE::
|
|
2871
|
+
|
|
2872
|
+
This defaults to true, so even if it does return ``True``
|
|
2873
|
+
you have no guarantee (unless the parent has properly
|
|
2874
|
+
overloaded this).
|
|
2875
|
+
|
|
2876
|
+
OUTPUT:
|
|
2877
|
+
|
|
2878
|
+
Return ``True`` if elements of this parent are represented exactly, i.e.,
|
|
2879
|
+
there is no precision loss when doing arithmetic.
|
|
2880
|
+
|
|
2881
|
+
EXAMPLES::
|
|
2882
|
+
|
|
2883
|
+
sage: QQ.is_exact()
|
|
2884
|
+
True
|
|
2885
|
+
sage: ZZ.is_exact()
|
|
2886
|
+
True
|
|
2887
|
+
sage: Qp(7).is_exact() # needs sage.rings.padics
|
|
2888
|
+
False
|
|
2889
|
+
sage: Zp(7, type='capped-abs').is_exact() # needs sage.rings.padics
|
|
2890
|
+
False
|
|
2891
|
+
"""
|
|
2892
|
+
return True
|
|
2893
|
+
|
|
2894
|
+
@cached_method
|
|
2895
|
+
def _is_numerical(self):
|
|
2896
|
+
r"""
|
|
2897
|
+
Test if elements of this parent can be numerically evaluated as complex
|
|
2898
|
+
numbers (in a canonical way).
|
|
2899
|
+
|
|
2900
|
+
EXAMPLES::
|
|
2901
|
+
|
|
2902
|
+
sage: QuadraticField(-1)._is_numerical() # needs sage.rings.number_field
|
|
2903
|
+
True
|
|
2904
|
+
sage: QQ._is_numerical()
|
|
2905
|
+
True
|
|
2906
|
+
sage: [RR._is_numerical(), CC._is_numerical()] # needs sage.rings.real_mpfr
|
|
2907
|
+
[True, True]
|
|
2908
|
+
sage: SR._is_numerical() # needs sage.symbolic
|
|
2909
|
+
False
|
|
2910
|
+
sage: [R._is_numerical() for R in [QQ['x'], QQ[['x']]]]
|
|
2911
|
+
[False, False]
|
|
2912
|
+
sage: [R._is_numerical() for R in [RBF, CBF]] # needs sage.libs.flint
|
|
2913
|
+
[False, False]
|
|
2914
|
+
sage: [R._is_numerical() for R in [RIF, CIF]] # needs sage.rings.real_interval_field
|
|
2915
|
+
[False, False]
|
|
2916
|
+
"""
|
|
2917
|
+
try:
|
|
2918
|
+
from sage.rings.complex_mpfr import ComplexField
|
|
2919
|
+
from sage.rings.real_mpfr import mpfr_prec_min
|
|
2920
|
+
except ImportError:
|
|
2921
|
+
pass
|
|
2922
|
+
else:
|
|
2923
|
+
return ComplexField(mpfr_prec_min()).has_coerce_map_from(self)
|
|
2924
|
+
|
|
2925
|
+
try:
|
|
2926
|
+
from sage.rings.complex_double import CDF
|
|
2927
|
+
except ImportError:
|
|
2928
|
+
pass
|
|
2929
|
+
else:
|
|
2930
|
+
return CDF.has_coerce_map_from(self)
|
|
2931
|
+
|
|
2932
|
+
from sage.rings.real_double import RDF
|
|
2933
|
+
return RDF.has_coerce_map_from(self)
|
|
2934
|
+
|
|
2935
|
+
@cached_method
|
|
2936
|
+
def _is_real_numerical(self):
|
|
2937
|
+
r"""
|
|
2938
|
+
Test if elements of this parent can be numerically evaluated as real
|
|
2939
|
+
numbers (in a canonical way).
|
|
2940
|
+
|
|
2941
|
+
EXAMPLES::
|
|
2942
|
+
|
|
2943
|
+
sage: QuadraticField(2)._is_real_numerical() # needs sage.rings.number_field
|
|
2944
|
+
True
|
|
2945
|
+
sage: [QQ._is_real_numerical(), ZZ._is_real_numerical()]
|
|
2946
|
+
[True, True]
|
|
2947
|
+
sage: [RR._is_real_numerical(), RLF._is_real_numerical()] # needs sage.rings.real_mpfr
|
|
2948
|
+
[True, True]
|
|
2949
|
+
sage: QuadraticField(-1)._is_real_numerical() # needs sage.rings.number_field
|
|
2950
|
+
False
|
|
2951
|
+
sage: CC._is_real_numerical() # needs sage.rings.real_mpfr
|
|
2952
|
+
False
|
|
2953
|
+
sage: SR._is_real_numerical() # needs sage.symbolic
|
|
2954
|
+
False
|
|
2955
|
+
sage: [R._is_real_numerical() for R in [QQ['x'], QQ[['x']]]]
|
|
2956
|
+
[False, False]
|
|
2957
|
+
sage: [R._is_real_numerical() for R in [RBF, CBF]] # needs sage.libs.flint
|
|
2958
|
+
[False, False]
|
|
2959
|
+
sage: [R._is_real_numerical() for R in [RIF, CIF]] # needs sage.libs.flint
|
|
2960
|
+
[False, False]
|
|
2961
|
+
"""
|
|
2962
|
+
try:
|
|
2963
|
+
from sage.rings.real_mpfr import RealField, mpfr_prec_min
|
|
2964
|
+
except ImportError:
|
|
2965
|
+
pass
|
|
2966
|
+
else:
|
|
2967
|
+
return RealField(mpfr_prec_min()).has_coerce_map_from(self)
|
|
2968
|
+
|
|
2969
|
+
from sage.rings.real_double import RDF
|
|
2970
|
+
return RDF.has_coerce_map_from(self)
|
|
2971
|
+
|
|
2972
|
+
############################################################################
|
|
2973
|
+
# Set base class --
|
|
2974
|
+
############################################################################
|
|
2975
|
+
|
|
2976
|
+
cdef class Set_generic(Parent):
|
|
2977
|
+
"""
|
|
2978
|
+
Abstract base class for sets.
|
|
2979
|
+
|
|
2980
|
+
TESTS::
|
|
2981
|
+
|
|
2982
|
+
sage: Set(QQ).category()
|
|
2983
|
+
Category of infinite sets
|
|
2984
|
+
"""
|
|
2985
|
+
def object(self):
|
|
2986
|
+
"""
|
|
2987
|
+
Return the underlying object of ``self``.
|
|
2988
|
+
|
|
2989
|
+
EXAMPLES::
|
|
2990
|
+
|
|
2991
|
+
sage: Set(QQ).object()
|
|
2992
|
+
Rational Field
|
|
2993
|
+
"""
|
|
2994
|
+
return self
|
|
2995
|
+
|
|
2996
|
+
def __bool__(self):
|
|
2997
|
+
"""
|
|
2998
|
+
A set is considered ``True`` unless it is empty, in which case it is
|
|
2999
|
+
considered to be ``False``.
|
|
3000
|
+
|
|
3001
|
+
EXAMPLES::
|
|
3002
|
+
|
|
3003
|
+
sage: bool(Set(QQ))
|
|
3004
|
+
True
|
|
3005
|
+
sage: bool(Set(GF(3)))
|
|
3006
|
+
True
|
|
3007
|
+
"""
|
|
3008
|
+
return not (self.is_finite() and len(self) == 0)
|
|
3009
|
+
|
|
3010
|
+
|
|
3011
|
+
# These functions are to guarantee that user defined _lmul_, _rmul_,
|
|
3012
|
+
# _act_on_, _acted_upon_ do not in turn call __mul__ on their
|
|
3013
|
+
# arguments, leading to an infinite loop.
|
|
3014
|
+
|
|
3015
|
+
cdef dict _coerce_test_dict = {}
|
|
3016
|
+
|
|
3017
|
+
cdef class EltPair:
|
|
3018
|
+
cdef x, y, tag
|
|
3019
|
+
|
|
3020
|
+
def __init__(self, x, y, tag):
|
|
3021
|
+
self.x = x
|
|
3022
|
+
self.y = y
|
|
3023
|
+
self.tag = tag
|
|
3024
|
+
|
|
3025
|
+
def __richcmp__(EltPair self, EltPair other, int op):
|
|
3026
|
+
cdef bint eq = self.x is other.x and self.y is other.y and self.tag is other.tag
|
|
3027
|
+
if op in [Py_EQ, Py_GE, Py_LE]:
|
|
3028
|
+
return eq
|
|
3029
|
+
else:
|
|
3030
|
+
return not eq
|
|
3031
|
+
|
|
3032
|
+
def __hash__(self):
|
|
3033
|
+
"""
|
|
3034
|
+
EXAMPLES::
|
|
3035
|
+
|
|
3036
|
+
sage: from sage.structure.parent import EltPair
|
|
3037
|
+
sage: a = EltPair(ZZ, QQ, "coerce")
|
|
3038
|
+
sage: b = EltPair(ZZ, QQ, "coerce")
|
|
3039
|
+
sage: hash(a) == hash(b)
|
|
3040
|
+
True
|
|
3041
|
+
|
|
3042
|
+
TESTS:
|
|
3043
|
+
|
|
3044
|
+
Verify that :issue:`16341` has been resolved::
|
|
3045
|
+
|
|
3046
|
+
sage: K.<a> = Qq(9) # needs sage.rings.padics
|
|
3047
|
+
sage: E = EllipticCurve_from_j(0).base_extend(K) # needs sage.rings.padics sage.schemes
|
|
3048
|
+
sage: E.get_action(ZZ) # needs sage.rings.padics sage.schemes
|
|
3049
|
+
Right action by Integer Ring
|
|
3050
|
+
on Elliptic Curve defined by y^2 + (1+O(3^20))*y = x^3
|
|
3051
|
+
over 3-adic Unramified Extension Field in a
|
|
3052
|
+
defined by x^2 + 2*x + 2
|
|
3053
|
+
"""
|
|
3054
|
+
return hash((id(self.x), id(self.y), id(self.tag)))
|
|
3055
|
+
|
|
3056
|
+
def short_repr(self):
|
|
3057
|
+
return self.tag, hex(<long><void*>self.x), hex(<long><void*>self.y)
|
|
3058
|
+
|
|
3059
|
+
def __repr__(self):
|
|
3060
|
+
return "%r: %r (%r), %r (%r)" % (self.tag, self.x, type(self.x), self.y, type(self.y))
|
|
3061
|
+
|
|
3062
|
+
cdef bint _may_cache_none(x, y, tag) except -1:
|
|
3063
|
+
# Are we allowed to cache the absence of a coercion
|
|
3064
|
+
# from y to x? We are only allowed, if y is *not*
|
|
3065
|
+
# part of any coerce path that is temporarily disregarded,
|
|
3066
|
+
# with the only exception of the path from y to x.
|
|
3067
|
+
# See #12969.
|
|
3068
|
+
cdef EltPair P
|
|
3069
|
+
for P in _coerce_test_dict:
|
|
3070
|
+
if (P.y is y) and (P.x is not x) and (P.tag is tag):
|
|
3071
|
+
return 0
|
|
3072
|
+
return 1
|
|
3073
|
+
|
|
3074
|
+
cdef bint _register_pair(x, y, tag) except -1:
|
|
3075
|
+
# Means: We will temporarily disregard coercions from
|
|
3076
|
+
# y to x when looking for a coercion path by depth first
|
|
3077
|
+
# search. This is to avoid infinite recursion.
|
|
3078
|
+
both = EltPair(x, y, tag)
|
|
3079
|
+
|
|
3080
|
+
if both in _coerce_test_dict:
|
|
3081
|
+
xp = type(x) if isinstance(x, Parent) else parent(x)
|
|
3082
|
+
yp = type(y) if isinstance(y, Parent) else parent(y)
|
|
3083
|
+
raise CoercionException(
|
|
3084
|
+
_LazyString("Infinite loop in action of %s (parent %s) and %s (parent %s)!",
|
|
3085
|
+
(x, xp, y, yp), {}))
|
|
3086
|
+
_coerce_test_dict[both] = True
|
|
3087
|
+
return 0
|
|
3088
|
+
|
|
3089
|
+
cdef bint _unregister_pair(x, y, tag) except -1:
|
|
3090
|
+
try:
|
|
3091
|
+
_coerce_test_dict.pop(EltPair(x, y, tag), None)
|
|
3092
|
+
except (ValueError, CoercionException):
|
|
3093
|
+
pass
|