passagemath-objects 10.6.41__cp312-cp312-win_amd64.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.
Files changed (281) hide show
  1. passagemath_objects/__init__.py +3 -0
  2. passagemath_objects-10.6.41.dist-info/DELVEWHEEL +2 -0
  3. passagemath_objects-10.6.41.dist-info/METADATA +115 -0
  4. passagemath_objects-10.6.41.dist-info/RECORD +281 -0
  5. passagemath_objects-10.6.41.dist-info/WHEEL +5 -0
  6. passagemath_objects-10.6.41.dist-info/top_level.txt +3 -0
  7. passagemath_objects.libs/libgmp-10-79b4110c7ea2b760f16cfef97e8a8a34.dll +0 -0
  8. sage/all__sagemath_objects.py +46 -0
  9. sage/arith/all__sagemath_objects.py +5 -0
  10. sage/arith/long.pxd +411 -0
  11. sage/arith/numerical_approx.cp312-win_amd64.pyd +0 -0
  12. sage/arith/numerical_approx.pxd +35 -0
  13. sage/arith/numerical_approx.pyx +75 -0
  14. sage/arith/power.cp312-win_amd64.pyd +0 -0
  15. sage/arith/power.pxd +31 -0
  16. sage/arith/power.pyx +127 -0
  17. sage/categories/action.cp312-win_amd64.pyd +0 -0
  18. sage/categories/action.pxd +29 -0
  19. sage/categories/action.pyx +641 -0
  20. sage/categories/algebra_functor.py +745 -0
  21. sage/categories/all__sagemath_objects.py +33 -0
  22. sage/categories/basic.py +71 -0
  23. sage/categories/cartesian_product.py +295 -0
  24. sage/categories/category.py +3401 -0
  25. sage/categories/category_cy_helper.cp312-win_amd64.pyd +0 -0
  26. sage/categories/category_cy_helper.pxd +8 -0
  27. sage/categories/category_cy_helper.pyx +322 -0
  28. sage/categories/category_singleton.cp312-win_amd64.pyd +0 -0
  29. sage/categories/category_singleton.pxd +3 -0
  30. sage/categories/category_singleton.pyx +342 -0
  31. sage/categories/category_types.py +637 -0
  32. sage/categories/category_with_axiom.py +2885 -0
  33. sage/categories/covariant_functorial_construction.py +703 -0
  34. sage/categories/facade_sets.py +228 -0
  35. sage/categories/functor.cp312-win_amd64.pyd +0 -0
  36. sage/categories/functor.pxd +7 -0
  37. sage/categories/functor.pyx +691 -0
  38. sage/categories/homset.py +1338 -0
  39. sage/categories/homsets.py +364 -0
  40. sage/categories/isomorphic_objects.py +73 -0
  41. sage/categories/map.cp312-win_amd64.pyd +0 -0
  42. sage/categories/map.pxd +34 -0
  43. sage/categories/map.pyx +2112 -0
  44. sage/categories/morphism.cp312-win_amd64.pyd +0 -0
  45. sage/categories/morphism.pxd +14 -0
  46. sage/categories/morphism.pyx +895 -0
  47. sage/categories/objects.py +167 -0
  48. sage/categories/primer.py +1696 -0
  49. sage/categories/pushout.py +4834 -0
  50. sage/categories/quotients.py +64 -0
  51. sage/categories/realizations.py +200 -0
  52. sage/categories/sets_cat.py +3228 -0
  53. sage/categories/sets_with_partial_maps.py +52 -0
  54. sage/categories/subobjects.py +64 -0
  55. sage/categories/subquotients.py +21 -0
  56. sage/categories/with_realizations.py +311 -0
  57. sage/cpython/__init__.py +28 -0
  58. sage/cpython/_py2_random.py +619 -0
  59. sage/cpython/all.py +3 -0
  60. sage/cpython/atexit.cp312-win_amd64.pyd +0 -0
  61. sage/cpython/atexit.pyx +269 -0
  62. sage/cpython/builtin_types.cp312-win_amd64.pyd +0 -0
  63. sage/cpython/builtin_types.pyx +7 -0
  64. sage/cpython/cython_metaclass.cp312-win_amd64.pyd +0 -0
  65. sage/cpython/cython_metaclass.h +117 -0
  66. sage/cpython/cython_metaclass.pxd +3 -0
  67. sage/cpython/cython_metaclass.pyx +130 -0
  68. sage/cpython/debug.cp312-win_amd64.pyd +0 -0
  69. sage/cpython/debug.pyx +302 -0
  70. sage/cpython/dict_del_by_value.cp312-win_amd64.pyd +0 -0
  71. sage/cpython/dict_del_by_value.pxd +9 -0
  72. sage/cpython/dict_del_by_value.pyx +191 -0
  73. sage/cpython/dict_internal.h +245 -0
  74. sage/cpython/getattr.cp312-win_amd64.pyd +0 -0
  75. sage/cpython/getattr.pxd +9 -0
  76. sage/cpython/getattr.pyx +439 -0
  77. sage/cpython/pycore_long.h +97 -0
  78. sage/cpython/pycore_long.pxd +10 -0
  79. sage/cpython/python_debug.h +44 -0
  80. sage/cpython/python_debug.pxd +47 -0
  81. sage/cpython/pyx_visit.h +13 -0
  82. sage/cpython/string.cp312-win_amd64.pyd +0 -0
  83. sage/cpython/string.pxd +76 -0
  84. sage/cpython/string.pyx +34 -0
  85. sage/cpython/string_impl.h +60 -0
  86. sage/cpython/type.cp312-win_amd64.pyd +0 -0
  87. sage/cpython/type.pxd +2 -0
  88. sage/cpython/type.pyx +40 -0
  89. sage/cpython/wrapperdescr.pxd +67 -0
  90. sage/ext/all__sagemath_objects.py +3 -0
  91. sage/ext/ccobject.h +64 -0
  92. sage/ext/cplusplus.pxd +17 -0
  93. sage/ext/mod_int.h +30 -0
  94. sage/ext/mod_int.pxd +24 -0
  95. sage/ext/stdsage.pxd +39 -0
  96. sage/groups/all__sagemath_objects.py +1 -0
  97. sage/groups/group.cp312-win_amd64.pyd +0 -0
  98. sage/groups/group.pxd +14 -0
  99. sage/groups/group.pyx +322 -0
  100. sage/groups/old.cp312-win_amd64.pyd +0 -0
  101. sage/groups/old.pxd +14 -0
  102. sage/groups/old.pyx +219 -0
  103. sage/libs/all__sagemath_objects.py +3 -0
  104. sage/libs/gmp/__init__.py +1 -0
  105. sage/libs/gmp/all.pxd +6 -0
  106. sage/libs/gmp/binop.pxd +23 -0
  107. sage/libs/gmp/misc.pxd +8 -0
  108. sage/libs/gmp/mpf.pxd +88 -0
  109. sage/libs/gmp/mpn.pxd +57 -0
  110. sage/libs/gmp/mpq.pxd +57 -0
  111. sage/libs/gmp/mpz.pxd +202 -0
  112. sage/libs/gmp/pylong.cp312-win_amd64.pyd +0 -0
  113. sage/libs/gmp/pylong.pxd +12 -0
  114. sage/libs/gmp/pylong.pyx +150 -0
  115. sage/libs/gmp/random.pxd +25 -0
  116. sage/libs/gmp/randomize.pxd +59 -0
  117. sage/libs/gmp/types.pxd +53 -0
  118. sage/libs/gmpxx.pxd +19 -0
  119. sage/misc/abstract_method.py +276 -0
  120. sage/misc/all__sagemath_objects.py +43 -0
  121. sage/misc/bindable_class.py +253 -0
  122. sage/misc/c3_controlled.cp312-win_amd64.pyd +0 -0
  123. sage/misc/c3_controlled.pxd +2 -0
  124. sage/misc/c3_controlled.pyx +1402 -0
  125. sage/misc/cachefunc.cp312-win_amd64.pyd +0 -0
  126. sage/misc/cachefunc.pxd +43 -0
  127. sage/misc/cachefunc.pyx +3781 -0
  128. sage/misc/call.py +188 -0
  129. sage/misc/classcall_metaclass.cp312-win_amd64.pyd +0 -0
  130. sage/misc/classcall_metaclass.pxd +14 -0
  131. sage/misc/classcall_metaclass.pyx +599 -0
  132. sage/misc/constant_function.cp312-win_amd64.pyd +0 -0
  133. sage/misc/constant_function.pyx +130 -0
  134. sage/misc/decorators.py +747 -0
  135. sage/misc/fast_methods.cp312-win_amd64.pyd +0 -0
  136. sage/misc/fast_methods.pxd +20 -0
  137. sage/misc/fast_methods.pyx +351 -0
  138. sage/misc/flatten.py +90 -0
  139. sage/misc/fpickle.cp312-win_amd64.pyd +0 -0
  140. sage/misc/fpickle.pyx +177 -0
  141. sage/misc/function_mangling.cp312-win_amd64.pyd +0 -0
  142. sage/misc/function_mangling.pxd +11 -0
  143. sage/misc/function_mangling.pyx +308 -0
  144. sage/misc/inherit_comparison.cp312-win_amd64.pyd +0 -0
  145. sage/misc/inherit_comparison.pxd +5 -0
  146. sage/misc/inherit_comparison.pyx +105 -0
  147. sage/misc/instancedoc.cp312-win_amd64.pyd +0 -0
  148. sage/misc/instancedoc.pyx +331 -0
  149. sage/misc/lazy_attribute.cp312-win_amd64.pyd +0 -0
  150. sage/misc/lazy_attribute.pyx +607 -0
  151. sage/misc/lazy_format.py +135 -0
  152. sage/misc/lazy_import.cp312-win_amd64.pyd +0 -0
  153. sage/misc/lazy_import.pyx +1299 -0
  154. sage/misc/lazy_import_cache.py +36 -0
  155. sage/misc/lazy_list.cp312-win_amd64.pyd +0 -0
  156. sage/misc/lazy_list.pxd +19 -0
  157. sage/misc/lazy_list.pyx +1187 -0
  158. sage/misc/lazy_string.cp312-win_amd64.pyd +0 -0
  159. sage/misc/lazy_string.pxd +7 -0
  160. sage/misc/lazy_string.pyx +546 -0
  161. sage/misc/misc.py +1066 -0
  162. sage/misc/misc_c.cp312-win_amd64.pyd +0 -0
  163. sage/misc/misc_c.pxd +3 -0
  164. sage/misc/misc_c.pyx +766 -0
  165. sage/misc/namespace_package.py +37 -0
  166. sage/misc/nested_class.cp312-win_amd64.pyd +0 -0
  167. sage/misc/nested_class.pxd +3 -0
  168. sage/misc/nested_class.pyx +394 -0
  169. sage/misc/persist.cp312-win_amd64.pyd +0 -0
  170. sage/misc/persist.pyx +1251 -0
  171. sage/misc/prandom.py +418 -0
  172. sage/misc/randstate.cp312-win_amd64.pyd +0 -0
  173. sage/misc/randstate.pxd +30 -0
  174. sage/misc/randstate.pyx +1059 -0
  175. sage/misc/repr.py +203 -0
  176. sage/misc/reset.cp312-win_amd64.pyd +0 -0
  177. sage/misc/reset.pyx +196 -0
  178. sage/misc/sage_ostools.cp312-win_amd64.pyd +0 -0
  179. sage/misc/sage_ostools.pyx +323 -0
  180. sage/misc/sage_timeit.py +276 -0
  181. sage/misc/sage_timeit_class.cp312-win_amd64.pyd +0 -0
  182. sage/misc/sage_timeit_class.pyx +120 -0
  183. sage/misc/sage_unittest.py +637 -0
  184. sage/misc/sageinspect.py +2768 -0
  185. sage/misc/session.cp312-win_amd64.pyd +0 -0
  186. sage/misc/session.pyx +392 -0
  187. sage/misc/superseded.py +557 -0
  188. sage/misc/test_nested_class.py +228 -0
  189. sage/misc/timing.py +264 -0
  190. sage/misc/unknown.py +222 -0
  191. sage/misc/verbose.py +253 -0
  192. sage/misc/weak_dict.cp312-win_amd64.pyd +0 -0
  193. sage/misc/weak_dict.pxd +15 -0
  194. sage/misc/weak_dict.pyx +1231 -0
  195. sage/modules/all__sagemath_objects.py +1 -0
  196. sage/modules/module.cp312-win_amd64.pyd +0 -0
  197. sage/modules/module.pxd +5 -0
  198. sage/modules/module.pyx +329 -0
  199. sage/rings/all__sagemath_objects.py +3 -0
  200. sage/rings/integer_fake.h +22 -0
  201. sage/rings/integer_fake.pxd +55 -0
  202. sage/sets/all__sagemath_objects.py +3 -0
  203. sage/sets/pythonclass.cp312-win_amd64.pyd +0 -0
  204. sage/sets/pythonclass.pxd +9 -0
  205. sage/sets/pythonclass.pyx +247 -0
  206. sage/structure/__init__.py +13 -0
  207. sage/structure/all.py +30 -0
  208. sage/structure/category_object.cp312-win_amd64.pyd +0 -0
  209. sage/structure/category_object.pxd +28 -0
  210. sage/structure/category_object.pyx +1087 -0
  211. sage/structure/coerce.cp312-win_amd64.pyd +0 -0
  212. sage/structure/coerce.pxd +44 -0
  213. sage/structure/coerce.pyx +2107 -0
  214. sage/structure/coerce_actions.cp312-win_amd64.pyd +0 -0
  215. sage/structure/coerce_actions.pxd +27 -0
  216. sage/structure/coerce_actions.pyx +988 -0
  217. sage/structure/coerce_dict.cp312-win_amd64.pyd +0 -0
  218. sage/structure/coerce_dict.pxd +51 -0
  219. sage/structure/coerce_dict.pyx +1557 -0
  220. sage/structure/coerce_exceptions.py +23 -0
  221. sage/structure/coerce_maps.cp312-win_amd64.pyd +0 -0
  222. sage/structure/coerce_maps.pxd +28 -0
  223. sage/structure/coerce_maps.pyx +718 -0
  224. sage/structure/debug_options.cp312-win_amd64.pyd +0 -0
  225. sage/structure/debug_options.pxd +6 -0
  226. sage/structure/debug_options.pyx +54 -0
  227. sage/structure/dynamic_class.py +541 -0
  228. sage/structure/element.cp312-win_amd64.pyd +0 -0
  229. sage/structure/element.pxd +272 -0
  230. sage/structure/element.pyx +4772 -0
  231. sage/structure/element_wrapper.cp312-win_amd64.pyd +0 -0
  232. sage/structure/element_wrapper.pxd +12 -0
  233. sage/structure/element_wrapper.pyx +582 -0
  234. sage/structure/factorization.py +1422 -0
  235. sage/structure/factorization_integer.py +105 -0
  236. sage/structure/factory.cp312-win_amd64.pyd +0 -0
  237. sage/structure/factory.pyx +786 -0
  238. sage/structure/formal_sum.py +489 -0
  239. sage/structure/gens_py.py +73 -0
  240. sage/structure/global_options.py +1743 -0
  241. sage/structure/indexed_generators.py +863 -0
  242. sage/structure/list_clone.cp312-win_amd64.pyd +0 -0
  243. sage/structure/list_clone.pxd +65 -0
  244. sage/structure/list_clone.pyx +1867 -0
  245. sage/structure/list_clone_demo.cp312-win_amd64.pyd +0 -0
  246. sage/structure/list_clone_demo.pyx +248 -0
  247. sage/structure/list_clone_timings.py +179 -0
  248. sage/structure/list_clone_timings_cy.cp312-win_amd64.pyd +0 -0
  249. sage/structure/list_clone_timings_cy.pyx +86 -0
  250. sage/structure/mutability.cp312-win_amd64.pyd +0 -0
  251. sage/structure/mutability.pxd +21 -0
  252. sage/structure/mutability.pyx +348 -0
  253. sage/structure/nonexact.py +69 -0
  254. sage/structure/parent.cp312-win_amd64.pyd +0 -0
  255. sage/structure/parent.pxd +112 -0
  256. sage/structure/parent.pyx +3093 -0
  257. sage/structure/parent_base.cp312-win_amd64.pyd +0 -0
  258. sage/structure/parent_base.pxd +13 -0
  259. sage/structure/parent_base.pyx +44 -0
  260. sage/structure/parent_gens.cp312-win_amd64.pyd +0 -0
  261. sage/structure/parent_gens.pxd +22 -0
  262. sage/structure/parent_gens.pyx +377 -0
  263. sage/structure/parent_old.cp312-win_amd64.pyd +0 -0
  264. sage/structure/parent_old.pxd +25 -0
  265. sage/structure/parent_old.pyx +294 -0
  266. sage/structure/proof/__init__.py +1 -0
  267. sage/structure/proof/all.py +243 -0
  268. sage/structure/proof/proof.py +300 -0
  269. sage/structure/richcmp.cp312-win_amd64.pyd +0 -0
  270. sage/structure/richcmp.pxd +213 -0
  271. sage/structure/richcmp.pyx +495 -0
  272. sage/structure/sage_object.cp312-win_amd64.pyd +0 -0
  273. sage/structure/sage_object.pxd +3 -0
  274. sage/structure/sage_object.pyx +988 -0
  275. sage/structure/sage_object_test.py +19 -0
  276. sage/structure/sequence.py +937 -0
  277. sage/structure/set_factories.py +1178 -0
  278. sage/structure/set_factories_example.py +527 -0
  279. sage/structure/support_view.py +179 -0
  280. sage/structure/test_factory.py +56 -0
  281. sage/structure/unique_representation.py +1359 -0
@@ -0,0 +1,786 @@
1
+ # sage_setup: distribution = sagemath-objects
2
+ r"""
3
+ Factory for cached representations
4
+
5
+ .. SEEALSO::
6
+
7
+ :mod:`sage.structure.unique_representation`
8
+
9
+ Using a :class:`UniqueFactory` is one way of implementing a *cached
10
+ representation behaviour*. In spite of its name, using a
11
+ :class:`UniqueFactory` is not enough to ensure the *unique representation
12
+ behaviour*. See :mod:`~sage.structure.unique_representation` for a
13
+ detailed explanation.
14
+
15
+ With a :class:`UniqueFactory`, one can preprocess the given arguments. There
16
+ is special support for specifying a subset of the arguments that serve as the
17
+ unique key, so that still *all* given arguments are used to create a new
18
+ instance, but only the specified subset is used to look up in the
19
+ cache. Typically, this is used to construct objects that accept an optional
20
+ ``check=[True|False]`` argument, but whose result should be unique
21
+ regardless of said optional argument. (This use case should be handled with
22
+ care, though: Any checking which isn't done in the ``create_key`` or
23
+ ``create_key_and_extra_args`` method will be done only when a new object is
24
+ generated, but not when a cached object is retrieved from cache.
25
+ Consequently, if the factory is once called with ``check=False``, a
26
+ subsequent call with ``check=True`` cannot be expected to perform all checks
27
+ unless these checks are all in the ``create_key`` or
28
+ ``create_key_and_extra_args`` method.)
29
+
30
+ For a class derived from
31
+ :class:`~sage.structure.unique_representation.CachedRepresentation`, argument
32
+ preprocessing can be obtained by providing a custom static ``__classcall__``
33
+ or ``__classcall_private__`` method, but this seems less transparent. When
34
+ argument preprocessing is not needed or the preprocess is not very
35
+ sophisticated, then generally
36
+ :class:`~sage.structure.unique_representation.CachedRepresentation` is much
37
+ easier to use than a factory.
38
+
39
+ AUTHORS:
40
+
41
+ - Robert Bradshaw (2008): initial version.
42
+ - Simon King (2013): extended documentation.
43
+ - Julian Rueth (2014-05-09): use ``_cache_key`` if parameters are unhashable
44
+ """
45
+
46
+ #*****************************************************************************
47
+ # Copyright (C) 2008 Robert Bradshaw <robertwb@math.washington.edu>
48
+ # 2014 Julian Rueth <julian.rueth@fsfe.org>
49
+ #
50
+ # This program is free software: you can redistribute it and/or modify
51
+ # it under the terms of the GNU General Public License as published by
52
+ # the Free Software Foundation, either version 2 of the License, or
53
+ # (at your option) any later version.
54
+ # http://www.gnu.org/licenses/
55
+ #*****************************************************************************
56
+
57
+ import types
58
+
59
+ from sage.structure.sage_object cimport SageObject
60
+
61
+ cdef sage_version = None
62
+ from sage.cpython.string cimport bytes_to_str
63
+
64
+ cimport sage.misc.weak_dict
65
+ from sage.misc.cachefunc cimport cache_key as _cache_key
66
+
67
+
68
+ cdef class UniqueFactory(SageObject):
69
+ """
70
+ This class is intended to make it easy to cache objects.
71
+
72
+ It is based on the idea that the object is uniquely defined by a set of
73
+ defining data (the key). There is also the possibility of some
74
+ non-defining data (extra args) which will be used in initial creation,
75
+ but not affect the caching.
76
+
77
+ .. WARNING::
78
+
79
+ This class only provides *cached representation behaviour*. Hence,
80
+ using :class:`UniqueFactory`, it is still possible to create distinct
81
+ objects that evaluate equal. Unique representation behaviour can be
82
+ added, for example, by additionally inheriting from
83
+ :class:`sage.misc.fast_methods.WithEqualityById`.
84
+
85
+ The objects created are cached (using weakrefs) based on their key and
86
+ returned directly rather than re-created if requested again. Pickling is
87
+ taken care of by the factory, and will return the same object for the same
88
+ version of Sage, and distinct (but hopefully equal) objects for different
89
+ versions of Sage.
90
+
91
+ .. WARNING::
92
+
93
+ The objects returned by a :class:`UniqueFactory` must be instances of
94
+ new style classes (hence, they must be instances of :class:`object`)
95
+ that must not only allow a weak reference, but must accept general
96
+ attribute assignment. Otherwise, pickling won't work.
97
+
98
+ USAGE:
99
+
100
+ A *unique factory* provides a way to create objects from parameters
101
+ (the type of these objects can depend on the parameters, and is often
102
+ determined only at runtime) and to cache them by a certain key
103
+ derived from these parameters, so that when the factory is being
104
+ called again with the same parameters (or just with parameters which
105
+ yield the same key), the object is being returned from cache rather
106
+ than constructed anew.
107
+
108
+ An implementation of a unique factory consists of a factory class and
109
+ an instance of this factory class.
110
+
111
+ The factory class has to be a class inheriting from ``UniqueFactory``.
112
+ Typically it only needs to implement :meth:`create_key` (a method that
113
+ creates a key from the given parameters, under which key the object
114
+ will be stored in the cache) and :meth:`create_object` (a method that
115
+ returns the actual object from the key). Sometimes, one would also
116
+ implement :meth:`create_key_and_extra_args` (this differs from
117
+ :meth:`create_key` in allowing to also create some additional
118
+ arguments from the given parameters, which arguments then get passed
119
+ to :meth:`create_object` and thus can have an effect on the initial
120
+ creation of the object, but do *not* affect the key) or
121
+ :meth:`other_keys`. Other methods are not supposed to be overloaded.
122
+
123
+ The factory class itself cannot be called to create objects. Instead,
124
+ an instance of the factory class has to be created first. For
125
+ technical reasons, this instance has to be provided with a name that
126
+ allows Sage to find its definition. Specifically, the name of the
127
+ factory instance (or the full path to it, if it is not in the global
128
+ namespace) has to be passed to the factory class as a string variable.
129
+ So, if our factory class has been called ``A`` and is located in
130
+ ``sage/spam/battletoads.py``, then we need to define an instance (say,
131
+ ``B``) of ``A`` by writing ``B = A("sage.spam.battletoads.B")``
132
+ (or ``B = A("B")`` if this ``B`` will be imported into global
133
+ namespace). This instance can then be used to create objects (by
134
+ calling ``B(*parameters)``).
135
+
136
+ Notice that the objects created by the factory don't inherit from the
137
+ factory class. They *do* know about the factory that created them (this
138
+ information, along with the keys under which this factory caches them,
139
+ is stored in the ``_factory_data`` attributes of the objects), but not
140
+ via inheritance.
141
+
142
+ EXAMPLES:
143
+
144
+ The below examples are rather artificial and illustrate particular
145
+ aspects. For a "real-life" usage case of ``UniqueFactory``, see
146
+ the finite field factory in :mod:`sage.rings.finite_rings.finite_field_constructor`.
147
+
148
+ In many cases, a factory class is implemented by providing the two
149
+ methods :meth:`create_key` and :meth:`create_object`. In our example,
150
+ we want to demonstrate how to use "extra arguments" to choose a specific
151
+ implementation, with preference given to an instance found in the cache,
152
+ even if its implementation is different. Hence, we implement
153
+ :meth:`create_key_and_extra_args` rather than :meth:`create_key`, putting
154
+ the chosen implementation into the extra arguments. Then, in the
155
+ :meth:`create_object` method, we create and return instances of the
156
+ specified implementation.
157
+ ::
158
+
159
+ sage: from sage.structure.factory import UniqueFactory
160
+ sage: class MyFactory(UniqueFactory):
161
+ ....: def create_key_and_extra_args(self, *args, **kwds):
162
+ ....: return args, {'impl':kwds.get('impl', None)}
163
+ ....: def create_object(self, version, key, **extra_args):
164
+ ....: impl = extra_args['impl']
165
+ ....: if impl == 'C':
166
+ ....: return C(*key)
167
+ ....: if impl == 'D':
168
+ ....: return D(*key)
169
+ ....: return E(*key)
170
+ ....:
171
+
172
+ Now we can create a factory instance. It is supposed to be found under the
173
+ name ``'F'`` in the ``__main__`` module. Note that in an interactive
174
+ session, ``F`` would automatically be in the ``__main__`` module. Hence,
175
+ the second and third of the following four lines are only needed in
176
+ doctests. ::
177
+
178
+ sage: F = MyFactory("__main__.F")
179
+ sage: import __main__
180
+ sage: __main__.F = F
181
+ sage: loads(dumps(F)) is F
182
+ True
183
+
184
+ Now we create three classes ``C``, ``D`` and ``E``. The first is a Cython
185
+ extension-type class that does not allow weak references nor attribute
186
+ assignment. The second is a Python class that is not derived from
187
+ :class:`object`. The third allows attribute assignment and is derived
188
+ from :class:`object`. ::
189
+
190
+ sage: cython("cdef class C: pass") # needs sage.misc.cython
191
+ sage: class D:
192
+ ....: def __init__(self, *args):
193
+ ....: self.t = args
194
+ ....: def __repr__(self):
195
+ ....: return "D%s"%repr(self.t)
196
+ ....:
197
+ sage: class E(D, object): pass
198
+
199
+ Again, being in a doctest, we need to put the class ``D`` into the
200
+ ``__main__`` module, so that Python can find it::
201
+
202
+ sage: import __main__
203
+ sage: __main__.D = D
204
+
205
+ It is impossible to create an instance of ``C`` with our factory, since it
206
+ does not allow weak references::
207
+
208
+ sage: F(1, impl='C') # needs sage.misc.cython
209
+ Traceback (most recent call last):
210
+ ...
211
+ TypeError: cannot create weak reference to '....C' object
212
+
213
+ Let us try again, with a Cython class that does allow weak
214
+ references. Now, creation of an instance using the factory works::
215
+
216
+ sage: cython( # needs sage.misc.cython
217
+ ....: '''
218
+ ....: cdef class C:
219
+ ....: cdef __weakref__
220
+ ....: ''')
221
+ ....:
222
+ sage: c = F(1, impl='C') # needs sage.misc.cython
223
+ sage: isinstance(c, C) # needs sage.misc.cython
224
+ True
225
+
226
+ The cache is used when calling the factory again---even if it is suggested
227
+ to use a different implementation. This is because the implementation is
228
+ only considered an "extra argument" that does not count for the key.
229
+ ::
230
+
231
+ sage: c is F(1, impl='C') is F(1, impl='D') is F(1) # needs sage.misc.cython
232
+ True
233
+
234
+ However, pickling and unpickling does not use the cache. This is because
235
+ the factory has tried to assign an attribute to the instance that provides
236
+ information on the key used to create the instance, but failed::
237
+
238
+ sage: loads(dumps(c)) is c # needs sage.misc.cython
239
+ False
240
+ sage: hasattr(c, '_factory_data') # needs sage.misc.cython
241
+ False
242
+
243
+ We have already seen that our factory will only take the requested
244
+ implementation into account if the arguments used as key have not been
245
+ used yet. So, we use other arguments to create an instance of class
246
+ ``D``::
247
+
248
+ sage: d = F(2, impl='D')
249
+ sage: isinstance(d, D)
250
+ True
251
+
252
+ The factory only knows about the pickling protocol used by new style
253
+ classes. Hence, again, pickling and unpickling fails to use the cache,
254
+ even though the "factory data" are now available (this is not the case
255
+ on Python 3 which *only* has new style classes)::
256
+
257
+ sage: loads(dumps(d)) is d
258
+ True
259
+ sage: d._factory_data
260
+ (<__main__.MyFactory object at ...>,
261
+ (...),
262
+ (2,),
263
+ {'impl': 'D'})
264
+
265
+ Only when we have a new style class that can be weak referenced and allows
266
+ for attribute assignment, everything works::
267
+
268
+ sage: e = F(3)
269
+ sage: isinstance(e, E)
270
+ True
271
+ sage: loads(dumps(e)) is e
272
+ True
273
+ sage: e._factory_data
274
+ (<__main__.MyFactory object at ...>,
275
+ (...),
276
+ (3,),
277
+ {'impl': None})
278
+ """
279
+ cdef readonly _name
280
+ cdef readonly _cache
281
+
282
+ def __init__(self, name):
283
+ """
284
+ INPUT:
285
+
286
+ - ``name`` -- string; a name in the global namespace referring to
287
+ ``self`` or a fully qualified path name to ``self``, which is used to
288
+ locate the factory on unpickling
289
+
290
+ EXAMPLES::
291
+
292
+ sage: from sage.structure.factory import UniqueFactory
293
+ sage: fake_factory = UniqueFactory('ZZ')
294
+ sage: loads(dumps(fake_factory))
295
+ Integer Ring
296
+ sage: fake_factory = UniqueFactory('sage.rings.rational_field.QQ')
297
+ sage: loads(dumps(fake_factory))
298
+ Rational Field
299
+ """
300
+ self._name = name
301
+ self._cache = sage.misc.weak_dict.WeakValueDictionary()
302
+
303
+ def __reduce__(self):
304
+ """
305
+ EXAMPLES::
306
+
307
+ sage: A = FiniteField(127)
308
+ sage: A is loads(dumps(A)) # indirect doctest
309
+ True
310
+
311
+ sage: # needs sage.rings.finite_rings
312
+ sage: B = FiniteField(3^3,'b')
313
+ sage: B is loads(dumps(B))
314
+ True
315
+ sage: C = FiniteField(2^16,'c')
316
+ sage: C is loads(dumps(C))
317
+ True
318
+ sage: D = FiniteField(3^20,'d')
319
+ sage: D is loads(dumps(D))
320
+ True
321
+
322
+ TESTS::
323
+
324
+ sage: loads(dumps(FiniteField)) is FiniteField
325
+ True
326
+ sage: from sage.structure.test_factory import test_factory
327
+ sage: loads(dumps(test_factory)) is test_factory
328
+ True
329
+ """
330
+ return lookup_global, (self._name,)
331
+
332
+ def __call__(self, *args, **kwds):
333
+ """
334
+ This is the method invoked to create objects. It first creates a key
335
+ from the given parameters, then if an object with that key already
336
+ exists returns it, and otherwise creates one and stores a weak reference
337
+ to it in its dictionary.
338
+
339
+ Do not override this method. Instead, override ``create_key`` and
340
+ ``create_object`` and put the docstring in the body of the class.
341
+
342
+ EXAMPLES::
343
+
344
+ sage: from sage.structure.test_factory import test_factory
345
+ sage: _ = test_factory(1,2,3); _
346
+ Making object (1, 2, 3)
347
+ <sage.structure.test_factory.A object at ...>
348
+
349
+ It already created one, so don't re-create::
350
+
351
+ sage: test_factory(1,2,3)
352
+ <sage.structure.test_factory.A object at ...>
353
+ sage: test_factory(1,2,3) is test_factory(1,2,3)
354
+ True
355
+
356
+ Of course, with a different key, a new object will be created::
357
+
358
+ sage: test_factory(1,2,3) is test_factory(1,2,4)
359
+ Making object (1, 2, 4)
360
+ False
361
+ """
362
+ key, kwds = self.create_key_and_extra_args(*args, **kwds)
363
+ version = self.get_version(sage_version)
364
+ return self.get_object(version, key, kwds)
365
+
366
+ cpdef get_object(self, version, key, extra_args):
367
+ """
368
+ Return the object corresponding to ``key``, creating it with
369
+ ``extra_args`` if necessary (for example, it isn't in the cache
370
+ or it is unpickling from an older version of Sage).
371
+
372
+ EXAMPLES::
373
+
374
+ sage: from sage.structure.test_factory import test_factory
375
+ sage: a = test_factory.get_object(3.0, 'a', {}); a
376
+ Making object a
377
+ <sage.structure.test_factory.A object at ...>
378
+ sage: test_factory.get_object(3.0, 'a', {}) is test_factory.get_object(3.0, 'a', {})
379
+ True
380
+ sage: test_factory.get_object(3.0, 'a', {}) is test_factory.get_object(3.1, 'a', {})
381
+ Making object a
382
+ False
383
+ sage: test_factory.get_object(3.0, 'a', {}) is test_factory.get_object(3.0, 'b', {})
384
+ Making object b
385
+ False
386
+
387
+ TESTS:
388
+
389
+ Check that :issue:`16317` has been fixed, i.e., caching works for
390
+ unhashable objects::
391
+
392
+ sage: K.<u> = Qq(4) # needs sage.rings.padics
393
+ sage: d = test_factory.get_object(3.0, (K(1), 'c'), {}) # needs sage.rings.padics
394
+ Making object (1 + O(2^20), 'c')
395
+ sage: d is test_factory.get_object(3.0, (K(1), 'c'), {}) # needs sage.rings.padics
396
+ True
397
+ """
398
+ cache_key = key
399
+ try:
400
+ try:
401
+ return self._cache[version, cache_key]
402
+ except TypeError: # key is unhashable
403
+ cache_key = _cache_key(cache_key)
404
+ return self._cache[version, cache_key]
405
+ except KeyError:
406
+ pass
407
+ obj = self.create_object(version, key, **extra_args)
408
+ self._cache[version, cache_key] = obj
409
+ try:
410
+ for key in self.other_keys(key, obj):
411
+ try:
412
+ self._cache[version, key] = obj
413
+ except TypeError: # key is unhashable
414
+ self._cache[version, _cache_key(key)] = obj
415
+ obj._factory_data = self, version, key, extra_args
416
+
417
+ # Install a custom __reduce__ method on the instance "obj"
418
+ # that we just created. We only do this if the class of
419
+ # "obj" has a generic __reduce__ method, which is either
420
+ # object.__reduce__ or __reduce_cython__, the
421
+ # auto-generated pickling function for Cython.
422
+ f = obj.__class__.__reduce__
423
+ if f.__objclass__ is object or f.__name__ == "__reduce_cython__":
424
+ obj.__reduce_ex__ = types.MethodType(generic_factory_reduce, obj)
425
+ except AttributeError:
426
+ pass
427
+ return obj
428
+
429
+ cpdef get_version(self, sage_version):
430
+ """
431
+ This is provided to allow more or less granular control over
432
+ pickle versioning. Objects pickled in the same version of Sage
433
+ will unpickle to the same rather than simply equal objects. This
434
+ can provide significant gains as arithmetic must be performed on
435
+ objects with identical parents. However, if there has been an
436
+ incompatible change (e.g. in element representation) we want the
437
+ version number to change so coercion is forced between the two
438
+ parents.
439
+
440
+ Defaults to the Sage version that is passed in, but coarser
441
+ granularity can be provided.
442
+
443
+ EXAMPLES::
444
+
445
+ sage: from sage.structure.test_factory import test_factory
446
+ sage: test_factory.get_version((3,1,0))
447
+ (3, 1, 0)
448
+ """
449
+ global sage_version
450
+ if sage_version is None:
451
+ from sage.version import version as sage_version
452
+ sage_version = sage_version.split('.')
453
+ for i in range(len(sage_version)):
454
+ try:
455
+ sage_version[i] = int(sage_version[i])
456
+ except ValueError:
457
+ pass
458
+ sage_version = tuple(sage_version)
459
+ return sage_version
460
+
461
+ def create_key_and_extra_args(self, *args, **kwds):
462
+ r"""
463
+ Return a tuple containing the key (uniquely defining data)
464
+ and any extra arguments (empty by default).
465
+
466
+ Defaults to :meth:`create_key`.
467
+
468
+ EXAMPLES::
469
+
470
+ sage: from sage.structure.test_factory import test_factory
471
+ sage: test_factory.create_key_and_extra_args(1, 2, key=5)
472
+ ((1, 2), {})
473
+ sage: GF.create_key_and_extra_args(3)
474
+ ((3, ('x',), None, 'modn', 3, 1, True, None, None, None, True, False), {})
475
+ """
476
+ return self.create_key(*args, **kwds), {}
477
+
478
+ def create_key(self, *args, **kwds):
479
+ """
480
+ Given the parameters (arguments and keywords), create a key
481
+ that uniquely determines this object.
482
+
483
+ EXAMPLES::
484
+
485
+ sage: from sage.structure.test_factory import test_factory
486
+ sage: test_factory.create_key(1, 2, key=5)
487
+ (1, 2)
488
+ """
489
+ raise NotImplementedError
490
+
491
+ def create_object(self, version, key, **extra_args):
492
+ """
493
+ Create the object from the key and extra arguments. This is only
494
+ called if the object was not found in the cache.
495
+
496
+ EXAMPLES::
497
+
498
+ sage: from sage.structure.test_factory import test_factory
499
+ sage: test_factory.create_object(0, (1,2,3))
500
+ Making object (1, 2, 3)
501
+ <sage.structure.test_factory.A object at ...>
502
+ sage: test_factory('a')
503
+ Making object ('a',)
504
+ <sage.structure.test_factory.A object at ...>
505
+ sage: test_factory('a') # NOT called again
506
+ <sage.structure.test_factory.A object at ...>
507
+ """
508
+ raise NotImplementedError
509
+
510
+ cpdef other_keys(self, key, obj):
511
+ """
512
+ Sometimes during object creation, certain defaults are chosen which
513
+ may result in a new (more specific) key. This allows the more specific
514
+ key to be regarded as equivalent to the original key returned by
515
+ :meth:`create_key` for the purpose of lookup in the cache, and is used
516
+ for pickling.
517
+
518
+ EXAMPLES:
519
+
520
+ The ``GF`` factory used to have a custom :meth:`other_keys`
521
+ method, but this was removed in :issue:`16934`::
522
+
523
+ sage: # needs sage.libs.linbox sage.rings.finite_rings
524
+ sage: key, _ = GF.create_key_and_extra_args(27, 'k'); key
525
+ (27, ('k',), x^3 + 2*x + 1, 'givaro', 3, 3, True, None, 'poly', True, True, True)
526
+ sage: K = GF.create_object(0, key); K
527
+ Finite Field in k of size 3^3
528
+ sage: GF.other_keys(key, K)
529
+ []
530
+
531
+ sage: K = GF(7^40, 'a') # needs sage.rings.finite_rings
532
+ sage: loads(dumps(K)) is K # needs sage.rings.finite_rings
533
+ True
534
+ """
535
+ return []
536
+
537
+ cpdef reduce_data(self, obj):
538
+ """
539
+ The results of this function can be returned from
540
+ :meth:`__reduce__`. This is here so the factory internals can
541
+ change without having to re-write :meth:`__reduce__` methods
542
+ that use it.
543
+
544
+ EXAMPLES::
545
+
546
+ sage: # needs sage.modules
547
+ sage: from sage.modules.free_module import FreeModuleFactory_with_standard_basis as F
548
+ sage: V = F(ZZ, 5)
549
+ sage: factory, data = F.reduce_data(V)
550
+ sage: factory(*data)
551
+ Ambient free module of rank 5 over the principal ideal domain Integer Ring
552
+ sage: factory(*data) is V
553
+ True
554
+
555
+ sage: from sage.structure.test_factory import test_factory
556
+ sage: a = test_factory(1, 2)
557
+ Making object (1, 2)
558
+ sage: test_factory.reduce_data(a)
559
+ (<built-in function generic_factory_unpickle>,
560
+ (<sage.structure.test_factory.UniqueFactoryTester object at ...>,
561
+ (...),
562
+ (1, 2),
563
+ {}))
564
+
565
+ Note that the ellipsis ``(...)`` here stands for the Sage
566
+ version.
567
+ """
568
+ return generic_factory_unpickle, obj._factory_data
569
+
570
+ # This is used to handle old UniqueFactory pickles
571
+ factory_unpickles = {}
572
+
573
+
574
+ def register_factory_unpickle(name, callable):
575
+ """
576
+ Register a callable to handle the unpickling from an old
577
+ :class:`UniqueFactory` object.
578
+
579
+ :class:`UniqueFactory` pickles use a global name through
580
+ :func:`generic_factory_unpickle()`, so the usual
581
+ :func:`~sage.misc.persist.register_unpickle_override()`
582
+ cannot be used here.
583
+
584
+ .. SEEALSO::
585
+
586
+ :func:`generic_factory_unpickle()`
587
+
588
+ TESTS:
589
+
590
+ This is similar to the example given in
591
+ :func:`generic_factory_unpickle()`, but here we will use a function to
592
+ explicitly return a polynomial ring.
593
+
594
+ First, we create the factory. In a doctest, it is needed to explicitly put
595
+ it into ``__main__``, so that it can be located when pickling. Also, it is
596
+ needed that we work with a new-style class::
597
+
598
+ sage: from sage.structure.factory import UniqueFactory, register_factory_unpickle
599
+ sage: import __main__
600
+ sage: class OldStuff():
601
+ ....: def __init__(self, n, **extras):
602
+ ....: self.n = n
603
+ ....: def __repr__(self):
604
+ ....: return "Rotten old thing of level {}".format(self.n)
605
+ sage: __main__.OldStuff = OldStuff
606
+ sage: class MyFactory(UniqueFactory):
607
+ ....: def create_object(self, version, key, **extras):
608
+ ....: return OldStuff(key[0])
609
+ ....: def create_key(self, *args):
610
+ ....: return args
611
+ sage: G = MyFactory('__main__.G')
612
+ sage: __main__.G = G
613
+ sage: a = G(3); a
614
+ Rotten old thing of level 3
615
+ sage: loads(dumps(a)) is a
616
+ True
617
+
618
+ Now, we create a pickle (the string returned by ``dumps(a)``)::
619
+
620
+ sage: s = dumps(a)
621
+
622
+ We create the function which will handle the unpickling::
623
+
624
+ sage: def foo(n, **kwds):
625
+ ....: return PolynomialRing(QQ, n, 'x')
626
+ sage: register_factory_unpickle('__main__.G', foo)
627
+
628
+ The old pickle correctly unpickles as an explicit polynomial ring::
629
+
630
+ sage: loads(s)
631
+ Multivariate Polynomial Ring in x0, x1, x2 over Rational Field
632
+ """
633
+ #global factory_unpickles
634
+ factory_unpickles[name] = callable
635
+
636
+
637
+ def generic_factory_unpickle(factory, *args):
638
+ """
639
+ Method used for unpickling the object.
640
+
641
+ The unpickling mechanism needs a plain Python function to call.
642
+ It takes a factory as the first argument, passes the rest of the
643
+ arguments onto the factory's :meth:`UniqueFactory.get_object` method.
644
+
645
+ EXAMPLES::
646
+
647
+ sage: # needs sage.modules
648
+ sage: from sage.modules.free_module import FreeModuleFactory_with_standard_basis as F
649
+ sage: V = F(ZZ, 5)
650
+ sage: func, data = F.reduce_data(V)
651
+ sage: func is sage.structure.factory.generic_factory_unpickle
652
+ True
653
+ sage: sage.structure.factory.generic_factory_unpickle(*data) is V
654
+ True
655
+
656
+ TESTS:
657
+
658
+ The following was enabled in :issue:`16349`. Suppose we have defined
659
+ (somewhere in the library of an old Sage version) a unique factory; in our
660
+ example below, it returns polynomial rings. Now suppose that we want to
661
+ replace the factory by something else, say, a class that provides the
662
+ unique parent behaviour using
663
+ :class:`~sage.structure.unique_representation.UniqueRepresentation`. We
664
+ show here how to make it possible to unpickle a pickle created with the
665
+ factory, automatically turning it into an instance of the new class.
666
+
667
+ First, we create the factory. In a doctest, it is needed to explicitly put
668
+ it into ``__main__``, so that it can be located when pickling. Also, it is
669
+ needed that we work with a new-style class::
670
+
671
+ sage: from sage.structure.factory import UniqueFactory
672
+ sage: import __main__
673
+ sage: class OldStuff():
674
+ ....: def __init__(self, n, **extras):
675
+ ....: self.n = n
676
+ ....: def __repr__(self):
677
+ ....: return "Rotten old thing of level {}".format(self.n)
678
+ sage: __main__.OldStuff = OldStuff
679
+ sage: class MyFactory(UniqueFactory):
680
+ ....: def create_object(self, version, key, **extras):
681
+ ....: return OldStuff(key[0])
682
+ ....: def create_key(self, *args):
683
+ ....: return args
684
+ sage: F = MyFactory('__main__.F')
685
+ sage: __main__.F = F
686
+ sage: a = F(3); a
687
+ Rotten old thing of level 3
688
+ sage: loads(dumps(a)) is a
689
+ True
690
+
691
+ Now, we create a pickle (the string returned by ``dumps(a)``)::
692
+
693
+ sage: s = dumps(a)
694
+
695
+ We create a new class, derived from
696
+ :class:`~sage.structure.unique_representation.UniqueRepresentation`, that
697
+ shall replace the old factory. In particular, the class has to have the
698
+ same name as the old factory, and has to be put into the same module
699
+ (here: ``__main__``). We turn it into a sub-class of the old class, but
700
+ this is just to save the effort of writing a new init method::
701
+
702
+ sage: from sage.structure.unique_representation import UniqueRepresentation
703
+ sage: class F(UniqueRepresentation, OldStuff):
704
+ ....: def __repr__(self):
705
+ ....: return "Shiny new thing of level {}".format(self.n)
706
+ sage: __main__.F = F
707
+
708
+ The old pickle correctly unpickles as an instance of the new class, which
709
+ is of course different from the instance of the old class, but exhibits
710
+ unique object behaviour as well::
711
+
712
+ sage: b = loads(s); b
713
+ Shiny new thing of level 3
714
+ sage: a is b
715
+ False
716
+ sage: loads(dumps(b)) is b
717
+ True
718
+ """
719
+ cdef UniqueFactory F
720
+ if factory is not None:
721
+ try:
722
+ F = factory
723
+ return F.get_object(*args)
724
+ except TypeError:
725
+ pass
726
+ # See Issue #16349: When replacing a UniqueFactory by something else (e.g.,
727
+ # a UniqueRepresentation), then we get the object by calling.
728
+ #
729
+ # The first argument of a UniqueFactory pickle is a version number. We
730
+ # strip this.
731
+ return factory(*args[1], **args[2])
732
+
733
+
734
+ def generic_factory_reduce(self, proto):
735
+ """
736
+ Used to provide a ``__reduce__`` method if one does not already exist.
737
+
738
+ EXAMPLES::
739
+
740
+ sage: V = QQ^6 # needs sage.modules
741
+ sage: sage.structure.factory.generic_factory_reduce(V, 1) == V.__reduce_ex__(1) # needs sage.modules
742
+ True
743
+ """
744
+ if self._factory_data is None:
745
+ raise NotImplementedError("__reduce__ not implemented for %s" % type(self))
746
+ else:
747
+ return self._factory_data[0].reduce_data(self)
748
+
749
+
750
+ def lookup_global(name):
751
+ """
752
+ Used in unpickling the factory itself.
753
+
754
+ EXAMPLES::
755
+
756
+ sage: from sage.structure.factory import lookup_global
757
+ sage: lookup_global('ZZ')
758
+ Integer Ring
759
+ sage: lookup_global('sage.rings.integer_ring.ZZ')
760
+ Integer Ring
761
+ """
762
+ name = bytes_to_str(name, encoding='ASCII')
763
+ try:
764
+ return factory_unpickles[name]
765
+ except KeyError:
766
+ pass
767
+
768
+ if '.' in name:
769
+ module, name = name.rsplit('.', 1)
770
+ all = __import__(module, fromlist=[name])
771
+ else:
772
+ try:
773
+ import sage.all as all
774
+ except ImportError:
775
+ try:
776
+ import sage.all__sagemath_modules as all
777
+ except ImportError:
778
+ try:
779
+ import sage.all__sagemath_pari as all
780
+ except ImportError:
781
+ import sage.all__sagemath_categories as all
782
+ return getattr(all, name)
783
+
784
+
785
+ # Old imports required for unpickling old pickles
786
+ from sage.structure.test_factory import test_factory