passagemath-objects 10.6.41__cp314-cp314t-macosx_13_0_arm64.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.

Files changed (280) hide show
  1. passagemath_objects/.dylibs/libgmp.10.dylib +0 -0
  2. passagemath_objects/__init__.py +3 -0
  3. passagemath_objects-10.6.41.dist-info/METADATA +115 -0
  4. passagemath_objects-10.6.41.dist-info/RECORD +280 -0
  5. passagemath_objects-10.6.41.dist-info/WHEEL +6 -0
  6. passagemath_objects-10.6.41.dist-info/top_level.txt +3 -0
  7. sage/all__sagemath_objects.py +37 -0
  8. sage/arith/all__sagemath_objects.py +5 -0
  9. sage/arith/long.pxd +411 -0
  10. sage/arith/numerical_approx.cpython-314t-darwin.so +0 -0
  11. sage/arith/numerical_approx.pxd +35 -0
  12. sage/arith/numerical_approx.pyx +75 -0
  13. sage/arith/power.cpython-314t-darwin.so +0 -0
  14. sage/arith/power.pxd +31 -0
  15. sage/arith/power.pyx +127 -0
  16. sage/categories/action.cpython-314t-darwin.so +0 -0
  17. sage/categories/action.pxd +29 -0
  18. sage/categories/action.pyx +641 -0
  19. sage/categories/algebra_functor.py +745 -0
  20. sage/categories/all__sagemath_objects.py +33 -0
  21. sage/categories/basic.py +62 -0
  22. sage/categories/cartesian_product.py +295 -0
  23. sage/categories/category.py +3401 -0
  24. sage/categories/category_cy_helper.cpython-314t-darwin.so +0 -0
  25. sage/categories/category_cy_helper.pxd +8 -0
  26. sage/categories/category_cy_helper.pyx +322 -0
  27. sage/categories/category_singleton.cpython-314t-darwin.so +0 -0
  28. sage/categories/category_singleton.pxd +3 -0
  29. sage/categories/category_singleton.pyx +342 -0
  30. sage/categories/category_types.py +637 -0
  31. sage/categories/category_with_axiom.py +2876 -0
  32. sage/categories/covariant_functorial_construction.py +703 -0
  33. sage/categories/facade_sets.py +228 -0
  34. sage/categories/functor.cpython-314t-darwin.so +0 -0
  35. sage/categories/functor.pxd +7 -0
  36. sage/categories/functor.pyx +691 -0
  37. sage/categories/homset.py +1338 -0
  38. sage/categories/homsets.py +364 -0
  39. sage/categories/isomorphic_objects.py +73 -0
  40. sage/categories/map.cpython-314t-darwin.so +0 -0
  41. sage/categories/map.pxd +34 -0
  42. sage/categories/map.pyx +2112 -0
  43. sage/categories/morphism.cpython-314t-darwin.so +0 -0
  44. sage/categories/morphism.pxd +14 -0
  45. sage/categories/morphism.pyx +895 -0
  46. sage/categories/objects.py +167 -0
  47. sage/categories/primer.py +1696 -0
  48. sage/categories/pushout.py +4834 -0
  49. sage/categories/quotients.py +64 -0
  50. sage/categories/realizations.py +200 -0
  51. sage/categories/sets_cat.py +3228 -0
  52. sage/categories/sets_with_partial_maps.py +52 -0
  53. sage/categories/subobjects.py +64 -0
  54. sage/categories/subquotients.py +21 -0
  55. sage/categories/with_realizations.py +311 -0
  56. sage/cpython/__init__.py +19 -0
  57. sage/cpython/_py2_random.py +619 -0
  58. sage/cpython/all.py +3 -0
  59. sage/cpython/atexit.cpython-314t-darwin.so +0 -0
  60. sage/cpython/atexit.pyx +269 -0
  61. sage/cpython/builtin_types.cpython-314t-darwin.so +0 -0
  62. sage/cpython/builtin_types.pyx +7 -0
  63. sage/cpython/cython_metaclass.cpython-314t-darwin.so +0 -0
  64. sage/cpython/cython_metaclass.h +117 -0
  65. sage/cpython/cython_metaclass.pxd +3 -0
  66. sage/cpython/cython_metaclass.pyx +130 -0
  67. sage/cpython/debug.cpython-314t-darwin.so +0 -0
  68. sage/cpython/debug.pyx +302 -0
  69. sage/cpython/dict_del_by_value.cpython-314t-darwin.so +0 -0
  70. sage/cpython/dict_del_by_value.pxd +9 -0
  71. sage/cpython/dict_del_by_value.pyx +191 -0
  72. sage/cpython/dict_internal.h +245 -0
  73. sage/cpython/getattr.cpython-314t-darwin.so +0 -0
  74. sage/cpython/getattr.pxd +9 -0
  75. sage/cpython/getattr.pyx +439 -0
  76. sage/cpython/pycore_long.h +97 -0
  77. sage/cpython/pycore_long.pxd +10 -0
  78. sage/cpython/python_debug.h +44 -0
  79. sage/cpython/python_debug.pxd +47 -0
  80. sage/cpython/pyx_visit.h +13 -0
  81. sage/cpython/string.cpython-314t-darwin.so +0 -0
  82. sage/cpython/string.pxd +76 -0
  83. sage/cpython/string.pyx +34 -0
  84. sage/cpython/string_impl.h +60 -0
  85. sage/cpython/type.cpython-314t-darwin.so +0 -0
  86. sage/cpython/type.pxd +2 -0
  87. sage/cpython/type.pyx +40 -0
  88. sage/cpython/wrapperdescr.pxd +67 -0
  89. sage/ext/all__sagemath_objects.py +3 -0
  90. sage/ext/ccobject.h +64 -0
  91. sage/ext/cplusplus.pxd +17 -0
  92. sage/ext/mod_int.h +30 -0
  93. sage/ext/mod_int.pxd +24 -0
  94. sage/ext/stdsage.pxd +39 -0
  95. sage/groups/all__sagemath_objects.py +1 -0
  96. sage/groups/group.cpython-314t-darwin.so +0 -0
  97. sage/groups/group.pxd +14 -0
  98. sage/groups/group.pyx +322 -0
  99. sage/groups/old.cpython-314t-darwin.so +0 -0
  100. sage/groups/old.pxd +14 -0
  101. sage/groups/old.pyx +219 -0
  102. sage/libs/all__sagemath_objects.py +3 -0
  103. sage/libs/gmp/__init__.py +1 -0
  104. sage/libs/gmp/all.pxd +6 -0
  105. sage/libs/gmp/binop.pxd +23 -0
  106. sage/libs/gmp/misc.pxd +8 -0
  107. sage/libs/gmp/mpf.pxd +88 -0
  108. sage/libs/gmp/mpn.pxd +57 -0
  109. sage/libs/gmp/mpq.pxd +57 -0
  110. sage/libs/gmp/mpz.pxd +202 -0
  111. sage/libs/gmp/pylong.cpython-314t-darwin.so +0 -0
  112. sage/libs/gmp/pylong.pxd +12 -0
  113. sage/libs/gmp/pylong.pyx +150 -0
  114. sage/libs/gmp/random.pxd +25 -0
  115. sage/libs/gmp/randomize.pxd +59 -0
  116. sage/libs/gmp/types.pxd +53 -0
  117. sage/libs/gmpxx.pxd +19 -0
  118. sage/misc/abstract_method.py +276 -0
  119. sage/misc/all__sagemath_objects.py +43 -0
  120. sage/misc/bindable_class.py +253 -0
  121. sage/misc/c3_controlled.cpython-314t-darwin.so +0 -0
  122. sage/misc/c3_controlled.pxd +2 -0
  123. sage/misc/c3_controlled.pyx +1402 -0
  124. sage/misc/cachefunc.cpython-314t-darwin.so +0 -0
  125. sage/misc/cachefunc.pxd +43 -0
  126. sage/misc/cachefunc.pyx +3781 -0
  127. sage/misc/call.py +188 -0
  128. sage/misc/classcall_metaclass.cpython-314t-darwin.so +0 -0
  129. sage/misc/classcall_metaclass.pxd +14 -0
  130. sage/misc/classcall_metaclass.pyx +599 -0
  131. sage/misc/constant_function.cpython-314t-darwin.so +0 -0
  132. sage/misc/constant_function.pyx +130 -0
  133. sage/misc/decorators.py +747 -0
  134. sage/misc/fast_methods.cpython-314t-darwin.so +0 -0
  135. sage/misc/fast_methods.pxd +20 -0
  136. sage/misc/fast_methods.pyx +351 -0
  137. sage/misc/flatten.py +90 -0
  138. sage/misc/fpickle.cpython-314t-darwin.so +0 -0
  139. sage/misc/fpickle.pyx +177 -0
  140. sage/misc/function_mangling.cpython-314t-darwin.so +0 -0
  141. sage/misc/function_mangling.pxd +11 -0
  142. sage/misc/function_mangling.pyx +308 -0
  143. sage/misc/inherit_comparison.cpython-314t-darwin.so +0 -0
  144. sage/misc/inherit_comparison.pxd +5 -0
  145. sage/misc/inherit_comparison.pyx +105 -0
  146. sage/misc/instancedoc.cpython-314t-darwin.so +0 -0
  147. sage/misc/instancedoc.pyx +331 -0
  148. sage/misc/lazy_attribute.cpython-314t-darwin.so +0 -0
  149. sage/misc/lazy_attribute.pyx +607 -0
  150. sage/misc/lazy_format.py +135 -0
  151. sage/misc/lazy_import.cpython-314t-darwin.so +0 -0
  152. sage/misc/lazy_import.pyx +1299 -0
  153. sage/misc/lazy_import_cache.py +36 -0
  154. sage/misc/lazy_list.cpython-314t-darwin.so +0 -0
  155. sage/misc/lazy_list.pxd +19 -0
  156. sage/misc/lazy_list.pyx +1187 -0
  157. sage/misc/lazy_string.cpython-314t-darwin.so +0 -0
  158. sage/misc/lazy_string.pxd +7 -0
  159. sage/misc/lazy_string.pyx +546 -0
  160. sage/misc/misc.py +1066 -0
  161. sage/misc/misc_c.cpython-314t-darwin.so +0 -0
  162. sage/misc/misc_c.pxd +3 -0
  163. sage/misc/misc_c.pyx +766 -0
  164. sage/misc/namespace_package.py +37 -0
  165. sage/misc/nested_class.cpython-314t-darwin.so +0 -0
  166. sage/misc/nested_class.pxd +3 -0
  167. sage/misc/nested_class.pyx +394 -0
  168. sage/misc/persist.cpython-314t-darwin.so +0 -0
  169. sage/misc/persist.pyx +1251 -0
  170. sage/misc/prandom.py +418 -0
  171. sage/misc/randstate.cpython-314t-darwin.so +0 -0
  172. sage/misc/randstate.pxd +30 -0
  173. sage/misc/randstate.pyx +1059 -0
  174. sage/misc/repr.py +203 -0
  175. sage/misc/reset.cpython-314t-darwin.so +0 -0
  176. sage/misc/reset.pyx +196 -0
  177. sage/misc/sage_ostools.cpython-314t-darwin.so +0 -0
  178. sage/misc/sage_ostools.pyx +323 -0
  179. sage/misc/sage_timeit.py +276 -0
  180. sage/misc/sage_timeit_class.cpython-314t-darwin.so +0 -0
  181. sage/misc/sage_timeit_class.pyx +120 -0
  182. sage/misc/sage_unittest.py +637 -0
  183. sage/misc/sageinspect.py +2768 -0
  184. sage/misc/session.cpython-314t-darwin.so +0 -0
  185. sage/misc/session.pyx +392 -0
  186. sage/misc/superseded.py +557 -0
  187. sage/misc/test_nested_class.py +228 -0
  188. sage/misc/timing.py +264 -0
  189. sage/misc/unknown.py +222 -0
  190. sage/misc/verbose.py +253 -0
  191. sage/misc/weak_dict.cpython-314t-darwin.so +0 -0
  192. sage/misc/weak_dict.pxd +15 -0
  193. sage/misc/weak_dict.pyx +1231 -0
  194. sage/modules/all__sagemath_objects.py +1 -0
  195. sage/modules/module.cpython-314t-darwin.so +0 -0
  196. sage/modules/module.pxd +5 -0
  197. sage/modules/module.pyx +329 -0
  198. sage/rings/all__sagemath_objects.py +3 -0
  199. sage/rings/integer_fake.h +22 -0
  200. sage/rings/integer_fake.pxd +55 -0
  201. sage/sets/all__sagemath_objects.py +3 -0
  202. sage/sets/pythonclass.cpython-314t-darwin.so +0 -0
  203. sage/sets/pythonclass.pxd +9 -0
  204. sage/sets/pythonclass.pyx +247 -0
  205. sage/structure/__init__.py +4 -0
  206. sage/structure/all.py +30 -0
  207. sage/structure/category_object.cpython-314t-darwin.so +0 -0
  208. sage/structure/category_object.pxd +28 -0
  209. sage/structure/category_object.pyx +1087 -0
  210. sage/structure/coerce.cpython-314t-darwin.so +0 -0
  211. sage/structure/coerce.pxd +44 -0
  212. sage/structure/coerce.pyx +2107 -0
  213. sage/structure/coerce_actions.cpython-314t-darwin.so +0 -0
  214. sage/structure/coerce_actions.pxd +27 -0
  215. sage/structure/coerce_actions.pyx +988 -0
  216. sage/structure/coerce_dict.cpython-314t-darwin.so +0 -0
  217. sage/structure/coerce_dict.pxd +51 -0
  218. sage/structure/coerce_dict.pyx +1557 -0
  219. sage/structure/coerce_exceptions.py +23 -0
  220. sage/structure/coerce_maps.cpython-314t-darwin.so +0 -0
  221. sage/structure/coerce_maps.pxd +28 -0
  222. sage/structure/coerce_maps.pyx +718 -0
  223. sage/structure/debug_options.cpython-314t-darwin.so +0 -0
  224. sage/structure/debug_options.pxd +6 -0
  225. sage/structure/debug_options.pyx +54 -0
  226. sage/structure/dynamic_class.py +541 -0
  227. sage/structure/element.cpython-314t-darwin.so +0 -0
  228. sage/structure/element.pxd +272 -0
  229. sage/structure/element.pyx +4772 -0
  230. sage/structure/element_wrapper.cpython-314t-darwin.so +0 -0
  231. sage/structure/element_wrapper.pxd +12 -0
  232. sage/structure/element_wrapper.pyx +582 -0
  233. sage/structure/factorization.py +1422 -0
  234. sage/structure/factorization_integer.py +105 -0
  235. sage/structure/factory.cpython-314t-darwin.so +0 -0
  236. sage/structure/factory.pyx +786 -0
  237. sage/structure/formal_sum.py +489 -0
  238. sage/structure/gens_py.py +73 -0
  239. sage/structure/global_options.py +1743 -0
  240. sage/structure/indexed_generators.py +863 -0
  241. sage/structure/list_clone.cpython-314t-darwin.so +0 -0
  242. sage/structure/list_clone.pxd +65 -0
  243. sage/structure/list_clone.pyx +1867 -0
  244. sage/structure/list_clone_demo.cpython-314t-darwin.so +0 -0
  245. sage/structure/list_clone_demo.pyx +248 -0
  246. sage/structure/list_clone_timings.py +179 -0
  247. sage/structure/list_clone_timings_cy.cpython-314t-darwin.so +0 -0
  248. sage/structure/list_clone_timings_cy.pyx +86 -0
  249. sage/structure/mutability.cpython-314t-darwin.so +0 -0
  250. sage/structure/mutability.pxd +21 -0
  251. sage/structure/mutability.pyx +348 -0
  252. sage/structure/nonexact.py +69 -0
  253. sage/structure/parent.cpython-314t-darwin.so +0 -0
  254. sage/structure/parent.pxd +112 -0
  255. sage/structure/parent.pyx +3093 -0
  256. sage/structure/parent_base.cpython-314t-darwin.so +0 -0
  257. sage/structure/parent_base.pxd +13 -0
  258. sage/structure/parent_base.pyx +44 -0
  259. sage/structure/parent_gens.cpython-314t-darwin.so +0 -0
  260. sage/structure/parent_gens.pxd +22 -0
  261. sage/structure/parent_gens.pyx +377 -0
  262. sage/structure/parent_old.cpython-314t-darwin.so +0 -0
  263. sage/structure/parent_old.pxd +25 -0
  264. sage/structure/parent_old.pyx +294 -0
  265. sage/structure/proof/__init__.py +1 -0
  266. sage/structure/proof/all.py +243 -0
  267. sage/structure/proof/proof.py +300 -0
  268. sage/structure/richcmp.cpython-314t-darwin.so +0 -0
  269. sage/structure/richcmp.pxd +213 -0
  270. sage/structure/richcmp.pyx +495 -0
  271. sage/structure/sage_object.cpython-314t-darwin.so +0 -0
  272. sage/structure/sage_object.pxd +3 -0
  273. sage/structure/sage_object.pyx +988 -0
  274. sage/structure/sage_object_test.py +19 -0
  275. sage/structure/sequence.py +937 -0
  276. sage/structure/set_factories.py +1178 -0
  277. sage/structure/set_factories_example.py +527 -0
  278. sage/structure/support_view.py +179 -0
  279. sage/structure/test_factory.py +56 -0
  280. sage/structure/unique_representation.py +1359 -0
@@ -0,0 +1,2112 @@
1
+ # sage_setup: distribution = sagemath-objects
2
+ r"""
3
+ Base class for maps
4
+
5
+ AUTHORS:
6
+
7
+ - Robert Bradshaw: initial implementation
8
+
9
+ - Sebastien Besnier (2014-05-5): :class:`FormalCompositeMap` contains
10
+ a list of Map instead of only two Map. See :issue:`16291`.
11
+
12
+ - Sebastian Oehms (2019-01-19): :meth:`section` added to :class:`FormalCompositeMap`.
13
+ See :issue:`27081`.
14
+ """
15
+ # ****************************************************************************
16
+ # Copyright (C) 2008 Robert Bradshaw <robertwb@math.washington.edu>
17
+ #
18
+ # This program is free software: you can redistribute it and/or modify
19
+ # it under the terms of the GNU General Public License as published by
20
+ # the Free Software Foundation, either version 2 of the License, or
21
+ # (at your option) any later version.
22
+ # https://www.gnu.org/licenses/
23
+ # ****************************************************************************
24
+
25
+ from sage.categories import homset
26
+ import weakref
27
+ from sage.ext.stdsage cimport HAS_DICTIONARY
28
+ from sage.arith.power cimport generic_power
29
+ from sage.sets.pythonclass cimport Set_PythonType
30
+ from sage.misc.constant_function import ConstantFunction
31
+ from sage.structure.element cimport parent
32
+ from cpython.object cimport PyObject_RichCompare
33
+
34
+
35
+ def unpickle_map(_class, parent, _dict, _slots):
36
+ """
37
+ Auxiliary function for unpickling a map.
38
+
39
+ TESTS::
40
+
41
+ sage: R.<x,y> = QQ[]
42
+ sage: f = R.hom([x+y, x-y], R)
43
+ sage: f == loads(dumps(f)) # indirect doctest
44
+ True
45
+ """
46
+ # should we use slots?
47
+ # from element.pyx
48
+ cdef Map mor = _class.__new__(_class)
49
+ mor._set_parent(parent)
50
+ mor._update_slots(_slots)
51
+ if HAS_DICTIONARY(mor):
52
+ mor.__dict__ = _dict
53
+ return mor
54
+
55
+
56
+ def is_Map(x):
57
+ """
58
+ Auxiliary function: Is the argument a map?
59
+
60
+ EXAMPLES::
61
+
62
+ sage: R.<x,y> = QQ[]
63
+ sage: f = R.hom([x+y, x-y], R)
64
+ sage: from sage.categories.map import is_Map
65
+ sage: is_Map(f)
66
+ doctest:warning...
67
+ DeprecationWarning: The function is_Map is deprecated; use 'isinstance(..., Map)' instead.
68
+ See https://github.com/sagemath/sage/issues/38103 for details.
69
+ True
70
+ """
71
+ from sage.misc.superseded import deprecation_cython
72
+ deprecation_cython(38103, "The function is_Map is deprecated; use 'isinstance(..., Map)' instead.")
73
+ return isinstance(x, Map)
74
+
75
+
76
+ cdef class Map(Element):
77
+ """
78
+ Basic class for all maps.
79
+
80
+ .. NOTE::
81
+
82
+ The call method is of course not implemented in this base class. This must
83
+ be done in the sub classes, by overloading ``_call_`` and possibly also
84
+ ``_call_with_args``.
85
+
86
+ EXAMPLES:
87
+
88
+ Usually, instances of this class will not be constructed directly, but
89
+ for example like this::
90
+
91
+ sage: from sage.categories.morphism import SetMorphism
92
+ sage: X.<x> = ZZ[]
93
+ sage: Y = ZZ
94
+ sage: phi = SetMorphism(Hom(X, Y, Rings()), lambda p: p[0])
95
+ sage: phi(x^2+2*x-1)
96
+ -1
97
+ sage: R.<x,y> = QQ[]
98
+ sage: f = R.hom([x+y, x-y], R)
99
+ sage: f(x^2+2*x-1)
100
+ x^2 + 2*x*y + y^2 + 2*x + 2*y - 1
101
+ """
102
+
103
+ def __init__(self, parent, codomain=None):
104
+ """
105
+ INPUT:
106
+
107
+ There can be one or two arguments of this init method. If it is one argument,
108
+ it must be a hom space. If it is two arguments, it must be two parent structures
109
+ that will be domain and codomain of the map-to-be-created.
110
+
111
+ TESTS::
112
+
113
+ sage: from sage.categories.map import Map
114
+
115
+ Using a hom space::
116
+
117
+ sage: Map(Hom(QQ, ZZ, Rings()))
118
+ Generic map:
119
+ From: Rational Field
120
+ To: Integer Ring
121
+
122
+ Using domain and codomain::
123
+
124
+ sage: Map(QQ['x'], SymmetricGroup(6)) # needs sage.groups
125
+ Generic map:
126
+ From: Univariate Polynomial Ring in x over Rational Field
127
+ To: Symmetric group of order 6! as a permutation group
128
+ """
129
+ if codomain is not None:
130
+ if isinstance(parent, type):
131
+ parent = Set_PythonType(parent)
132
+ parent = homset.Hom(parent, codomain)
133
+ elif not isinstance(parent, homset.Homset):
134
+ raise TypeError("parent (=%s) must be a Homspace" % parent)
135
+ Element.__init__(self, parent)
136
+ D = parent.domain()
137
+ C = parent.codomain()
138
+ self._category_for = parent.homset_category()
139
+ self._codomain = C
140
+ self.domain = ConstantFunction(D)
141
+ self.codomain = ConstantFunction(C)
142
+ self._is_coercion = False
143
+ if D.is_exact() and C.is_exact():
144
+ self._coerce_cost = 10 # default value.
145
+ else:
146
+ self._coerce_cost = 10000 # inexact morphisms are bad.
147
+
148
+ def __copy__(self):
149
+ """
150
+ Return copy, with strong references to domain and codomain.
151
+
152
+ .. NOTE::
153
+
154
+ To implement copying on sub-classes, do not override this method, but
155
+ implement cdef methods ``_extra_slots()`` returning a dictionary and
156
+ ``_update_slots()`` using this dictionary to fill the cdef or cpdef
157
+ slots of the subclass.
158
+
159
+ EXAMPLES::
160
+
161
+ sage: phi = QQ['x']._internal_coerce_map_from(ZZ)
162
+ sage: phi.domain
163
+ <weakref at ...; to 'sage.rings.integer_ring.IntegerRing_class' at ...>
164
+ sage: type(phi)
165
+ <class 'sage.categories.map.FormalCompositeMap'>
166
+ sage: psi = copy(phi) # indirect doctest
167
+ sage: psi
168
+ Composite map:
169
+ From: Integer Ring
170
+ To: Univariate Polynomial Ring in x over Rational Field
171
+ Defn: Natural morphism:
172
+ From: Integer Ring
173
+ To: Rational Field
174
+ then
175
+ Polynomial base injection morphism:
176
+ From: Rational Field
177
+ To: Univariate Polynomial Ring in x over Rational Field
178
+ sage: psi.domain
179
+ The constant function (...) -> Integer Ring
180
+ sage: psi(3)
181
+ 3
182
+ """
183
+ cdef Map out = Element.__copy__(self)
184
+ # Element.__copy__ updates the __dict__, but not the slots.
185
+ # Let's do this now, but with strong references.
186
+ out._parent = self.parent() # self._parent might be None
187
+ out._update_slots(self._extra_slots())
188
+ return out
189
+
190
+ def parent(self):
191
+ r"""
192
+ Return the homset containing this map.
193
+
194
+ .. NOTE::
195
+
196
+ The method :meth:`_make_weak_references`, that is used for the maps
197
+ found by the coercion system, needs to remove the usual strong
198
+ reference from the coercion map to the homset containing it. As long
199
+ as the user keeps strong references to domain and codomain of the map,
200
+ we will be able to reconstruct the homset. However, a strong reference
201
+ to the coercion map does not prevent the domain from garbage collection!
202
+
203
+ EXAMPLES::
204
+
205
+ sage: Q = QuadraticField(-5) # needs sage.rings.number_field
206
+ sage: phi = CDF._internal_convert_map_from(Q) # needs sage.rings.number_field
207
+ sage: print(phi.parent()) # needs sage.rings.number_field
208
+ Set of field embeddings
209
+ from Number Field in a with defining polynomial x^2 + 5
210
+ with a = 2.236067977499790?*I
211
+ to Complex Double Field
212
+
213
+ We now demonstrate that the reference to the coercion map `\phi` does
214
+ not prevent `Q` from being garbage collected::
215
+
216
+ sage: import gc
217
+ sage: del Q # needs sage.rings.number_field
218
+ sage: _ = gc.collect()
219
+ sage: phi.parent() # needs sage.rings.number_field
220
+ Traceback (most recent call last):
221
+ ...
222
+ ValueError: This map is in an invalid state,
223
+ the domain has been garbage collected
224
+
225
+ You can still obtain copies of the maps used by the coercion system with
226
+ strong references::
227
+
228
+ sage: # needs sage.rings.number_field
229
+ sage: Q = QuadraticField(-5)
230
+ sage: phi = CDF.convert_map_from(Q)
231
+ sage: print(phi.parent())
232
+ Set of field embeddings
233
+ from Number Field in a with defining polynomial x^2 + 5
234
+ with a = 2.236067977499790?*I
235
+ to Complex Double Field
236
+ sage: import gc
237
+ sage: del Q
238
+ sage: _ = gc.collect()
239
+ sage: phi.parent()
240
+ Set of field embeddings
241
+ from Number Field in a with defining polynomial x^2 + 5
242
+ with a = 2.236067977499790?*I
243
+ to Complex Double Field
244
+ """
245
+ if self._parent is None:
246
+ D = self.domain()
247
+ C = self._codomain
248
+ if C is None or D is None:
249
+ raise ValueError("This map is in an invalid state, the domain has been garbage collected")
250
+ return homset.Hom(D, C, self._category_for)
251
+ return self._parent
252
+
253
+ def _make_weak_references(self):
254
+ """
255
+ Only store weak references to domain and codomain of this map.
256
+
257
+ .. NOTE::
258
+
259
+ This method is internally used on maps that are used for coercions
260
+ or conversions between parents. Without using this method, some objects
261
+ would stay alive indefinitely as soon as they are involved in a coercion
262
+ or conversion.
263
+
264
+ .. SEEALSO::
265
+
266
+ :meth:`_make_strong_references`
267
+
268
+ EXAMPLES::
269
+
270
+ sage: Q = QuadraticField(-5) # needs sage.rings.number_field
271
+ sage: phi = CDF._internal_convert_map_from(Q) # needs sage.rings.number_field
272
+
273
+ By :issue:`14711`, maps used in the coercion and conversion system
274
+ use *weak* references to domain and codomain, in contrast to other
275
+ maps::
276
+
277
+ sage: phi.domain # needs sage.rings.number_field
278
+ <weakref at ...; to '...NumberField_quadratic_with_category' at ...>
279
+ sage: phi._make_strong_references() # needs sage.rings.number_field
280
+ sage: print(phi.domain) # needs sage.rings.number_field
281
+ The constant function (...) -> Number Field in a
282
+ with defining polynomial x^2 + 5 with a = 2.236067977499790?*I
283
+
284
+ Now, as there is a strong reference, `Q` cannot be garbage collected::
285
+
286
+ sage: # needs sage.rings.number_field
287
+ sage: import gc
288
+ sage: _ = gc.collect()
289
+ sage: C = Q.__class__.__base__
290
+ sage: x = None
291
+ sage: numberQuadFields = len([x for x in gc.get_objects()
292
+ ....: if isinstance(x, C)])
293
+ sage: del Q, x
294
+ sage: _ = gc.collect()
295
+ sage: numberQuadFields == len([x for x in gc.get_objects()
296
+ ....: if isinstance(x, C)])
297
+ True
298
+
299
+ However, if we now make the references weak again, the number field can
300
+ be garbage collected, which of course makes the map and its parents
301
+ invalid. This is why :meth:`_make_weak_references` should only be used
302
+ if one really knows what one is doing::
303
+
304
+ sage: # needs sage.rings.number_field
305
+ sage: phi._make_weak_references()
306
+ sage: _ = gc.collect()
307
+ sage: numberQuadFields == len([x for x in gc.get_objects()
308
+ ....: if isinstance(x, C)]) + 1
309
+ True
310
+ sage: phi
311
+ Defunct map
312
+ """
313
+ if not isinstance(self.domain, ConstantFunction):
314
+ return
315
+ self.domain = weakref.ref(self.domain())
316
+ # Save the category before clearing the parent.
317
+ self._category_for = self._parent.homset_category()
318
+ self._parent = None
319
+
320
+ def _make_strong_references(self):
321
+ """
322
+ Store strong references to domain and codomain of this map.
323
+
324
+ .. NOTE::
325
+
326
+ By default, maps keep strong references to domain and codomain,
327
+ preventing them thus from garbage collection. However, in Sage's
328
+ coercion system, these strong references are replaced by weak
329
+ references, since otherwise some objects would stay alive indefinitely
330
+ as soon as they are involved in a coercion or conversion.
331
+
332
+ .. SEEALSO::
333
+
334
+ :meth:`_make_weak_references`
335
+
336
+ EXAMPLES::
337
+
338
+ sage: Q = QuadraticField(-5) # needs sage.rings.number_field
339
+ sage: phi = CDF._internal_convert_map_from(Q) # needs sage.rings.number_field
340
+
341
+ By :issue:`14711`, maps used in the coercion and conversion system
342
+ use *weak* references to domain and codomain, in contrast to other
343
+ maps::
344
+
345
+ sage: phi.domain # needs sage.rings.number_field
346
+ <weakref at ...; to '...NumberField_quadratic_with_category' at ...>
347
+ sage: phi._make_strong_references() # needs sage.rings.number_field
348
+ sage: print(phi.domain) # needs sage.rings.number_field
349
+ The constant function (...) -> Number Field in a
350
+ with defining polynomial x^2 + 5 with a = 2.236067977499790?*I
351
+
352
+ Now, as there is a strong reference, `Q` cannot be garbage collected::
353
+
354
+ sage: # needs sage.rings.number_field
355
+ sage: import gc
356
+ sage: _ = gc.collect()
357
+ sage: C = Q.__class__.__base__
358
+ sage: x = None
359
+ sage: numberQuadFields = len([x for x in gc.get_objects()
360
+ ....: if isinstance(x, C)])
361
+ sage: del Q, x
362
+ sage: _ = gc.collect()
363
+ sage: numberQuadFields == len([x for x in gc.get_objects()
364
+ ....: if isinstance(x, C)])
365
+ True
366
+
367
+ However, if we now make the references weak again, the number field can
368
+ be garbage collected, which of course makes the map and its parents
369
+ invalid. This is why :meth:`_make_weak_references` should only be used
370
+ if one really knows what one is doing::
371
+
372
+ sage: # needs sage.rings.number_field
373
+ sage: phi._make_weak_references()
374
+ sage: _ = gc.collect()
375
+ sage: numberQuadFields == len([x for x in gc.get_objects()
376
+ ....: if isinstance(x, C)]) + 1
377
+ True
378
+ sage: phi
379
+ Defunct map
380
+ sage: phi._make_strong_references()
381
+ Traceback (most recent call last):
382
+ ...
383
+ RuntimeError: The domain of this map became garbage collected
384
+ sage: phi.parent()
385
+ Traceback (most recent call last):
386
+ ...
387
+ ValueError: This map is in an invalid state, the domain has been garbage collected
388
+ """
389
+ if isinstance(self.domain, ConstantFunction):
390
+ return
391
+ D = self.domain()
392
+ C = self._codomain
393
+ if D is None or C is None:
394
+ raise RuntimeError("The domain of this map became garbage collected")
395
+ self.domain = ConstantFunction(D)
396
+ self._parent = homset.Hom(D, C, self._category_for)
397
+
398
+ cdef _update_slots(self, dict slots):
399
+ """
400
+ Set various attributes of this map to implement unpickling.
401
+
402
+ INPUT:
403
+
404
+ - ``slots`` -- dictionary of slots to be updated;
405
+ the dictionary must have the keys ``'_domain'`` and
406
+ ``'_codomain'``, and may have the keys ``'_repr_type_str'``
407
+ and ``'_is_coercion'``
408
+
409
+ TESTS:
410
+
411
+ Since it is a ``cdef``d method, it is tested using a dummy python method.
412
+ ::
413
+
414
+ sage: # needs sage.rings.real_mpfr
415
+ sage: from sage.categories.map import Map
416
+ sage: f = Map(Hom(QQ, ZZ, Rings()))
417
+ sage: f._update_slots_test({"_domain": RR, "_codomain": QQ}) # indirect doctest
418
+ sage: f.domain()
419
+ Real Field with 53 bits of precision
420
+ sage: f.codomain()
421
+ Rational Field
422
+ sage: f._repr_type_str
423
+ sage: f._update_slots_test({"_repr_type_str": "bla", "_domain": RR, "_codomain": QQ})
424
+ sage: f._repr_type_str
425
+ 'bla'
426
+ """
427
+ # todo: the following can break during unpickling of complex
428
+ # objects with circular references! In that case, _slots might
429
+ # contain incomplete objects.
430
+ self.domain = ConstantFunction(slots['_domain'])
431
+ self._codomain = slots['_codomain']
432
+ self.codomain = ConstantFunction(self._codomain)
433
+
434
+ # Several pickles exist without the following, so these are
435
+ # optional
436
+ self._repr_type_str = slots.get('_repr_type_str')
437
+ self._is_coercion = slots.get('_is_coercion')
438
+
439
+ def _update_slots_test(self, _slots):
440
+ """
441
+ A Python method to test the cdef _update_slots method.
442
+
443
+ TESTS::
444
+
445
+ sage: # needs sage.rings.real_mpfr
446
+ sage: from sage.categories.map import Map
447
+ sage: f = Map(Hom(QQ, ZZ, Rings()))
448
+ sage: f._update_slots_test({"_domain": RR, "_codomain": QQ})
449
+ sage: f.domain()
450
+ Real Field with 53 bits of precision
451
+ sage: f.codomain()
452
+ Rational Field
453
+ sage: f._repr_type_str
454
+ sage: f._update_slots_test({"_repr_type_str": "bla", "_domain": RR, "_codomain": QQ})
455
+ sage: f._repr_type_str
456
+ 'bla'
457
+ """
458
+ self._update_slots(_slots)
459
+
460
+ cdef dict _extra_slots(self):
461
+ """
462
+ Return a dict with attributes to pickle and copy this map.
463
+ """
464
+ return dict(
465
+ _domain=self.domain(),
466
+ _codomain=self._codomain,
467
+ _is_coercion=self._is_coercion,
468
+ _repr_type_str=self._repr_type_str)
469
+
470
+ def _extra_slots_test(self):
471
+ """
472
+ A Python method to test the cdef _extra_slots method.
473
+
474
+ TESTS::
475
+
476
+ sage: from sage.categories.map import Map
477
+ sage: f = Map(Hom(QQ, ZZ, Rings()))
478
+ sage: f._extra_slots_test()
479
+ {'_codomain': Integer Ring,
480
+ '_domain': Rational Field,
481
+ '_is_coercion': False,
482
+ '_repr_type_str': None}
483
+ """
484
+ return self._extra_slots()
485
+
486
+ def __reduce__(self):
487
+ """
488
+ TESTS::
489
+
490
+ sage: from sage.categories.map import Map
491
+ sage: f = Map(Hom(QQ, ZZ, Rings())); f
492
+ Generic map:
493
+ From: Rational Field
494
+ To: Integer Ring
495
+ sage: loads(dumps(f)) # indirect doctest
496
+ Generic map:
497
+ From: Rational Field
498
+ To: Integer Ring
499
+ """
500
+ if HAS_DICTIONARY(self):
501
+ _dict = self.__dict__
502
+ else:
503
+ _dict = {}
504
+ return unpickle_map, (type(self), self.parent(), _dict, self._extra_slots())
505
+
506
+ def _repr_type(self):
507
+ """
508
+ Return a string describing the specific type of this map, to be used when printing ``self``.
509
+
510
+ .. NOTE::
511
+
512
+ By default, the string ``'Generic'`` is returned. Subclasses may overload this method.
513
+
514
+ EXAMPLES::
515
+
516
+ sage: from sage.categories.map import Map
517
+ sage: f = Map(Hom(QQ, ZZ, Rings()))
518
+ sage: print(f._repr_type())
519
+ Generic
520
+ sage: R.<x,y> = QQ[]
521
+ sage: phi = R.hom([x+y, x-y], R)
522
+ sage: print(phi._repr_type())
523
+ Ring
524
+ """
525
+ if self._repr_type_str is None:
526
+ return "Generic"
527
+ else:
528
+ return self._repr_type_str
529
+
530
+ def _repr_defn(self):
531
+ """
532
+ Return a string describing the definition of ``self``, to be used when printing ``self``.
533
+
534
+ .. NOTE::
535
+
536
+ By default, the empty string is returned. Subclasses may overload this method.
537
+
538
+ EXAMPLES::
539
+
540
+ sage: from sage.categories.map import Map
541
+ sage: f = Map(Hom(QQ, ZZ, Rings()))
542
+ sage: f._repr_defn() == ''
543
+ True
544
+ sage: R.<x,y> = QQ[]
545
+ sage: f = R.hom([x+y, x-y], R)
546
+ sage: print(f._repr_defn())
547
+ x |--> x + y
548
+ y |--> x - y
549
+ """
550
+ return ""
551
+
552
+ def _repr_(self):
553
+ """
554
+ .. NOTE::
555
+
556
+ The string representation is based on the strings returned by
557
+ :meth:`_repr_defn` and :meth:`_repr_type`, as well as the domain
558
+ and the codomain.
559
+
560
+ A map that has been subject to :meth:`_make_weak_references` has
561
+ probably been used internally in the coercion system. Hence, it
562
+ may become defunct by garbage collection of the domain. In this
563
+ case, a warning is printed accordingly.
564
+
565
+ EXAMPLES::
566
+
567
+ sage: from sage.categories.map import Map
568
+ sage: Map(Hom(QQ, ZZ, Rings())) # indirect doctest
569
+ Generic map:
570
+ From: Rational Field
571
+ To: Integer Ring
572
+ sage: R.<x,y> = QQ[]
573
+ sage: R.hom([x+y, x-y], R)
574
+ Ring endomorphism of Multivariate Polynomial Ring in x, y over Rational Field
575
+ Defn: x |--> x + y
576
+ y |--> x - y
577
+
578
+ TESTS::
579
+
580
+ sage: # needs sage.rings.number_field
581
+ sage: Q = QuadraticField(-5)
582
+ sage: phi = CDF._internal_coerce_map_from(Q); phi
583
+ (map internal to coercion system -- copy before use)
584
+ Composite map:
585
+ From: Number Field in a with defining polynomial x^2 + 5 with a = 2.236067977499790?*I
586
+ To: Complex Double Field
587
+ sage: del Q
588
+ sage: import gc
589
+ sage: _ = gc.collect()
590
+ sage: phi
591
+ Defunct map
592
+ """
593
+ D = self.domain()
594
+ if D is None:
595
+ return "Defunct map"
596
+ s = "%s map:" % self._repr_type()
597
+ s += "\n From: %s" % D
598
+ s += "\n To: %s" % self._codomain
599
+ if isinstance(self.domain, ConstantFunction):
600
+ d = self._repr_defn()
601
+ if d != '':
602
+ s += "\n Defn: %s" % ('\n '.join(d.split('\n')))
603
+ else:
604
+ d = "(map internal to coercion system -- copy before use)"
605
+ s = d + "\n" + s
606
+ return s
607
+
608
+ def _default_repr_(self):
609
+ D = self.domain()
610
+ if D is None:
611
+ return "Defunct map"
612
+ s = "%s map:" % self._repr_type()
613
+ s += "\n From: %s" % D
614
+ s += "\n To: %s" % self._codomain
615
+ d = self._repr_defn()
616
+ if d != '':
617
+ s += "\n Defn: %s" % ('\n '.join(d.split('\n')))
618
+ return s
619
+
620
+ def domains(self):
621
+ """
622
+ Iterate over the domains of the factors of a (composite) map.
623
+
624
+ This default implementation simply yields the domain of this map.
625
+
626
+ .. SEEALSO:: :meth:`FormalCompositeMap.domains`
627
+
628
+ EXAMPLES::
629
+
630
+ sage: list(QQ.coerce_map_from(ZZ).domains())
631
+ [Integer Ring]
632
+ """
633
+ yield self.domain()
634
+
635
+ def category_for(self):
636
+ """
637
+ Return the category ``self`` is a morphism for.
638
+
639
+ .. NOTE::
640
+
641
+ This is different from the category of maps to which this
642
+ map belongs *as an object*.
643
+
644
+ EXAMPLES::
645
+
646
+ sage: from sage.categories.morphism import SetMorphism
647
+ sage: X.<x> = ZZ[]
648
+ sage: Y = ZZ
649
+ sage: phi = SetMorphism(Hom(X, Y, Rings()), lambda p: p[0])
650
+ sage: phi.category_for()
651
+ Category of rings
652
+ sage: phi.category()
653
+ Category of homsets of unital magmas and additive unital additive magmas
654
+ sage: R.<x,y> = QQ[]
655
+ sage: f = R.hom([x+y, x-y], R)
656
+ sage: f.category_for()
657
+ Join of Category of unique factorization domains
658
+ and Category of algebras with basis over
659
+ (number fields and quotient fields and metric spaces)
660
+ and Category of commutative algebras over
661
+ (number fields and quotient fields and metric spaces)
662
+ and Category of infinite sets
663
+ sage: f.category()
664
+ Category of endsets of unital magmas
665
+ and right modules over (number fields and quotient fields and metric spaces)
666
+ and left modules over (number fields and quotient fields and metric spaces)
667
+
668
+
669
+ FIXME: find a better name for this method
670
+ """
671
+ if self._category_for is None:
672
+ # This can happen if the map is the result of unpickling.
673
+ # We have initialised self._parent, but could not set
674
+ # self._category_for at that moment, because it could
675
+ # happen that the parent was not fully constructed and
676
+ # did not know its category yet.
677
+ self._category_for = self._parent.homset_category()
678
+ return self._category_for
679
+
680
+ def __call__(self, x, *args, **kwds):
681
+ """
682
+ Apply this map to ``x``.
683
+
684
+ IMPLEMENTATION:
685
+
686
+ - To implement the call method in a subclass of Map, implement
687
+ :meth:`_call_` and possibly also :meth:`_call_with_args` and
688
+ :meth:`pushforward`.
689
+ - If the parent of ``x`` cannot be coerced into the domain of
690
+ ``self``, then the method ``pushforward`` is called with ``x``
691
+ and the other given arguments, provided it is implemented.
692
+ In that way, ``self`` could be applied to objects like ideals
693
+ or sub-modules.
694
+ - If there is no coercion and if ``pushforward`` is not implemented
695
+ or fails, ``_call_`` is called after conversion into the domain
696
+ (which may be possible even when there is no coercion); if there
697
+ are additional arguments (or keyword arguments),
698
+ :meth:`_call_with_args` is called instead. Note that the
699
+ positional arguments after ``x`` are passed as a tuple to
700
+ :meth:`_call_with_args` and the named arguments are passed
701
+ as a dictionary.
702
+
703
+ INPUT:
704
+
705
+ - ``x`` -- an element coercible to the domain of ``self``; also objects
706
+ like ideals are supported in some cases
707
+
708
+ OUTPUT:
709
+
710
+ an element (or ideal, etc.)
711
+
712
+ EXAMPLES::
713
+
714
+ sage: R.<x,y> = QQ[]; phi = R.hom([y, x])
715
+ sage: phi(y) # indirect doctest
716
+ x
717
+
718
+ We take the image of an ideal::
719
+
720
+ sage: I = ideal(x, y); I
721
+ Ideal (x, y) of Multivariate Polynomial Ring in x, y over Rational Field
722
+ sage: phi(I)
723
+ Ideal (y, x) of Multivariate Polynomial Ring in x, y over Rational Field
724
+
725
+ TESTS:
726
+
727
+ We test that the map can be applied to something that converts
728
+ (but not coerces) into the domain and can *not* be dealt with
729
+ by :meth:`pushforward` (see :issue:`10496`)::
730
+
731
+ sage: D = {(0, 2): -1, (0, 0): -1, (1, 1): 7, (2, 0): 1/3}
732
+ sage: phi(D)
733
+ -x^2 + 7*x*y + 1/3*y^2 - 1
734
+
735
+ We test what happens if the argument can't be converted into
736
+ the domain::
737
+
738
+ sage: from sage.categories.map import Map
739
+ sage: f = Map(Hom(ZZ, QQ, Rings()))
740
+ sage: f(1/2)
741
+ Traceback (most recent call last):
742
+ ...
743
+ TypeError: 1/2 fails to convert into the map's domain Integer Ring,
744
+ but a `pushforward` method is not properly implemented
745
+
746
+ We test that the default call method really works as described
747
+ above (that was fixed in :issue:`10496`)::
748
+
749
+ sage: class FOO(Map):
750
+ ....: def _call_(self, x):
751
+ ....: print("_call_ {}".format(parent(x)))
752
+ ....: return self.codomain()(x)
753
+ ....: def _call_with_args(self, x, args=(), kwds={}):
754
+ ....: print("_call_with_args {}".format(parent(x)))
755
+ ....: return self.codomain()(x)^kwds.get('exponent', 1)
756
+ ....: def pushforward(self, x, exponent=1):
757
+ ....: print("pushforward {}".format(parent(x)))
758
+ ....: return self.codomain()(1/x)^exponent
759
+ sage: f = FOO(ZZ, QQ)
760
+ sage: f(1/1) #indirect doctest
761
+ pushforward Rational Field
762
+ 1
763
+
764
+ ``_call_`` and ``_call_with_args_`` are used *after* coercion::
765
+
766
+ sage: f(int(1))
767
+ _call_ Integer Ring
768
+ 1
769
+ sage: f(int(2), exponent=2)
770
+ _call_with_args Integer Ring
771
+ 4
772
+
773
+ ``pushforward`` is called without conversion::
774
+
775
+ sage: f(1/2)
776
+ pushforward Rational Field
777
+ 2
778
+ sage: f(1/2, exponent=2)
779
+ pushforward Rational Field
780
+ 4
781
+
782
+ If the argument does not coerce into the domain, and if
783
+ ``pushforward`` fails, ``_call_`` is tried after conversion::
784
+
785
+ sage: g = FOO(QQ, ZZ)
786
+ sage: g(SR(3)) # needs sage.symbolic
787
+ pushforward Symbolic Ring
788
+ _call_ Rational Field
789
+ 3
790
+ sage: g(SR(3), exponent=2) # needs sage.symbolic
791
+ pushforward Symbolic Ring
792
+ _call_with_args Rational Field
793
+ 9
794
+
795
+ If conversion fails as well, an error is raised::
796
+
797
+ sage: h = FOO(ZZ, ZZ)
798
+ sage: h(2/3)
799
+ Traceback (most recent call last):
800
+ ...
801
+ TypeError: 2/3 fails to convert into the map's domain Integer Ring,
802
+ but a `pushforward` method is not properly implemented
803
+ """
804
+ P = parent(x)
805
+ cdef Parent D = self.domain()
806
+ if P is D: # we certainly want to call _call_/with_args
807
+ if not args and not kwds:
808
+ return self._call_(x)
809
+ return self._call_with_args(x, args, kwds)
810
+ # Is there coercion?
811
+ converter = D._internal_coerce_map_from(P)
812
+ if converter is None:
813
+ try:
814
+ return self.pushforward(x, *args, **kwds)
815
+ except (AttributeError, TypeError, NotImplementedError):
816
+ pass
817
+ try:
818
+ x = D(x)
819
+ except (TypeError, NotImplementedError):
820
+ raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented" % (x, D))
821
+ else:
822
+ x = converter(x)
823
+ if not args and not kwds:
824
+ return self._call_(x)
825
+ return self._call_with_args(x, args, kwds)
826
+
827
+ cpdef Element _call_(self, x):
828
+ """
829
+ Call method with a single argument, not implemented in the base class.
830
+
831
+ TESTS::
832
+
833
+ sage: from sage.categories.map import Map
834
+ sage: f = Map(Hom(QQ, ZZ, Rings()))
835
+ sage: f(1/2) # indirect doctest
836
+ Traceback (most recent call last):
837
+ ...
838
+ NotImplementedError: <class 'sage.categories.map.Map'>
839
+ """
840
+ raise NotImplementedError(type(self))
841
+
842
+ cpdef Element _call_with_args(self, x, args=(), kwds={}):
843
+ """
844
+ Call method with multiple arguments, not implemented in the base class.
845
+
846
+ TESTS::
847
+
848
+ sage: from sage.categories.map import Map
849
+ sage: f = Map(Hom(QQ, ZZ, Rings()))
850
+ sage: f(1/2, 2, foo='bar') # indirect doctest
851
+ Traceback (most recent call last):
852
+ ...
853
+ NotImplementedError: _call_with_args not overridden to accept arguments for <class 'sage.categories.map.Map'>
854
+ """
855
+ if not args and not kwds:
856
+ return self(x)
857
+ raise NotImplementedError("_call_with_args not overridden "
858
+ f"to accept arguments for {type(self)}")
859
+
860
+ def __mul__(self, right):
861
+ r"""
862
+ The multiplication * operator is operator composition.
863
+
864
+ IMPLEMENTATION:
865
+
866
+ If you want to change the behaviour of composition for
867
+ derived classes, please overload :meth:`_composition_`
868
+ (but not :meth:`_composition`!) of the left factor.
869
+
870
+ INPUT:
871
+
872
+ - ``self`` -- Map
873
+ - ``right`` -- Map
874
+
875
+ OUTPUT:
876
+
877
+ The map `x \mapsto self(right(x))`.
878
+
879
+ EXAMPLES::
880
+
881
+ sage: from sage.categories.morphism import SetMorphism
882
+ sage: X.<x> = ZZ[]
883
+ sage: Y = ZZ
884
+ sage: Z = QQ
885
+ sage: phi_xy = SetMorphism(Hom(X, Y, Rings()), lambda p: p[0])
886
+ sage: phi_yz = SetMorphism(Hom(Y, Z, CommutativeAdditiveMonoids()), lambda y: QQ(y)/2)
887
+ sage: phi_yz * phi_xy
888
+ Composite map:
889
+ From: Univariate Polynomial Ring in x over Integer Ring
890
+ To: Rational Field
891
+ Defn: Generic morphism:
892
+ From: Univariate Polynomial Ring in x over Integer Ring
893
+ To: Integer Ring
894
+ then
895
+ Generic morphism:
896
+ From: Integer Ring
897
+ To: Rational Field
898
+
899
+ If ``right`` is a ring homomorphism given by the images of
900
+ generators, then it is attempted to form the composition
901
+ accordingly. Only if this fails, or if the result does not
902
+ belong to the given homset, a formal composite map is
903
+ returned (as above).
904
+ ::
905
+
906
+ sage: R.<x,y> = QQ[]
907
+ sage: S.<a,b> = QQ[]
908
+ sage: f = R.hom([x+y, x-y], R)
909
+ sage: f = R.hom([a+b, a-b])
910
+ sage: g = S.hom([x+y, x-y])
911
+ sage: f*g
912
+ Ring endomorphism of Multivariate Polynomial Ring in a, b over Rational Field
913
+ Defn: a |--> 2*a
914
+ b |--> 2*b
915
+ sage: h = SetMorphism(Hom(S, QQ, Rings()), lambda p: p.lc())
916
+ sage: h*f
917
+ Composite map:
918
+ From: Multivariate Polynomial Ring in x, y over Rational Field
919
+ To: Rational Field
920
+ Defn: Ring morphism:
921
+ From: Multivariate Polynomial Ring in x, y over Rational Field
922
+ To: Multivariate Polynomial Ring in a, b over Rational Field
923
+ Defn: x |--> a + b
924
+ y |--> a - b
925
+ then
926
+ Generic morphism:
927
+ From: Multivariate Polynomial Ring in a, b over Rational Field
928
+ To: Rational Field
929
+ """
930
+ if not isinstance(right, Map):
931
+ raise TypeError("right (=%s) must be a map to multiply it by %s" % (right, self))
932
+ if right.codomain() != self.domain():
933
+ raise TypeError("self (=%s) domain must equal right (=%s) codomain" % (self, right))
934
+ return self._composition(right)
935
+
936
+ def _composition(self, right):
937
+ """
938
+ Composition of maps, which generically returns a :class:`CompositeMap`.
939
+
940
+ INPUT:
941
+
942
+ - ``self`` -- a Map in some ``Hom(Y, Z, category_left)``
943
+ - ``right`` -- a Map in some ``Hom(X, Y, category_right)``
944
+
945
+ OUTPUT:
946
+
947
+ Returns the composition of ``self`` and ``right`` as a
948
+ morphism in ``Hom(X, Z, category)`` where ``category`` is the
949
+ meet of ``category_left`` and ``category_right``.
950
+
951
+ EXAMPLES::
952
+
953
+ sage: from sage.categories.morphism import SetMorphism
954
+ sage: X.<x> = ZZ[]
955
+ sage: Y = ZZ
956
+ sage: Z = QQ
957
+ sage: phi_xy = SetMorphism(Hom(X, Y, Rings()), lambda p: p[0])
958
+ sage: phi_yz = SetMorphism(Hom(Y, Z, CommutativeAdditiveMonoids()), lambda y: QQ(y)/2)
959
+ sage: phi_yz._composition(phi_xy)
960
+ Composite map:
961
+ From: Univariate Polynomial Ring in x over Integer Ring
962
+ To: Rational Field
963
+ Defn: Generic morphism:
964
+ From: Univariate Polynomial Ring in x over Integer Ring
965
+ To: Integer Ring
966
+ then
967
+ Generic morphism:
968
+ From: Integer Ring
969
+ To: Rational Field
970
+ sage: phi_yz.category_for()
971
+ Category of commutative additive monoids
972
+ """
973
+ category = self.category_for()._meet_(right.category_for())
974
+ H = homset.Hom(right.domain(), self._codomain, category)
975
+ return self._composition_(right, H)
976
+
977
+ def _composition_(self, right, homset):
978
+ """
979
+ INPUT:
980
+
981
+ - ``self``, ``right`` -- maps
982
+ - ``homset`` -- a homset
983
+
984
+ ASSUMPTION:
985
+
986
+ The codomain of ``right`` is contained in the domain of ``self``.
987
+ This assumption is not verified.
988
+
989
+ OUTPUT:
990
+
991
+ Returns a formal composite map, the composition of ``right``
992
+ followed by ``self``, as a morphism in ``homset``.
993
+
994
+ Classes deriving from :class:`Map` are encouraged to override
995
+ this whenever meaningful. This is the case, e.g., for ring
996
+ homomorphisms.
997
+
998
+ EXAMPLES::
999
+
1000
+ sage: Rx.<x> = ZZ['x']
1001
+ sage: Ry.<y> = ZZ['y']
1002
+ sage: Rz.<z> = ZZ['z']
1003
+ sage: phi_xy = Rx.hom([y+1]); phi_xy
1004
+ Ring morphism:
1005
+ From: Univariate Polynomial Ring in x over Integer Ring
1006
+ To: Univariate Polynomial Ring in y over Integer Ring
1007
+ Defn: x |--> y + 1
1008
+ sage: phi_yz = Ry.hom([z+1]); phi_yz
1009
+ Ring morphism:
1010
+ From: Univariate Polynomial Ring in y over Integer Ring
1011
+ To: Univariate Polynomial Ring in z over Integer Ring
1012
+ Defn: y |--> z + 1
1013
+ sage: phi_xz = phi_yz._composition_(phi_xy, Hom(Rx, Rz, Monoids()))
1014
+ sage: phi_xz
1015
+ Composite map:
1016
+ From: Univariate Polynomial Ring in x over Integer Ring
1017
+ To: Univariate Polynomial Ring in z over Integer Ring
1018
+ Defn: Ring morphism:
1019
+ From: Univariate Polynomial Ring in x over Integer Ring
1020
+ To: Univariate Polynomial Ring in y over Integer Ring
1021
+ Defn: x |--> y + 1
1022
+ then
1023
+ Ring morphism:
1024
+ From: Univariate Polynomial Ring in y over Integer Ring
1025
+ To: Univariate Polynomial Ring in z over Integer Ring
1026
+ Defn: y |--> z + 1
1027
+ sage: phi_xz.category_for()
1028
+ Category of monoids
1029
+
1030
+ TESTS:
1031
+
1032
+ This illustrates that it is not tested whether the maps can actually
1033
+ be composed, i.e., whether codomain and domain match.
1034
+ ::
1035
+
1036
+ sage: R.<x,y> = QQ[]
1037
+ sage: S.<a,b> = QQ[]
1038
+ sage: f_R = R.hom([x+y, x-y], R)
1039
+ sage: f_S = S.hom([a+b, a-b], S)
1040
+ sage: foo_bar = f_R._composition_(f_S, Hom(S, R, Monoids()))
1041
+ sage: foo_bar(a)
1042
+ 2*x
1043
+
1044
+ However, it is tested when attempting to compose the maps in
1045
+ the usual multiplicative notation::
1046
+
1047
+ sage: f_R*f_S
1048
+ Traceback (most recent call last):
1049
+ ...
1050
+ TypeError: self (=Ring endomorphism of Multivariate Polynomial Ring in x, y over Rational Field
1051
+ Defn: x |--> x + y
1052
+ y |--> x - y) domain must equal right (=Ring endomorphism of Multivariate Polynomial Ring in a, b over Rational Field
1053
+ Defn: a |--> a + b
1054
+ b |--> a - b) codomain
1055
+ """
1056
+ return FormalCompositeMap(homset, right, self)
1057
+
1058
+ def pre_compose(self, right):
1059
+ """
1060
+ INPUT:
1061
+
1062
+ - ``self`` -- a Map in some ``Hom(Y, Z, category_left)``
1063
+ - ``left`` -- a Map in some ``Hom(X, Y, category_right)``
1064
+
1065
+ Returns the composition of ``right`` followed by ``self`` as a
1066
+ morphism in ``Hom(X, Z, category)`` where ``category`` is the
1067
+ meet of ``category_left`` and ``category_right``.
1068
+
1069
+ EXAMPLES::
1070
+
1071
+ sage: from sage.categories.morphism import SetMorphism
1072
+ sage: X.<x> = ZZ[]
1073
+ sage: Y = ZZ
1074
+ sage: Z = QQ
1075
+ sage: phi_xy = SetMorphism(Hom(X, Y, Rings()), lambda p: p[0])
1076
+ sage: phi_yz = SetMorphism(Hom(Y, Z, Monoids()), lambda y: QQ(y**2))
1077
+ sage: phi_xz = phi_yz.pre_compose(phi_xy); phi_xz
1078
+ Composite map:
1079
+ From: Univariate Polynomial Ring in x over Integer Ring
1080
+ To: Rational Field
1081
+ Defn: Generic morphism:
1082
+ From: Univariate Polynomial Ring in x over Integer Ring
1083
+ To: Integer Ring
1084
+ then
1085
+ Generic morphism:
1086
+ From: Integer Ring
1087
+ To: Rational Field
1088
+ sage: phi_xz.category_for()
1089
+ Category of monoids
1090
+ """
1091
+ D = self.domain()
1092
+ if D is not right.codomain():
1093
+ right = right.extend_codomain(D)
1094
+ return self._composition(right)
1095
+
1096
+ def post_compose(self, left):
1097
+ """
1098
+ INPUT:
1099
+
1100
+ - ``self`` -- a Map in some ``Hom(X, Y, category_right)``
1101
+ - ``left`` -- a Map in some ``Hom(Y, Z, category_left)``
1102
+
1103
+ Returns the composition of ``self`` followed by ``left`` as a
1104
+ morphism in ``Hom(X, Z, category)`` where ``category`` is the
1105
+ meet of ``category_left`` and ``category_right``.
1106
+
1107
+ Caveat: see the current restrictions on :meth:`Category.meet`
1108
+
1109
+ EXAMPLES::
1110
+
1111
+ sage: from sage.categories.morphism import SetMorphism
1112
+ sage: X.<x> = ZZ[]
1113
+ sage: Y = ZZ
1114
+ sage: Z = QQ
1115
+ sage: phi_xy = SetMorphism(Hom(X, Y, Rings()), lambda p: p[0])
1116
+ sage: phi_yz = SetMorphism(Hom(Y, Z, Monoids()), lambda y: QQ(y**2))
1117
+ sage: phi_xz = phi_xy.post_compose(phi_yz); phi_xz
1118
+ Composite map:
1119
+ From: Univariate Polynomial Ring in x over Integer Ring
1120
+ To: Rational Field
1121
+ Defn: Generic morphism:
1122
+ From: Univariate Polynomial Ring in x over Integer Ring
1123
+ To: Integer Ring
1124
+ then
1125
+ Generic morphism:
1126
+ From: Integer Ring
1127
+ To: Rational Field
1128
+ sage: phi_xz.category_for()
1129
+ Category of monoids
1130
+ """
1131
+ return left._composition(self)
1132
+
1133
+ def extend_domain(self, new_domain):
1134
+ r"""
1135
+ INPUT:
1136
+
1137
+ - ``self`` -- a member of Hom(Y, Z)
1138
+ - ``new_codomain`` -- an object X such that there is a canonical coercion
1139
+ `\phi` in Hom(X, Y)
1140
+
1141
+ OUTPUT:
1142
+
1143
+ An element of Hom(X, Z) obtained by composing self with `\phi`. If
1144
+ no canonical `\phi` exists, a :exc:`TypeError` is raised.
1145
+
1146
+ EXAMPLES::
1147
+
1148
+ sage: # needs sage.rings.complex_double
1149
+ sage: mor = CDF.coerce_map_from(RDF)
1150
+ sage: mor.extend_domain(QQ)
1151
+ Composite map:
1152
+ From: Rational Field
1153
+ To: Complex Double Field
1154
+ Defn: Native morphism:
1155
+ From: Rational Field
1156
+ To: Real Double Field
1157
+ then
1158
+ Native morphism:
1159
+ From: Real Double Field
1160
+ To: Complex Double Field
1161
+ sage: mor.extend_domain(ZZ['x'])
1162
+ Traceback (most recent call last):
1163
+ ...
1164
+ TypeError: No coercion from Univariate Polynomial Ring in x over Integer Ring
1165
+ to Real Double Field
1166
+ """
1167
+ D = self.domain()
1168
+ if D is None:
1169
+ raise ValueError("This map became defunct by garbage collection")
1170
+ cdef Map connecting = D._internal_coerce_map_from(new_domain)
1171
+ if connecting is None:
1172
+ raise TypeError("No coercion from %s to %s" % (new_domain, D))
1173
+ elif connecting.codomain() is not D:
1174
+ raise RuntimeError("BUG: coerce_map_from should always return a map to self (%s)" % D)
1175
+ else:
1176
+ return self.pre_compose(connecting.__copy__())
1177
+
1178
+ def extend_codomain(self, new_codomain):
1179
+ r"""
1180
+ INPUT:
1181
+
1182
+ - ``self`` -- a member of Hom(X, Y)
1183
+ - ``new_codomain`` -- an object Z such that there is a canonical coercion
1184
+ `\phi` in Hom(Y, Z)
1185
+
1186
+ OUTPUT:
1187
+
1188
+ An element of Hom(X, Z) obtained by composing ``self`` with `\phi`. If
1189
+ no canonical `\phi` exists, a :exc:`TypeError` is raised.
1190
+
1191
+ EXAMPLES::
1192
+
1193
+ sage: mor = QQ.coerce_map_from(ZZ)
1194
+ sage: mor.extend_codomain(RDF)
1195
+ Composite map:
1196
+ From: Integer Ring
1197
+ To: Real Double Field
1198
+ Defn: Natural morphism:
1199
+ From: Integer Ring
1200
+ To: Rational Field
1201
+ then
1202
+ Native morphism:
1203
+ From: Rational Field
1204
+ To: Real Double Field
1205
+ sage: mor.extend_codomain(GF(7))
1206
+ Traceback (most recent call last):
1207
+ ...
1208
+ TypeError: No coercion from Rational Field to Finite Field of size 7
1209
+ """
1210
+ cdef Map connecting = new_codomain._internal_coerce_map_from(self._codomain)
1211
+ if connecting is None:
1212
+ raise TypeError("No coercion from %s to %s" % (self._codomain, new_codomain))
1213
+ elif connecting.domain() is not self._codomain:
1214
+ raise RuntimeError("BUG: coerce_map_from should always return a map from its input (%s)" % new_codomain)
1215
+ else:
1216
+ return self.post_compose(connecting.__copy__())
1217
+
1218
+ def is_surjective(self):
1219
+ """
1220
+ Tell whether the map is surjective (not implemented in the base class).
1221
+
1222
+ TESTS::
1223
+
1224
+ sage: from sage.categories.map import Map
1225
+ sage: f = Map(Hom(QQ, ZZ, Rings()))
1226
+ sage: f.is_surjective()
1227
+ Traceback (most recent call last):
1228
+ ...
1229
+ NotImplementedError: <class 'sage.categories.map.Map'>
1230
+ """
1231
+ raise NotImplementedError(type(self))
1232
+
1233
+ cpdef _pow_int(self, n):
1234
+ """
1235
+ TESTS::
1236
+
1237
+ sage: R.<x> = ZZ['x']
1238
+ sage: phi = R.hom([x+1]); phi
1239
+ Ring endomorphism of Univariate Polynomial Ring in x over Integer Ring
1240
+ Defn: x |--> x + 1
1241
+
1242
+ sage: phi^0
1243
+ Identity endomorphism of Univariate Polynomial Ring in x over Integer Ring
1244
+
1245
+ sage: phi^2 == phi*phi
1246
+ True
1247
+
1248
+ sage: S.<y> = QQ[]
1249
+ sage: psi = R.hom([y^2])
1250
+ sage: psi^1
1251
+ Ring morphism:
1252
+ From: Univariate Polynomial Ring in x over Integer Ring
1253
+ To: Univariate Polynomial Ring in y over Rational Field
1254
+ Defn: x |--> y^2
1255
+ sage: psi^2
1256
+ Traceback (most recent call last):
1257
+ ...
1258
+ TypeError: self must be an endomorphism
1259
+
1260
+ sage: # needs sage.rings.number_field
1261
+ sage: K.<a> = NumberField(x^4 - 5*x + 5)
1262
+ sage: C5.<z> = CyclotomicField(5)
1263
+ sage: tau = K.hom([z - z^2]); tau
1264
+ Ring morphism:
1265
+ From: Number Field in a with defining polynomial x^4 - 5*x + 5
1266
+ To: Cyclotomic Field of order 5 and degree 4
1267
+ Defn: a |--> -z^2 + z
1268
+ sage: tau^-1
1269
+ Ring morphism:
1270
+ From: Cyclotomic Field of order 5 and degree 4
1271
+ To: Number Field in a with defining polynomial x^4 - 5*x + 5
1272
+ Defn: z |--> 3/11*a^3 + 4/11*a^2 + 9/11*a - 14/11
1273
+ """
1274
+ if self.domain() is not self._codomain and n != 1 and n != -1:
1275
+ raise TypeError("self must be an endomorphism")
1276
+ if n == 0:
1277
+ from sage.categories.morphism import IdentityMorphism
1278
+ return IdentityMorphism(self._parent)
1279
+ return generic_power(self, n)
1280
+
1281
+ def section(self):
1282
+ """
1283
+ Return a section of ``self``.
1284
+
1285
+ .. NOTE::
1286
+
1287
+ By default, it returns ``None``. You may override it in subclasses.
1288
+
1289
+ TESTS::
1290
+
1291
+ sage: R.<x,y> = QQ[]
1292
+ sage: f = R.hom([x+y, x-y], R)
1293
+ sage: print(f.section())
1294
+ None
1295
+
1296
+ sage: f = QQ.coerce_map_from(ZZ); f
1297
+ Natural morphism:
1298
+ From: Integer Ring
1299
+ To: Rational Field
1300
+ sage: ff = f.section(); ff
1301
+ Generic map:
1302
+ From: Rational Field
1303
+ To: Integer Ring
1304
+ sage: ff(4/2)
1305
+ 2
1306
+ sage: parent(ff(4/2)) is ZZ
1307
+ True
1308
+ sage: ff(1/2)
1309
+ Traceback (most recent call last):
1310
+ ...
1311
+ TypeError: no conversion of this rational to integer
1312
+ """
1313
+ return None
1314
+
1315
+ def __hash__(self):
1316
+ """
1317
+ Return the hash of this map.
1318
+
1319
+ TESTS::
1320
+
1321
+ sage: f = sage.rings.morphism.RingMap(ZZ.Hom(ZZ))
1322
+ sage: type(f)
1323
+ <class 'sage.rings.morphism.RingMap'>
1324
+ sage: hash(f) == hash(f)
1325
+ True
1326
+ sage: {f: 1}[f]
1327
+ 1
1328
+ """
1329
+ D = self.domain()
1330
+ if D is None:
1331
+ raise ValueError("This map became defunct by garbage collection")
1332
+ return hash((self.domain(), self._codomain))
1333
+
1334
+ cdef class Section(Map):
1335
+ """
1336
+ A formal section of a map.
1337
+
1338
+ .. NOTE::
1339
+
1340
+ Call methods are not implemented for the base class ``Section``.
1341
+
1342
+ EXAMPLES::
1343
+
1344
+ sage: from sage.categories.map import Section
1345
+ sage: R.<x,y> = ZZ[]
1346
+ sage: S.<a,b> = QQ[]
1347
+ sage: f = R.hom([a+b, a-b])
1348
+ sage: sf = Section(f); sf
1349
+ Section map:
1350
+ From: Multivariate Polynomial Ring in a, b over Rational Field
1351
+ To: Multivariate Polynomial Ring in x, y over Integer Ring
1352
+ sage: sf(a)
1353
+ Traceback (most recent call last):
1354
+ ...
1355
+ NotImplementedError: <class 'sage.categories.map.Section'>
1356
+ """
1357
+
1358
+ def __init__(self, map):
1359
+ """
1360
+ INPUT:
1361
+
1362
+ - ``map`` -- a map
1363
+
1364
+ TESTS::
1365
+
1366
+ sage: from sage.categories.map import Section
1367
+ sage: R.<x,y> = QQ[]
1368
+ sage: f = R.hom([x+y, x-y], R)
1369
+ sage: sf = Section(f); sf
1370
+ Section map:
1371
+ From: Multivariate Polynomial Ring in x, y over Rational Field
1372
+ To: Multivariate Polynomial Ring in x, y over Rational Field
1373
+ """
1374
+ from sage.categories.homset import Hom
1375
+ from sage.categories.sets_with_partial_maps import SetsWithPartialMaps
1376
+ Map.__init__(self, Hom(map.codomain(), map.domain(), SetsWithPartialMaps()))
1377
+ self._inverse = map # TODO: Use this attribute somewhere!
1378
+
1379
+ cdef dict _extra_slots(self):
1380
+ """
1381
+ Helper for pickling and copying.
1382
+
1383
+ TESTS::
1384
+
1385
+ sage: from sage.categories.map import Section
1386
+ sage: R.<x,y> = QQ[]
1387
+ sage: f = R.hom([x+y, x-y], R)
1388
+ sage: sf = Section(f)
1389
+ sage: copy(sf) # indirect doctest
1390
+ Section map:
1391
+ From: Multivariate Polynomial Ring in x, y over Rational Field
1392
+ To: Multivariate Polynomial Ring in x, y over Rational Field
1393
+ """
1394
+ slots = Map._extra_slots(self)
1395
+ slots['_inverse'] = self._inverse
1396
+ return slots
1397
+
1398
+ cdef _update_slots(self, dict _slots):
1399
+ """
1400
+ Helper for pickling and copying.
1401
+
1402
+ TESTS::
1403
+
1404
+ sage: from sage.categories.map import Section
1405
+ sage: R.<x,y> = QQ[]
1406
+ sage: f = R.hom([x+y, x-y], R)
1407
+ sage: sf = Section(f)
1408
+ sage: copy(sf) # indirect doctest
1409
+ Section map:
1410
+ From: Multivariate Polynomial Ring in x, y over Rational Field
1411
+ To: Multivariate Polynomial Ring in x, y over Rational Field
1412
+ """
1413
+ Map._update_slots(self, _slots)
1414
+ self._inverse = _slots['_inverse']
1415
+
1416
+ def _repr_type(self):
1417
+ """
1418
+ Return a string describing the type of this map (which is "Section").
1419
+
1420
+ TESTS::
1421
+
1422
+ sage: from sage.categories.map import Section
1423
+ sage: R.<x,y> = QQ[]
1424
+ sage: f = R.hom([x+y, x-y], R)
1425
+ sage: sf = Section(f)
1426
+ sage: sf # indirect doctest
1427
+ Section map:
1428
+ From: Multivariate Polynomial Ring in x, y over Rational Field
1429
+ To: Multivariate Polynomial Ring in x, y over Rational Field
1430
+ """
1431
+ return "Section"
1432
+
1433
+ def inverse(self):
1434
+ """
1435
+ Return inverse of ``self``.
1436
+
1437
+ TESTS::
1438
+
1439
+ sage: from sage.categories.map import Section
1440
+ sage: R.<x,y> = QQ[]
1441
+ sage: f = R.hom([x+y, x-y], R)
1442
+ sage: sf = Section(f)
1443
+ sage: sf.inverse()
1444
+ Ring endomorphism of Multivariate Polynomial Ring in x, y over Rational Field
1445
+ Defn: x |--> x + y
1446
+ y |--> x - y
1447
+ """
1448
+ return self._inverse
1449
+
1450
+
1451
+ cdef class FormalCompositeMap(Map):
1452
+ """
1453
+ Formal composite maps.
1454
+
1455
+ A formal composite map is formed by two maps, so that the codomain of the
1456
+ first map is contained in the domain of the second map.
1457
+
1458
+ .. NOTE::
1459
+
1460
+ When calling a composite with additional arguments, these arguments are
1461
+ *only* passed to the second underlying map.
1462
+
1463
+ EXAMPLES::
1464
+
1465
+ sage: R.<x> = QQ[]
1466
+ sage: S.<a> = QQ[]
1467
+ sage: from sage.categories.morphism import SetMorphism
1468
+ sage: f = SetMorphism(Hom(R, S, Rings()), lambda p: p[0]*a^p.degree())
1469
+ sage: g = S.hom([2*x])
1470
+ sage: f*g
1471
+ Composite map:
1472
+ From: Univariate Polynomial Ring in a over Rational Field
1473
+ To: Univariate Polynomial Ring in a over Rational Field
1474
+ Defn: Ring morphism:
1475
+ From: Univariate Polynomial Ring in a over Rational Field
1476
+ To: Univariate Polynomial Ring in x over Rational Field
1477
+ Defn: a |--> 2*x
1478
+ then
1479
+ Generic morphism:
1480
+ From: Univariate Polynomial Ring in x over Rational Field
1481
+ To: Univariate Polynomial Ring in a over Rational Field
1482
+ sage: g*f
1483
+ Composite map:
1484
+ From: Univariate Polynomial Ring in x over Rational Field
1485
+ To: Univariate Polynomial Ring in x over Rational Field
1486
+ Defn: Generic morphism:
1487
+ From: Univariate Polynomial Ring in x over Rational Field
1488
+ To: Univariate Polynomial Ring in a over Rational Field
1489
+ then
1490
+ Ring morphism:
1491
+ From: Univariate Polynomial Ring in a over Rational Field
1492
+ To: Univariate Polynomial Ring in x over Rational Field
1493
+ Defn: a |--> 2*x
1494
+ sage: (f*g)(2*a^2+5)
1495
+ 5*a^2
1496
+ sage: (g*f)(2*x^2+5)
1497
+ 20*x^2
1498
+ """
1499
+
1500
+ def __init__(self, parent, first, second=None):
1501
+ """
1502
+ INPUT:
1503
+
1504
+ - ``parent`` -- a homset
1505
+ - ``first`` -- a map or a list of maps
1506
+ - ``second`` -- a map or None
1507
+
1508
+ .. NOTE::
1509
+
1510
+ The intended use is of course that the codomain of the
1511
+ first map is contained in the domain of the second map,
1512
+ so that the two maps can be composed, and that the
1513
+ composition belongs to ``parent``. However, none of
1514
+ these conditions is verified in the init method.
1515
+
1516
+ The user is advised to compose two maps ``f`` and ``g``
1517
+ in multiplicative notation, ``g*f``, since this will in
1518
+ some cases return a more efficient map object than a
1519
+ formal composite map.
1520
+
1521
+ TESTS::
1522
+
1523
+ sage: R.<x,y> = QQ[]
1524
+ sage: S.<a,b> = QQ[]
1525
+ sage: f = R.hom([a+b, a-b])
1526
+ sage: g = S.hom([x+y, x-y])
1527
+ sage: H = Hom(R, R, Rings())
1528
+ sage: from sage.categories.map import FormalCompositeMap
1529
+ sage: m = FormalCompositeMap(H, f, g); m
1530
+ Composite map:
1531
+ From: Multivariate Polynomial Ring in x, y over Rational Field
1532
+ To: Multivariate Polynomial Ring in x, y over Rational Field
1533
+ Defn: Ring morphism:
1534
+ From: Multivariate Polynomial Ring in x, y over Rational Field
1535
+ To: Multivariate Polynomial Ring in a, b over Rational Field
1536
+ Defn: x |--> a + b
1537
+ y |--> a - b
1538
+ then
1539
+ Ring morphism:
1540
+ From: Multivariate Polynomial Ring in a, b over Rational Field
1541
+ To: Multivariate Polynomial Ring in x, y over Rational Field
1542
+ Defn: a |--> x + y
1543
+ b |--> x - y
1544
+ sage: m(x), m(y)
1545
+ (2*x, 2*y)
1546
+ """
1547
+ Map.__init__(self, parent)
1548
+
1549
+ if isinstance(first, (list, tuple)):
1550
+ self.__list = first
1551
+ self._coerce_cost = sum((<Map>f)._coerce_cost for f in first)
1552
+ return
1553
+
1554
+ self.__list = []
1555
+ if isinstance(first, FormalCompositeMap):
1556
+ self.__list += (<FormalCompositeMap>first).__list
1557
+ else:
1558
+ self.__list += [first]
1559
+
1560
+ if isinstance(second, FormalCompositeMap):
1561
+ self.__list += (<FormalCompositeMap>second).__list
1562
+ else:
1563
+ self.__list += [second]
1564
+ self._coerce_cost = (<Map>first)._coerce_cost + (<Map>second)._coerce_cost
1565
+
1566
+ def __copy__(self):
1567
+ """
1568
+ Since :meth:`_extra_slots` would return the uncopied constituents
1569
+ of this composite map, we cannot rely on the default copying method
1570
+ of maps.
1571
+
1572
+ TESTS::
1573
+
1574
+ sage: copy(QQ['q,t'].coerce_map_from(int)) # indirect doctest
1575
+ Composite map:
1576
+ From: Set of Python objects of class 'int'
1577
+ To: Multivariate Polynomial Ring in q, t over Rational Field
1578
+ Defn: Native morphism:
1579
+ From: Set of Python objects of class 'int'
1580
+ To: Rational Field
1581
+ then
1582
+ Polynomial base injection morphism:
1583
+ From: Rational Field
1584
+ To: Multivariate Polynomial Ring in q, t over Rational Field
1585
+ """
1586
+ return FormalCompositeMap(self.parent(), [f.__copy__() for f in self.__list])
1587
+
1588
+ cdef _update_slots(self, dict _slots):
1589
+ """
1590
+ Used in pickling and copying.
1591
+
1592
+ TESTS::
1593
+
1594
+ sage: R.<x,y> = QQ[]
1595
+ sage: S.<a,b> = QQ[]
1596
+ sage: f = R.hom([a+b, a-b])
1597
+ sage: g = S.hom([x+y, x-y])
1598
+ sage: from sage.categories.map import FormalCompositeMap
1599
+ sage: H = Hom(R, R, Rings())
1600
+ sage: m = FormalCompositeMap(H, f, g)
1601
+ sage: m == loads(dumps(m)) # indirect doctest
1602
+ True
1603
+ """
1604
+ self.__list = _slots['__list']
1605
+ Map._update_slots(self, _slots)
1606
+
1607
+ cdef dict _extra_slots(self):
1608
+ """
1609
+ Used in pickling and copying.
1610
+
1611
+ TESTS::
1612
+
1613
+ sage: R.<x,y> = QQ[]
1614
+ sage: S.<a,b> = QQ[]
1615
+ sage: f = R.hom([a+b, a-b])
1616
+ sage: g = S.hom([x+y, x-y])
1617
+ sage: from sage.categories.map import FormalCompositeMap
1618
+ sage: H = Hom(R, R, Rings())
1619
+ sage: m = FormalCompositeMap(H, f, g)
1620
+ sage: m == loads(dumps(m)) # indirect doctest
1621
+ True
1622
+ """
1623
+ slots = Map._extra_slots(self)
1624
+ slots['__list'] = self.__list
1625
+ return slots
1626
+
1627
+ def __richcmp__(self, other, int op):
1628
+ """
1629
+ TESTS::
1630
+
1631
+ sage: R.<x,y> = QQ[]
1632
+ sage: S.<a,b> = QQ[]
1633
+ sage: f = R.hom([a+b, a-b])
1634
+ sage: g = S.hom([x+y, x-y])
1635
+ sage: from sage.categories.map import FormalCompositeMap
1636
+ sage: H = Hom(R, R, Rings())
1637
+ sage: m = FormalCompositeMap(H, f, g)
1638
+ sage: m == loads(dumps(m))
1639
+ True
1640
+
1641
+ sage: m == None
1642
+ False
1643
+ sage: m == 2
1644
+ False
1645
+ """
1646
+ if type(self) is not type(other):
1647
+ return NotImplemented
1648
+ left = (<FormalCompositeMap>self).__list
1649
+ right = (<FormalCompositeMap>other).__list
1650
+ return PyObject_RichCompare(left, right, op)
1651
+
1652
+ def __hash__(self):
1653
+ """
1654
+ Return the hash of this map.
1655
+
1656
+ TESTS::
1657
+
1658
+ sage: R.<x,y> = QQ[]
1659
+ sage: S.<a,b> = QQ[]
1660
+ sage: f = R.hom([a+b, a-b])
1661
+ sage: g = S.hom([x+y, x-y])
1662
+ sage: from sage.categories.map import FormalCompositeMap
1663
+ sage: H = Hom(R, R, Rings())
1664
+ sage: m = FormalCompositeMap(H, f, g)
1665
+ sage: hash(m) == hash(m)
1666
+ True
1667
+ sage: {m: 1}[m]
1668
+ 1
1669
+ sage: n = FormalCompositeMap(Hom(S, S, Rings()), g, f)
1670
+ sage: hash(m) == hash(n)
1671
+ False
1672
+ sage: len({m: 1, n: 2}.keys())
1673
+ 2
1674
+ """
1675
+ return hash(tuple(self.__list))
1676
+
1677
+ def __getitem__(self, i):
1678
+ r"""
1679
+ Return the `i`-th map of the formal composition.
1680
+
1681
+ If ``self`` represents `f_n \circ f_{n-1} \circ \cdots \circ
1682
+ f_1 \circ f_0`, then ``self[i]`` gives `f_i`. Support
1683
+ negative indices as ``list.__getitem__``. Raise an error if
1684
+ the index does not match, in the same way as
1685
+ ``list.__getitem__``.
1686
+
1687
+ EXAMPLES::
1688
+
1689
+ sage: from sage.categories.map import Map
1690
+ sage: f = Map(ZZ, QQ)
1691
+ sage: g = Map(QQ, ZZ)
1692
+ sage: (f*g)[0]
1693
+ Generic map:
1694
+ From: Rational Field
1695
+ To: Integer Ring
1696
+ sage: (f*g)[1]
1697
+ Generic map:
1698
+ From: Integer Ring
1699
+ To: Rational Field
1700
+ sage: (f*g)[-1]
1701
+ Generic map:
1702
+ From: Integer Ring
1703
+ To: Rational Field
1704
+ sage: (f*g)[-2]
1705
+ Generic map:
1706
+ From: Rational Field
1707
+ To: Integer Ring
1708
+ sage: (f*g)[-3]
1709
+ Traceback (most recent call last):
1710
+ ...
1711
+ IndexError: list index out of range
1712
+ sage: (f*g)[2]
1713
+ Traceback (most recent call last):
1714
+ ...
1715
+ IndexError: list index out of range
1716
+ """
1717
+ return self.__list[i]
1718
+
1719
+ cpdef Element _call_(self, x):
1720
+ """
1721
+ Call with a single argument.
1722
+
1723
+ TESTS::
1724
+
1725
+ sage: R.<x> = QQ[]
1726
+ sage: S.<a> = QQ[]
1727
+ sage: from sage.categories.morphism import SetMorphism
1728
+ sage: f = SetMorphism(Hom(R, S, Rings()), lambda p: p[0]*a^p.degree())
1729
+ sage: g = S.hom([2*x])
1730
+ sage: (g*f)((x+1)^2), (f*g)((a+1)^2) # indirect doctest
1731
+ (4*x^2, a^2)
1732
+ """
1733
+ for f in self.__list:
1734
+ x = f._call_(x)
1735
+ return x
1736
+
1737
+ cpdef Element _call_with_args(self, x, args=(), kwds={}):
1738
+ """
1739
+ Additional arguments are only passed to the last applied map.
1740
+
1741
+ TESTS::
1742
+
1743
+ sage: from sage.categories.morphism import SetMorphism
1744
+ sage: R.<x> = QQ[]
1745
+ sage: def foo(x, *args, **kwds):
1746
+ ....: print('foo called with {} {}'.format(args, kwds))
1747
+ ....: return x
1748
+ sage: def bar(x, *args, **kwds):
1749
+ ....: print('bar called with {} {}'.format(args, kwds))
1750
+ ....: return x
1751
+ sage: f = SetMorphism(Hom(R, R, Rings()), foo)
1752
+ sage: b = SetMorphism(Hom(R, R, Rings()), bar)
1753
+ sage: c = b*f
1754
+ sage: c(2, 'hello world', test=1) # indirect doctest
1755
+ foo called with () {}
1756
+ bar called with ('hello world',) {'test': 1}
1757
+ 2
1758
+ sage: c = f*b
1759
+ sage: c(2, 'hello world', test=1)
1760
+ bar called with () {}
1761
+ foo called with ('hello world',) {'test': 1}
1762
+ 2
1763
+ """
1764
+ for f in self.__list[:-1]:
1765
+ x = f._call_(x)
1766
+ return self.__list[-1]._call_with_args(x, args, kwds)
1767
+
1768
+ def _repr_type(self):
1769
+ """
1770
+ Return a string describing the type of ``self``, namely "Composite".
1771
+
1772
+ TESTS::
1773
+
1774
+ sage: R.<x> = QQ[]
1775
+ sage: S.<a> = QQ[]
1776
+ sage: from sage.categories.morphism import SetMorphism
1777
+ sage: f = SetMorphism(Hom(R, S, Rings()), lambda p: p[0]*a^p.degree())
1778
+ sage: g = S.hom([2*x])
1779
+ sage: f*g # indirect doctest
1780
+ Composite map:
1781
+ From: Univariate Polynomial Ring in a over Rational Field
1782
+ To: Univariate Polynomial Ring in a over Rational Field
1783
+ Defn: Ring morphism:
1784
+ From: Univariate Polynomial Ring in a over Rational Field
1785
+ To: Univariate Polynomial Ring in x over Rational Field
1786
+ Defn: a |--> 2*x
1787
+ then
1788
+ Generic morphism:
1789
+ From: Univariate Polynomial Ring in x over Rational Field
1790
+ To: Univariate Polynomial Ring in a over Rational Field
1791
+ """
1792
+ return "Composite"
1793
+
1794
+ def _repr_defn(self):
1795
+ """
1796
+ Return a string describing the definition of ``self``.
1797
+
1798
+ The return value is obtained from the string representations
1799
+ of the two constituents.
1800
+
1801
+ TESTS::
1802
+
1803
+ sage: R.<x> = QQ[]
1804
+ sage: S.<a> = QQ[]
1805
+ sage: from sage.categories.morphism import SetMorphism
1806
+ sage: f = SetMorphism(Hom(R, S, Rings()), lambda p: p[0]*a^p.degree())
1807
+ sage: g = S.hom([2*x])
1808
+ sage: f*g # indirect doctest
1809
+ Composite map:
1810
+ From: Univariate Polynomial Ring in a over Rational Field
1811
+ To: Univariate Polynomial Ring in a over Rational Field
1812
+ Defn: Ring morphism:
1813
+ From: Univariate Polynomial Ring in a over Rational Field
1814
+ To: Univariate Polynomial Ring in x over Rational Field
1815
+ Defn: a |--> 2*x
1816
+ then
1817
+ Generic morphism:
1818
+ From: Univariate Polynomial Ring in x over Rational Field
1819
+ To: Univariate Polynomial Ring in a over Rational Field
1820
+ """
1821
+ s = " %s" % (self.__list[0])
1822
+ for f in self.__list[1:]:
1823
+ s += "\nthen\n %s" % f
1824
+ return s
1825
+
1826
+ def first(self):
1827
+ r"""
1828
+ Return the first map in the formal composition.
1829
+
1830
+ If ``self`` represents `f_n \circ f_{n-1} \circ \cdots \circ
1831
+ f_1 \circ f_0`, then ``self.first()`` returns `f_0`. We have
1832
+ ``self == self.then() * self.first()``.
1833
+
1834
+ EXAMPLES::
1835
+
1836
+ sage: R.<x> = QQ[]
1837
+ sage: S.<a> = QQ[]
1838
+ sage: from sage.categories.morphism import SetMorphism
1839
+ sage: f = SetMorphism(Hom(R, S, Rings()), lambda p: p[0]*a^p.degree())
1840
+ sage: g = S.hom([2*x])
1841
+ sage: fg = f * g
1842
+ sage: fg.first() == g
1843
+ True
1844
+ sage: fg == fg.then() * fg.first()
1845
+ True
1846
+ """
1847
+ return self.__list[0]
1848
+
1849
+ def then(self):
1850
+ r"""
1851
+ Return the tail of the list of maps.
1852
+
1853
+ If ``self`` represents `f_n \circ f_{n-1} \circ \cdots \circ
1854
+ f_1 \circ f_0`, then ``self.first()`` returns `f_n \circ
1855
+ f_{n-1} \circ \cdots \circ f_1`. We have ``self ==
1856
+ self.then() * self.first()``.
1857
+
1858
+ EXAMPLES::
1859
+
1860
+ sage: R.<x> = QQ[]
1861
+ sage: S.<a> = QQ[]
1862
+ sage: from sage.categories.morphism import SetMorphism
1863
+ sage: f = SetMorphism(Hom(R, S, Rings()), lambda p: p[0]*a^p.degree())
1864
+ sage: g = S.hom([2*x])
1865
+ sage: (f*g).then() == f
1866
+ True
1867
+
1868
+ sage: f = QQ.coerce_map_from(ZZ)
1869
+ sage: f = f.extend_domain(ZZ).extend_codomain(QQ)
1870
+ sage: f.then()
1871
+ Composite map:
1872
+ From: Integer Ring
1873
+ To: Rational Field
1874
+ Defn: Natural morphism:
1875
+ From: Integer Ring
1876
+ To: Rational Field
1877
+ then
1878
+ Identity endomorphism of Rational Field
1879
+ """
1880
+ if len(self.__list) == 2:
1881
+ return self.__list[1]
1882
+ domain = self.__list[0].codomain()
1883
+ codomain = self.codomain()
1884
+ H = homset.Hom(domain, codomain, category=self._category_for)
1885
+ return FormalCompositeMap(H, self.__list[1:])
1886
+
1887
+ def is_injective(self):
1888
+ """
1889
+ Tell whether ``self`` is injective.
1890
+
1891
+ It raises :exc:`NotImplementedError` if it cannot be determined.
1892
+
1893
+ EXAMPLES::
1894
+
1895
+ sage: # needs sage.modules
1896
+ sage: V1 = QQ^2
1897
+ sage: V2 = QQ^3
1898
+ sage: phi1 = (QQ^1).hom(Matrix([[1, 1]]), V1)
1899
+ sage: phi2 = V1.hom(Matrix([[1, 2, 3], [4, 5, 6]]), V2)
1900
+
1901
+ If both constituents are injective, the composition is injective::
1902
+
1903
+ sage: from sage.categories.map import FormalCompositeMap
1904
+ sage: c1 = FormalCompositeMap(Hom(QQ^1, V2, phi1.category_for()), # needs sage.modules
1905
+ ....: phi1, phi2)
1906
+ sage: c1.is_injective() # needs sage.modules
1907
+ True
1908
+
1909
+ If it cannot be determined whether the composition is injective,
1910
+ an error is raised::
1911
+
1912
+ sage: psi1 = V2.hom(Matrix([[1, 2], [3, 4], [5, 6]]), V1) # needs sage.modules
1913
+ sage: c2 = FormalCompositeMap(Hom(V1, V1, phi2.category_for()), # needs sage.modules
1914
+ ....: phi2, psi1)
1915
+ sage: c2.is_injective() # needs sage.modules
1916
+ Traceback (most recent call last):
1917
+ ...
1918
+ NotImplementedError: not enough information to deduce injectivity
1919
+
1920
+ If the first map is surjective and the second map is not injective,
1921
+ then the composition is not injective::
1922
+
1923
+ sage: psi2 = V1.hom([[1], [1]], QQ^1) # needs sage.modules
1924
+ sage: c3 = FormalCompositeMap(Hom(V2, QQ^1, phi2.category_for()), # needs sage.modules
1925
+ ....: psi2, psi1)
1926
+ sage: c3.is_injective() # needs sage.modules
1927
+ False
1928
+
1929
+ TESTS:
1930
+
1931
+ Check that :issue:`23205` has been resolved::
1932
+
1933
+ sage: f = QQ.hom(QQbar) * ZZ.hom(QQ) # needs sage.rings.number_field
1934
+ sage: f.is_injective() # needs sage.rings.number_field
1935
+ True
1936
+ """
1937
+ try:
1938
+ # we try the category first
1939
+ # as of 2017-06, the MRO of this class does not get patched to
1940
+ # include the category's MorphismMethods (because it is a Cython
1941
+ # class); therefore, we cannot simply call "super" but need to
1942
+ # invoke the category method explicitly
1943
+ return self.getattr_from_category('is_injective')()
1944
+ except (AttributeError, NotImplementedError):
1945
+ pass
1946
+
1947
+ injectives = []
1948
+ for f in self.__list:
1949
+ if f.is_injective():
1950
+ injectives.append(f)
1951
+ else:
1952
+ break
1953
+ else:
1954
+ return True
1955
+
1956
+ if all(f.is_surjective() for f in injectives):
1957
+ return False
1958
+
1959
+ raise NotImplementedError("not enough information to deduce injectivity")
1960
+
1961
+ def is_surjective(self):
1962
+ """
1963
+ Tell whether ``self`` is surjective.
1964
+
1965
+ It raises :exc:`NotImplementedError` if it cannot be determined.
1966
+
1967
+ EXAMPLES::
1968
+
1969
+ sage: from sage.categories.map import FormalCompositeMap
1970
+ sage: V3 = QQ^3 # needs sage.modules
1971
+ sage: V2 = QQ^2 # needs sage.modules
1972
+ sage: V1 = QQ^1 # needs sage.modules
1973
+
1974
+ If both maps are surjective, the composition is surjective::
1975
+
1976
+ sage: # needs sage.modules
1977
+ sage: phi32 = V3.hom(Matrix([[1, 2], [3, 4], [5, 6]]), V2)
1978
+ sage: phi21 = V2.hom(Matrix([[1], [1]]), V1)
1979
+ sage: c_phi = FormalCompositeMap(Hom(V3, V1, phi32.category_for()),
1980
+ ....: phi32, phi21)
1981
+ sage: c_phi.is_surjective()
1982
+ True
1983
+
1984
+ If the second map is not surjective, the composition is not
1985
+ surjective::
1986
+
1987
+ sage: FormalCompositeMap(Hom(V3, V1, phi32.category_for()), # needs sage.modules
1988
+ ....: phi32,
1989
+ ....: V2.hom(Matrix([[0], [0]]), V1)).is_surjective()
1990
+ False
1991
+
1992
+ If the second map is an isomorphism and the first map is not
1993
+ surjective, then the composition is not surjective::
1994
+
1995
+ sage: FormalCompositeMap(Hom(V2, V1, phi32.category_for()), # needs sage.modules
1996
+ ....: V2.hom(Matrix([[0], [0]]), V1),
1997
+ ....: V1.hom(Matrix([[1]]), V1)).is_surjective()
1998
+ False
1999
+
2000
+ Otherwise, surjectivity of the composition cannot be determined::
2001
+
2002
+ sage: FormalCompositeMap(Hom(V2, V1, phi32.category_for()), # needs sage.modules
2003
+ ....: V2.hom(Matrix([[1, 1], [1, 1]]), V2),
2004
+ ....: V2.hom(Matrix([[1], [1]]), V1)).is_surjective()
2005
+ Traceback (most recent call last):
2006
+ ...
2007
+ NotImplementedError: not enough information to deduce surjectivity
2008
+ """
2009
+ try:
2010
+ # we try the category first
2011
+ # as of 2017-06, the MRO of this class does not get patched to
2012
+ # include the category's MorphismMethods (because it is a Cython
2013
+ # class); therefore, we cannot simply call "super" but need to
2014
+ # invoke the category method explicitly
2015
+ return self.getattr_from_category('is_surjective')()
2016
+ except (AttributeError, NotImplementedError):
2017
+ pass
2018
+
2019
+ surjectives = []
2020
+ for f in self.__list[::-1]:
2021
+ if f.is_surjective():
2022
+ surjectives.append(f)
2023
+ else:
2024
+ break
2025
+ else:
2026
+ return True
2027
+
2028
+ if all(f.is_injective() for f in surjectives):
2029
+ return False
2030
+
2031
+ raise NotImplementedError("not enough information to deduce surjectivity")
2032
+
2033
+ def domains(self):
2034
+ """
2035
+ Iterate over the domains of the factors of this map.
2036
+
2037
+ (This is useful in particular to check for loops in coercion maps.)
2038
+
2039
+ .. SEEALSO:: :meth:`Map.domains`
2040
+
2041
+ EXAMPLES::
2042
+
2043
+ sage: f = QQ.coerce_map_from(ZZ)
2044
+ sage: g = MatrixSpace(QQ, 2, 2).coerce_map_from(QQ) # needs sage.modules
2045
+ sage: list((g * f).domains()) # needs sage.modules
2046
+ [Integer Ring, Rational Field]
2047
+ """
2048
+ for f in self.__list:
2049
+ yield f.domain()
2050
+
2051
+ def section(self):
2052
+ """
2053
+ Compute a section map from sections of the factors of
2054
+ ``self`` if they have been implemented.
2055
+
2056
+ EXAMPLES::
2057
+
2058
+ sage: P.<x> = QQ[]
2059
+ sage: incl = P.coerce_map_from(ZZ)
2060
+ sage: sect = incl.section(); sect
2061
+ Composite map:
2062
+ From: Univariate Polynomial Ring in x over Rational Field
2063
+ To: Integer Ring
2064
+ Defn: Generic map:
2065
+ From: Univariate Polynomial Ring in x over Rational Field
2066
+ To: Rational Field
2067
+ then
2068
+ Generic map:
2069
+ From: Rational Field
2070
+ To: Integer Ring
2071
+ sage: p = x + 5; q = x + 2
2072
+ sage: sect(p-q)
2073
+ 3
2074
+
2075
+ the following example has been attached to :meth:`_integer_`
2076
+ of :class:`sage.rings.polynomial.polynomial_element.Polynomial`
2077
+ before (see comment there)::
2078
+
2079
+ sage: k = GF(47)
2080
+ sage: R.<x> = PolynomialRing(k)
2081
+ sage: R.coerce_map_from(ZZ).section()
2082
+ Composite map:
2083
+ From: Univariate Polynomial Ring in x over Finite Field of size 47
2084
+ To: Integer Ring
2085
+ Defn: Generic map:
2086
+ From: Univariate Polynomial Ring in x over Finite Field of size 47
2087
+ To: Finite Field of size 47
2088
+ then
2089
+ Lifting map:
2090
+ From: Finite Field of size 47
2091
+ To: Integer Ring
2092
+ sage: ZZ(R(45)) # indirect doctest
2093
+ 45
2094
+ sage: ZZ(3*x + 45) # indirect doctest
2095
+ Traceback (most recent call last):
2096
+ ...
2097
+ TypeError: 3*x + 45 is not a constant polynomial
2098
+ """
2099
+ sections = []
2100
+ for m in reversed(list(self)):
2101
+ try:
2102
+ sec = m.section()
2103
+ except TypeError:
2104
+ return None
2105
+ if sec is None:
2106
+ return None
2107
+ sections.append(sec)
2108
+
2109
+ from sage.categories.homset import Hom
2110
+ from sage.categories.sets_with_partial_maps import SetsWithPartialMaps
2111
+ H = Hom(self.codomain(), self.domain(), category=SetsWithPartialMaps())
2112
+ return FormalCompositeMap(H, sections)