passagemath-objects 10.8.1a3__cp314-cp314-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 (283) hide show
  1. passagemath_objects/__init__.py +3 -0
  2. passagemath_objects-10.8.1a3.dist-info/DELVEWHEEL +2 -0
  3. passagemath_objects-10.8.1a3.dist-info/METADATA +114 -0
  4. passagemath_objects-10.8.1a3.dist-info/RECORD +283 -0
  5. passagemath_objects-10.8.1a3.dist-info/WHEEL +5 -0
  6. passagemath_objects-10.8.1a3.dist-info/top_level.txt +3 -0
  7. passagemath_objects.libs/libgmp-10-60021eeab4282b29024e43b2b1412b53.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.cp314-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.cp314-win_amd64.pyd +0 -0
  15. sage/arith/power.pxd +31 -0
  16. sage/arith/power.pyx +127 -0
  17. sage/categories/action.cp314-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 +292 -0
  24. sage/categories/category.py +3379 -0
  25. sage/categories/category_cy_helper.cp314-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.cp314-win_amd64.pyd +0 -0
  29. sage/categories/category_singleton.pxd +3 -0
  30. sage/categories/category_singleton.pyx +343 -0
  31. sage/categories/category_types.py +637 -0
  32. sage/categories/category_with_axiom.py +2889 -0
  33. sage/categories/covariant_functorial_construction.py +700 -0
  34. sage/categories/facade_sets.py +228 -0
  35. sage/categories/functor.cp314-win_amd64.pyd +0 -0
  36. sage/categories/functor.pxd +7 -0
  37. sage/categories/functor.pyx +659 -0
  38. sage/categories/homset.py +1289 -0
  39. sage/categories/homsets.py +364 -0
  40. sage/categories/isomorphic_objects.py +73 -0
  41. sage/categories/map.cp314-win_amd64.pyd +0 -0
  42. sage/categories/map.pxd +34 -0
  43. sage/categories/map.pyx +2106 -0
  44. sage/categories/morphism.cp314-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 +1695 -0
  49. sage/categories/pushout.py +4847 -0
  50. sage/categories/quotients.py +64 -0
  51. sage/categories/realizations.py +200 -0
  52. sage/categories/sets_cat.py +3305 -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 +22 -0
  58. sage/cpython/_py2_random.py +619 -0
  59. sage/cpython/all.py +3 -0
  60. sage/cpython/atexit.cp314-win_amd64.pyd +0 -0
  61. sage/cpython/atexit.pyx +269 -0
  62. sage/cpython/builtin_types.cp314-win_amd64.pyd +0 -0
  63. sage/cpython/builtin_types.pyx +7 -0
  64. sage/cpython/cython_metaclass.cp314-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.cp314-win_amd64.pyd +0 -0
  69. sage/cpython/debug.pyx +302 -0
  70. sage/cpython/dict_del_by_value.cp314-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 +80 -0
  74. sage/cpython/getattr.cp314-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.cp314-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.cp314-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.cp314-win_amd64.pyd +0 -0
  98. sage/groups/group.pxd +14 -0
  99. sage/groups/group.pyx +296 -0
  100. sage/groups/old.cp314-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.cp314-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.cp314-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.cp314-win_amd64.pyd +0 -0
  126. sage/misc/cachefunc.pxd +43 -0
  127. sage/misc/cachefunc.pyx +3801 -0
  128. sage/misc/call.py +188 -0
  129. sage/misc/classcall_metaclass.cp314-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.cp314-win_amd64.pyd +0 -0
  133. sage/misc/constant_function.pyx +130 -0
  134. sage/misc/decorators.py +739 -0
  135. sage/misc/fast_methods.cp314-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.cp314-win_amd64.pyd +0 -0
  140. sage/misc/fpickle.pyx +176 -0
  141. sage/misc/function_mangling.cp314-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.cp314-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.cp314-win_amd64.pyd +0 -0
  148. sage/misc/instancedoc.pyx +331 -0
  149. sage/misc/lazy_attribute.cp314-win_amd64.pyd +0 -0
  150. sage/misc/lazy_attribute.pyx +607 -0
  151. sage/misc/lazy_format.py +132 -0
  152. sage/misc/lazy_import.cp314-win_amd64.pyd +0 -0
  153. sage/misc/lazy_import.pxd +13 -0
  154. sage/misc/lazy_import.pyx +1307 -0
  155. sage/misc/lazy_import_cache.py +36 -0
  156. sage/misc/lazy_list.cp314-win_amd64.pyd +0 -0
  157. sage/misc/lazy_list.pxd +19 -0
  158. sage/misc/lazy_list.pyx +1187 -0
  159. sage/misc/lazy_string.cp314-win_amd64.pyd +0 -0
  160. sage/misc/lazy_string.pxd +7 -0
  161. sage/misc/lazy_string.pyx +546 -0
  162. sage/misc/misc.py +980 -0
  163. sage/misc/misc_c.cp314-win_amd64.pyd +0 -0
  164. sage/misc/misc_c.pxd +3 -0
  165. sage/misc/misc_c.pyx +765 -0
  166. sage/misc/namespace_package.py +37 -0
  167. sage/misc/nested_class.cp314-win_amd64.pyd +0 -0
  168. sage/misc/nested_class.pxd +3 -0
  169. sage/misc/nested_class.pyx +394 -0
  170. sage/misc/persist.cp314-win_amd64.pyd +0 -0
  171. sage/misc/persist.pyx +1279 -0
  172. sage/misc/prandom.py +418 -0
  173. sage/misc/randstate.cp314-win_amd64.pyd +0 -0
  174. sage/misc/randstate.pxd +31 -0
  175. sage/misc/randstate.pyx +1096 -0
  176. sage/misc/repr.py +203 -0
  177. sage/misc/reset.cp314-win_amd64.pyd +0 -0
  178. sage/misc/reset.pyx +196 -0
  179. sage/misc/sage_ostools.cp314-win_amd64.pyd +0 -0
  180. sage/misc/sage_ostools.pyx +323 -0
  181. sage/misc/sage_timeit.py +275 -0
  182. sage/misc/sage_timeit_class.cp314-win_amd64.pyd +0 -0
  183. sage/misc/sage_timeit_class.pyx +120 -0
  184. sage/misc/sage_unittest.py +639 -0
  185. sage/misc/sageinspect.py +2792 -0
  186. sage/misc/session.cp314-win_amd64.pyd +0 -0
  187. sage/misc/session.pyx +392 -0
  188. sage/misc/superseded.py +576 -0
  189. sage/misc/test_nested_class.py +228 -0
  190. sage/misc/timing.py +264 -0
  191. sage/misc/unknown.py +222 -0
  192. sage/misc/verbose.py +253 -0
  193. sage/misc/weak_dict.cp314-win_amd64.pyd +0 -0
  194. sage/misc/weak_dict.pxd +15 -0
  195. sage/misc/weak_dict.pyx +1197 -0
  196. sage/modules/all__sagemath_objects.py +1 -0
  197. sage/modules/module.cp314-win_amd64.pyd +0 -0
  198. sage/modules/module.pxd +5 -0
  199. sage/modules/module.pyx +329 -0
  200. sage/rings/all__sagemath_objects.py +3 -0
  201. sage/rings/integer_fake.h +22 -0
  202. sage/rings/integer_fake.pxd +55 -0
  203. sage/rings/integer_fake.pyi +8 -0
  204. sage/sets/all__sagemath_objects.py +3 -0
  205. sage/sets/pythonclass.cp314-win_amd64.pyd +0 -0
  206. sage/sets/pythonclass.pxd +9 -0
  207. sage/sets/pythonclass.pyx +247 -0
  208. sage/structure/__init__.py +13 -0
  209. sage/structure/all.py +30 -0
  210. sage/structure/category_object.cp314-win_amd64.pyd +0 -0
  211. sage/structure/category_object.pxd +28 -0
  212. sage/structure/category_object.pyx +1090 -0
  213. sage/structure/coerce.cp314-win_amd64.pyd +0 -0
  214. sage/structure/coerce.pxd +44 -0
  215. sage/structure/coerce.pyx +2113 -0
  216. sage/structure/coerce_actions.cp314-win_amd64.pyd +0 -0
  217. sage/structure/coerce_actions.pxd +27 -0
  218. sage/structure/coerce_actions.pyx +988 -0
  219. sage/structure/coerce_dict.cp314-win_amd64.pyd +0 -0
  220. sage/structure/coerce_dict.pxd +51 -0
  221. sage/structure/coerce_dict.pyx +1557 -0
  222. sage/structure/coerce_exceptions.py +23 -0
  223. sage/structure/coerce_maps.cp314-win_amd64.pyd +0 -0
  224. sage/structure/coerce_maps.pxd +24 -0
  225. sage/structure/coerce_maps.pyx +656 -0
  226. sage/structure/debug_options.cp314-win_amd64.pyd +0 -0
  227. sage/structure/debug_options.pxd +6 -0
  228. sage/structure/debug_options.pyx +54 -0
  229. sage/structure/dynamic_class.py +541 -0
  230. sage/structure/element.cp314-win_amd64.pyd +0 -0
  231. sage/structure/element.pxd +271 -0
  232. sage/structure/element.pyx +4584 -0
  233. sage/structure/element_wrapper.cp314-win_amd64.pyd +0 -0
  234. sage/structure/element_wrapper.pxd +12 -0
  235. sage/structure/element_wrapper.pyx +582 -0
  236. sage/structure/factorization.py +1457 -0
  237. sage/structure/factorization_integer.py +154 -0
  238. sage/structure/factory.cp314-win_amd64.pyd +0 -0
  239. sage/structure/factory.pyx +863 -0
  240. sage/structure/formal_sum.py +489 -0
  241. sage/structure/gens_py.py +73 -0
  242. sage/structure/global_options.py +1725 -0
  243. sage/structure/indexed_generators.py +863 -0
  244. sage/structure/list_clone.cp314-win_amd64.pyd +0 -0
  245. sage/structure/list_clone.pxd +65 -0
  246. sage/structure/list_clone.pyx +1867 -0
  247. sage/structure/list_clone_demo.cp314-win_amd64.pyd +0 -0
  248. sage/structure/list_clone_demo.pyx +248 -0
  249. sage/structure/list_clone_timings.py +179 -0
  250. sage/structure/list_clone_timings_cy.cp314-win_amd64.pyd +0 -0
  251. sage/structure/list_clone_timings_cy.pyx +86 -0
  252. sage/structure/mutability.cp314-win_amd64.pyd +0 -0
  253. sage/structure/mutability.pxd +21 -0
  254. sage/structure/mutability.pyx +346 -0
  255. sage/structure/nonexact.py +69 -0
  256. sage/structure/parent.cp314-win_amd64.pyd +0 -0
  257. sage/structure/parent.pxd +112 -0
  258. sage/structure/parent.pyx +3087 -0
  259. sage/structure/parent_base.cp314-win_amd64.pyd +0 -0
  260. sage/structure/parent_base.pxd +13 -0
  261. sage/structure/parent_base.pyx +35 -0
  262. sage/structure/parent_gens.cp314-win_amd64.pyd +0 -0
  263. sage/structure/parent_gens.pxd +22 -0
  264. sage/structure/parent_gens.pyx +374 -0
  265. sage/structure/parent_old.cp314-win_amd64.pyd +0 -0
  266. sage/structure/parent_old.pxd +24 -0
  267. sage/structure/parent_old.pyx +278 -0
  268. sage/structure/proof/__init__.py +1 -0
  269. sage/structure/proof/all.py +243 -0
  270. sage/structure/proof/proof.py +300 -0
  271. sage/structure/richcmp.cp314-win_amd64.pyd +0 -0
  272. sage/structure/richcmp.pxd +212 -0
  273. sage/structure/richcmp.pyx +494 -0
  274. sage/structure/sage_object.cp314-win_amd64.pyd +0 -0
  275. sage/structure/sage_object.pxd +3 -0
  276. sage/structure/sage_object.pyx +1088 -0
  277. sage/structure/sage_object_test.py +19 -0
  278. sage/structure/sequence.py +937 -0
  279. sage/structure/set_factories.py +1178 -0
  280. sage/structure/set_factories_example.py +527 -0
  281. sage/structure/support_view.py +164 -0
  282. sage/structure/test_factory.py +56 -0
  283. sage/structure/unique_representation.py +1443 -0
@@ -0,0 +1,1443 @@
1
+ # sage_setup: distribution = sagemath-objects
2
+ r"""
3
+ Unique Representation
4
+
5
+ This modules defines abstract classes for cached and unique representation
6
+ behavior.
7
+
8
+ What is a cached representation?
9
+ ================================
10
+
11
+ Instances of a class have a *cached representation behavior* when several
12
+ instances constructed with the same arguments share the same memory
13
+ representation. For example, calling twice::
14
+
15
+ sage: G = SymmetricGroup(6) # needs sage.groups
16
+ sage: H = SymmetricGroup(6) # needs sage.groups
17
+
18
+ to create the symmetric group on six elements gives back the same
19
+ object::
20
+
21
+ sage: G is H # needs sage.groups
22
+ True
23
+
24
+ This is a standard design pattern. Besides saving memory, it allows for
25
+ sharing cached data (say representation theoretical information about a
26
+ group). And of course a look-up in the cache is faster than the creation of a
27
+ new object.
28
+
29
+ Implementing a cached representation
30
+ ------------------------------------
31
+
32
+ Sage provides two standard ways to create a cached representation:
33
+ :class:`CachedRepresentation` and
34
+ :class:`~sage.structure.factory.UniqueFactory`. Note that, in spite of its
35
+ name, :class:`~sage.structure.factory.UniqueFactory` does not ensure *unique*
36
+ representation behaviour, which will be explained below.
37
+
38
+ Using :class:`CachedRepresentation`
39
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
40
+
41
+ It is often very easy to use :class:`CachedRepresentation`: One simply writes
42
+ a Python class and adds :class:`CachedRepresentation` to the list of base
43
+ classes. If one does so, then the arguments used to create an instance of this
44
+ class will by default also be used as keys for the cache::
45
+
46
+ sage: from sage.structure.unique_representation import CachedRepresentation
47
+ sage: class C(CachedRepresentation):
48
+ ....: def __init__(self, a, b=0):
49
+ ....: self.a = a
50
+ ....: self.b = b
51
+ ....: def __repr__(self):
52
+ ....: return "C(%s, %s)"%(self.a, self.b)
53
+ sage: a = C(1)
54
+ sage: a is C(1)
55
+ True
56
+
57
+ In addition, pickling just works, provided that Python is able to look up the
58
+ class. Hence, in the following two lines, we explicitly put the class into the
59
+ ``__main__`` module. This is needed in doctests, but not in an interactive
60
+ session::
61
+
62
+ sage: import __main__
63
+ sage: __main__.C = C
64
+ sage: loads(dumps(a)) is a
65
+ True
66
+
67
+ Often, this very easy approach is sufficient for applications. However, there
68
+ are some pitfalls. Since the arguments are used for caching, all arguments
69
+ must be hashable, i.e., must be valid as dictionary keys::
70
+
71
+ sage: C((1,2))
72
+ C((1, 2), 0)
73
+ sage: C([1,2])
74
+ Traceback (most recent call last):
75
+ ...
76
+ TypeError: ...unhashable type: 'list'...
77
+
78
+ In addition, equivalent ways of providing the arguments are *not*
79
+ automatically normalised when forming the cache key, and hence different but
80
+ equivalent arguments may yield distinct instances::
81
+
82
+ sage: C(1) is C(1,0)
83
+ False
84
+ sage: C(1) is C(a=1)
85
+ False
86
+ sage: repr(C(1)) == repr(C(a=1))
87
+ True
88
+
89
+ It should also be noted that the arguments are compared by equality, not by
90
+ identity. This is often desired, but can imply subtle problems. For example,
91
+ since ``C(1)`` already is in the cache, and since the unit elements in
92
+ different finite fields are all equal to the integer one, we find::
93
+
94
+ sage: GF(5)(1) == 1 == GF(3)(1)
95
+ True
96
+ sage: C(1) is C(GF(3)(1)) is C(GF(5)(1))
97
+ True
98
+
99
+ But ``C(2)`` is not in the cache, and the number two is not equal in different
100
+ finite fields (i. e., ``GF(5)(2) == GF(3)(2)`` returns as ``False``), even
101
+ though it is equal to the number two in the ring of integers (
102
+ ``GF(5)(2) == 2 == GF(3)(2)`` returns as ``True``; equality is not transitive
103
+ when comparing elements of *distinct* algebraic structures!!). Hence, we
104
+ have::
105
+
106
+ sage: GF(5)(2) == GF(3)(2)
107
+ False
108
+ sage: C(GF(3)(2)) is C(GF(5)(2))
109
+ False
110
+
111
+ Normalising the arguments
112
+ .........................
113
+
114
+ :class:`CachedRepresentation` uses the metaclass
115
+ :class:`~sage.misc.classcall_metaclass.ClasscallMetaclass`. Its
116
+ ``__classcall__`` method is a
117
+ :class:`~sage.misc.cachefunc.WeakCachedFunction`. This function creates an
118
+ instance of the given class using the given arguments, unless it finds the
119
+ result in the cache. This has the following implications:
120
+
121
+ - The arguments must be valid dictionary keys (i.e., they must be hashable;
122
+ see above).
123
+ - It is a weak cache, hence, if the user does not keep a reference to the
124
+ resulting instance, then it may be removed from the cache during garbage
125
+ collection.
126
+ - It is possible to preprocess the input arguments by implementing a
127
+ ``__classcall__`` or a ``__classcall_private__`` method, but in order to
128
+ benefit from caching, :meth:`CachedRepresentation.__classcall__` should at
129
+ some point be called.
130
+
131
+ .. NOTE::
132
+
133
+ For technical reasons, it is needed that ``__classcall__`` respectively
134
+ ``__classcall_private__`` are "static methods", i.e., they are callable
135
+ objects that do not bind to an instance or class. For example, a
136
+ :class:`~sage.misc.cachefunc.cached_function` can be used here, because it
137
+ is callable, but does not bind to an instance or class, because it has no
138
+ ``__get__()`` method. A usual Python function, however, has a
139
+ ``__get__()`` method and would thus under normal circumstances bind to an
140
+ instance or class, and thus the instance or class would be passed to the
141
+ function as the first argument. To prevent a callable object from being
142
+ bound to the instance or class, one can prepend the ``@staticmethod``
143
+ decorator to the definition; see :class:`staticmethod`.
144
+
145
+ For more on Python's ``__get__()`` method, see:
146
+ https://docs.python.org/2/howto/descriptor.html
147
+
148
+ .. WARNING::
149
+
150
+ If there is preprocessing, then the preprocessed arguments
151
+ passed to :meth:`CachedRepresentation.__classcall__` must be invariant
152
+ under the preprocessing. That is to say, preprocessing the input
153
+ arguments twice must have the same effect as preprocessing the input
154
+ arguments only once. That is to say, the preprocessing must be idempotent.
155
+
156
+ The reason for this warning lies in the way pickling is implemented. If the
157
+ preprocessed arguments are passed to
158
+ :meth:`CachedRepresentation.__classcall__`, then the resulting instance will
159
+ store the *preprocessed* arguments in some attribute, and will use them for
160
+ pickling. If the pickle is unpickled, then preprocessing is applied to the
161
+ preprocessed arguments---and this second round of preprocessing must not
162
+ change the arguments further, since otherwise a different instance would be
163
+ created.
164
+
165
+ We illustrate the warning by an example. Imagine that one has instances that
166
+ are created with an integer-valued argument, but only depend on the *square*
167
+ of the argument. It would be a mistake to square the given argument during
168
+ preprocessing::
169
+
170
+ sage: class WrongUsage(CachedRepresentation):
171
+ ....: @staticmethod
172
+ ....: def __classcall__(cls, n):
173
+ ....: return super().__classcall__(cls, n^2)
174
+ ....: def __init__(self, n):
175
+ ....: self.n = n
176
+ ....: def __repr__(self):
177
+ ....: return "Something(%d)"%self.n
178
+ sage: import __main__
179
+ sage: __main__.WrongUsage = WrongUsage # This is only needed in doctests
180
+ sage: w = WrongUsage(3); w
181
+ Something(9)
182
+ sage: w._reduction
183
+ (<class '__main__.WrongUsage'>, (9,), {})
184
+
185
+ Indeed, the reduction data are obtained from the preprocessed argument. By
186
+ consequence, if the resulting instance is pickled and unpickled, the argument
187
+ gets squared *again*::
188
+
189
+ sage: loads(dumps(w))
190
+ Something(81)
191
+
192
+ Instead, the preprocessing should only take the absolute value of the given
193
+ argument, while the squaring should happen inside of the ``__init__`` method,
194
+ where it won't mess with the cache::
195
+
196
+ sage: class BetterUsage(CachedRepresentation):
197
+ ....: @staticmethod
198
+ ....: def __classcall__(cls, n):
199
+ ....: return super().__classcall__(cls, abs(n))
200
+ ....: def __init__(self, n):
201
+ ....: self.n = n^2
202
+ ....: def __repr__(self):
203
+ ....: return "SomethingElse(%d)"%self.n
204
+ sage: __main__.BetterUsage = BetterUsage # This is only needed in doctests
205
+ sage: b = BetterUsage(3); b
206
+ SomethingElse(9)
207
+ sage: loads(dumps(b)) is b
208
+ True
209
+ sage: b is BetterUsage(-3)
210
+ True
211
+
212
+ In our next example, we create a cached representation class ``C`` that
213
+ returns an instance of a sub-class ``C1`` or ``C2`` depending on the given
214
+ arguments. This is implemented in a static ``__classcall_private__`` method of
215
+ ``C``, letting it choose the sub-class according to the given arguments. Since
216
+ a ``__classcall_private__`` method will be ignored on sub-classes, the caching
217
+ of :class:`CachedRepresentation` is available to both ``C1`` and ``C2``. But
218
+ for illustration, we overload the static ``__classcall__`` method on ``C2``,
219
+ doing some argument preprocessing. We also create a sub-class ``C2b`` of
220
+ ``C2``, demonstrating that the ``__classcall__`` method is used on the
221
+ sub-class (in contrast to a ``__classcall_private__`` method!). ::
222
+
223
+ sage: class C(CachedRepresentation):
224
+ ....: @staticmethod
225
+ ....: def __classcall_private__(cls, n, implementation=0):
226
+ ....: if not implementation:
227
+ ....: return C.__classcall__(cls, n)
228
+ ....: if implementation==1:
229
+ ....: return C1(n)
230
+ ....: if implementation>1:
231
+ ....: return C2(n,implementation)
232
+ ....: def __init__(self, n):
233
+ ....: self.n = n
234
+ ....: def __repr__(self):
235
+ ....: return "C(%d, 0)"%self.n
236
+ sage: class C1(C):
237
+ ....: def __repr__(self):
238
+ ....: return "C1(%d)"%self.n
239
+ sage: class C2(C):
240
+ ....: @staticmethod
241
+ ....: def __classcall__(cls, n, implementation=0):
242
+ ....: if implementation:
243
+ ....: return super().__classcall__(cls, (n,)*implementation)
244
+ ....: return super().__classcall__(cls, n)
245
+ ....: def __init__(self, t):
246
+ ....: self.t = t
247
+ ....: def __repr__(self):
248
+ ....: return "C2(%s)"%repr(self.t)
249
+ sage: class C2b(C2):
250
+ ....: def __repr__(self):
251
+ ....: return "C2b(%s)"%repr(self.t)
252
+ sage: __main__.C2 = C2 # not needed in an interactive session
253
+ sage: __main__.C2b = C2b
254
+
255
+ In the above example, ``C`` drops the argument ``implementation`` if it
256
+ evaluates to ``False``, and since the cached ``__classcall__`` is called in
257
+ this case, we have::
258
+
259
+ sage: C(1)
260
+ C(1, 0)
261
+ sage: C(1) is C(1,0)
262
+ True
263
+ sage: C(1) is C(1,0) is C(1,None) is C(1,[])
264
+ True
265
+
266
+ (Note that we were able to bypass the issue of arguments having to be
267
+ hashable by catching the empty list ``[]`` during preprocessing in the
268
+ ``__classcall_private__`` method. Similarly, unhashable arguments can
269
+ be made hashable -- e. g., lists normalized to tuples -- in the
270
+ ``__classcall_private__`` method before they are further delegated to
271
+ ``__classcall__``. See
272
+ :class:`~sage.combinat.crystals.elementary_crystals.TCrystal` for an
273
+ example.)
274
+
275
+ If we call ``C1`` directly or if we provide ``implementation=1`` to ``C``, we
276
+ obtain an instance of ``C1``. Since it uses the ``__classcall__`` method
277
+ inherited from :class:`CachedRepresentation`, the resulting instances are
278
+ cached::
279
+
280
+ sage: C1(2)
281
+ C1(2)
282
+ sage: C(2, implementation=1)
283
+ C1(2)
284
+ sage: C(2, implementation=1) is C1(2)
285
+ True
286
+
287
+ The class ``C2`` preprocesses the input arguments. Instances can, again, be
288
+ obtained directly or by calling ``C``::
289
+
290
+ sage: C(1, implementation=3)
291
+ C2((1, 1, 1))
292
+ sage: C(1, implementation=3) is C2(1,3)
293
+ True
294
+
295
+ The argument preprocessing of ``C2`` is inherited by ``C2b``, since
296
+ ``__classcall__`` and not ``__classcall_private__`` is used. Pickling works,
297
+ since the preprocessing of arguments is idempotent::
298
+
299
+ sage: c2b = C2b(2,3); c2b
300
+ C2b((2, 2, 2))
301
+ sage: loads(dumps(c2b)) is c2b
302
+ True
303
+
304
+ Using :class:`~sage.structure.factory.UniqueFactory`
305
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
306
+
307
+ For creating a cached representation using a factory, one has to
308
+
309
+ - create a class *separately* from the factory. This class **must** inherit
310
+ from :class:`object`. Its instances **must** allow attribute assignment.
311
+ - write a method ``create_key`` (or ``create_key_and_extra_args``) that
312
+ creates the cache key from the given arguments.
313
+ - write a method ``create_object`` that creates an instance of the class
314
+ from a given cache key.
315
+ - create an instance of the factory with a name that allows to conclude where
316
+ it is defined.
317
+
318
+ An example::
319
+
320
+ sage: class C():
321
+ ....: def __init__(self, t):
322
+ ....: self.t = t
323
+ ....: def __repr__(self):
324
+ ....: return "C%s"%repr(self.t)
325
+ sage: from sage.structure.factory import UniqueFactory
326
+ sage: class MyFactory(UniqueFactory):
327
+ ....: def create_key(self, n, m=None):
328
+ ....: if isinstance(n, (tuple,list)) and m is None:
329
+ ....: return tuple(n)
330
+ ....: return (n,)*m
331
+ ....: def create_object(self, version, key, **extra_args):
332
+ ....: # We ignore version and extra_args
333
+ ....: return C(key)
334
+
335
+ Now, we define an instance of the factory, stating that it can be found under
336
+ the name ``'F'`` in the ``__main__`` module. By consequence, pickling works::
337
+
338
+ sage: F = MyFactory("__main__.F")
339
+ sage: __main__.F = F # not needed in an interactive session
340
+ sage: loads(dumps(F)) is F
341
+ True
342
+
343
+ We can now create *cached* instances of ``C`` by calling the factory. The
344
+ cache only takes into account the key computed with the method ``create_key``
345
+ that we provided. Hence, different given arguments may result in the same
346
+ instance. Note that, again, the cache is weak, hence, the instance might be
347
+ removed from the cache during garbage collection, unless an external reference
348
+ is preserved.
349
+ ::
350
+
351
+ sage: a = F(1, 2); a
352
+ C(1, 1)
353
+ sage: a is F((1,1))
354
+ True
355
+
356
+ **If** the class of the returned instances is a sub-class of :class:`object`,
357
+ and **if** the resulting instance allows attribute assignment, then pickling
358
+ of the resulting instances is automatically provided for, and respects the
359
+ cache. ::
360
+
361
+ sage: loads(dumps(a)) is a
362
+ True
363
+
364
+ This is because an attribute is stored that explains how the instance was
365
+ created::
366
+
367
+ sage: a._factory_data
368
+ (<__main__.MyFactory object at ...>, (...), (1, 1), {})
369
+
370
+ .. NOTE::
371
+
372
+ If a class is used that does not inherit from :class:`object` then unique
373
+ pickling is *not* provided.
374
+
375
+ Caching is only available if the factory is called. If an instance of the
376
+ class is directly created, then the cache is not used::
377
+
378
+ sage: C((1,1))
379
+ C(1, 1)
380
+ sage: C((1,1)) is a
381
+ False
382
+
383
+ Comparing the two ways of implementing a cached representation
384
+ --------------------------------------------------------------
385
+
386
+ In this sub-section, we discuss advantages and disadvantages of the two ways
387
+ of implementing a cached representation, depending on the type of application.
388
+
389
+ Simplicity and transparency
390
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
391
+
392
+ In many cases, turning a class into a cached representation requires nothing
393
+ more than adding :class:`CachedRepresentation` to the list of base classes of
394
+ this class. This is, of course, a very easy and convenient way. Writing a
395
+ factory would involve a lot more work.
396
+
397
+ If preprocessing of the arguments is needed, then we have seen how to do this
398
+ by a ``__classcall_private__`` or ``__classcall__`` method. But these are
399
+ double underscore methods and hence, for example, invisible in the
400
+ automatically created reference manual. Moreover, preprocessing *and* caching
401
+ are implemented in the same method, which might be confusing. In a unique
402
+ factory, these two tasks are cleanly implemented in two separate methods.
403
+ With a factory, it is possible to create the resulting instance by arguments
404
+ that are different from the key used for caching. This is significantly
405
+ restricted with CachedRepresentation due to the requirement that argument
406
+ preprocessing be idempotent.
407
+
408
+ Hence, if advanced preprocessing is needed, then
409
+ :class:`~sage.structure.factory.UniqueFactory` might be easier and more
410
+ transparent to use than :class:`CachedRepresentation`.
411
+
412
+ Class inheritance
413
+ ^^^^^^^^^^^^^^^^^
414
+
415
+ Using :class:`CachedRepresentation` has the advantage that one has a class and
416
+ creates cached instances of this class by the usual Python syntax::
417
+
418
+ sage: G = SymmetricGroup(6) # needs sage.groups
419
+ sage: issubclass(SymmetricGroup, sage.structure.unique_representation.CachedRepresentation) # needs sage.groups
420
+ True
421
+ sage: isinstance(G, SymmetricGroup) # needs sage.groups
422
+ True
423
+
424
+ In contrast, a factory is just a callable object that returns something that
425
+ has absolutely nothing to do with the factory, and may in fact return
426
+ instances of quite different classes::
427
+
428
+ sage: isinstance(GF, sage.structure.factory.UniqueFactory)
429
+ True
430
+ sage: K5 = GF(5)
431
+ sage: type(K5)
432
+ <class 'sage.rings.finite_rings.finite_field_prime_modn.FiniteField_prime_modn_with_category'>
433
+
434
+ sage: # needs sage.rings.finite_rings
435
+ sage: K25 = GF(25, 'x')
436
+ sage: type(K25) # needs sage.libs.linbox
437
+ <class 'sage.rings.finite_rings.finite_field_givaro.FiniteField_givaro_with_category'>
438
+ sage: Kp = GF(next_prime_power(1000000)^2, 'x')
439
+ sage: type(Kp)
440
+ <class 'sage.rings.finite_rings.finite_field_pari_ffelt.FiniteField_pari_ffelt_with_category'>
441
+
442
+ This can be confusing to the user. Namely, the user might determine the class
443
+ of an instance and try to create further instances by calling the class rather
444
+ than the factory---which is a mistake since it works around the cache (and
445
+ also since the class might be more restrictive than the factory -- i. e., the
446
+ type of ``K5`` in the above doctest cannot be called on a prime power which
447
+ is not a prime). This mistake can more easily be avoided by using
448
+ :class:`CachedRepresentation`.
449
+
450
+ We have seen above that one can easily create new cached-representation
451
+ classes by subclassing an existing cached-representation class, even making
452
+ use of an existing argument preprocess. This would be much more complicated
453
+ with a factory. Namely, one would need to rewrite old factories making them
454
+ aware of the new classes, and/or write new factories for the new classes.
455
+
456
+ Python versus extension classes
457
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
458
+
459
+ :class:`CachedRepresentation` uses a metaclass, namely
460
+ :class:`~sage.misc.classcall_metaclass.ClasscallMetaclass`. Hence, it can
461
+ currently not be a Cython extension class. Moreover, it is supposed to be used
462
+ by providing it as a base class. But in typical applications, one also has
463
+ another base class, say, :class:`~sage.structure.parent.Parent`. Hence, one
464
+ would like to create a class with at least two base classes, which is
465
+ currently impossible in Cython extension classes.
466
+
467
+ In other words, when using :class:`CachedRepresentation`, one must work with
468
+ Python classes. These can be defined in Cython code (``.pyx`` files) and can
469
+ thus benefit from Cython's speed inside of their methods, but they must not be
470
+ ``cdef class`` and can thus not use ``cdef`` attributes or methods.
471
+
472
+ Such restrictions do not exist when using a factory. However, if attribute
473
+ assignment does not work, then the automatic pickling provided by
474
+ :class:`~sage.structure.factory.UniqueFactory` will not be available.
475
+
476
+ What is a unique representation?
477
+ ================================
478
+
479
+ Instances of a class have a *unique instance behavior* when instances of this
480
+ class evaluate equal if and only if they are identical. Sage provides the base
481
+ class :class:`~sage.misc.fast_methods.WithEqualityById`, which provides
482
+ comparison by identity and a hash that is determined by the memory address of
483
+ the instance. Both the equality test and the hash are implemented in Cython
484
+ and are very fast, even when one has a Python class inheriting from
485
+ :class:`~sage.misc.fast_methods.WithEqualityById`.
486
+
487
+ In many applications, one wants to combine unique instance and cached
488
+ representation behaviour. This is called *unique representation* behaviour.
489
+ We have seen above that symmetric groups have a *cached* representation
490
+ behaviour. However, they do not show the *unique* representation behaviour,
491
+ since they are equal to groups created in a totally different way, namely to
492
+ subgroups::
493
+
494
+ sage: # needs sage.groups
495
+ sage: G = SymmetricGroup(6)
496
+ sage: G3 = G.subgroup([G((1,2,3,4,5,6)), G((1,2))])
497
+ sage: G is G3
498
+ False
499
+ sage: type(G) == type(G3)
500
+ False
501
+ sage: G == G3
502
+ True
503
+
504
+ The unique representation behaviour can conveniently be implemented with a
505
+ class that inherits from :class:`UniqueRepresentation`: By adding
506
+ :class:`UniqueRepresentation` to the base classes, the class will
507
+ simultaneously inherit from :class:`CachedRepresentation` and from
508
+ :class:`~sage.misc.fast_methods.WithEqualityById`.
509
+
510
+ For example, a symmetric function algebra is uniquely determined by the base
511
+ ring. Thus, it is reasonable to use :class:`UniqueRepresentation` in this
512
+ case::
513
+
514
+ sage: isinstance(SymmetricFunctions(CC), SymmetricFunctions) # needs sage.combinat sage.modules sage.rings.real_mpfr
515
+ True
516
+ sage: issubclass(SymmetricFunctions, UniqueRepresentation) # needs sage.combinat sage.modules
517
+ True
518
+
519
+ :class:`UniqueRepresentation` differs from :class:`CachedRepresentation` only
520
+ by adding :class:`~sage.misc.fast_methods.WithEqualityById` as a base
521
+ class. Hence, the above examples of argument preprocessing work for
522
+ :class:`UniqueRepresentation` as well.
523
+
524
+ Note that a cached representation created with
525
+ :class:`~sage.structure.factory.UniqueFactory` does *not* automatically
526
+ provide unique representation behaviour, in spite of its name! Hence, for
527
+ unique representation behaviour, one has to implement hash and equality test
528
+ accordingly, for example by inheriting from
529
+ :class:`~sage.misc.fast_methods.WithEqualityById`.
530
+
531
+ .. SEEALSO::
532
+
533
+ :class:`sage.structure.factory.UniqueFactory`
534
+
535
+ AUTHORS:
536
+
537
+ - Nicolas M. Thiery (2008): initial version
538
+ - Simon A. King (2013-02): separated cached and unique representation
539
+ - Simon A. King (2013-08): extended documentation
540
+ - Kwankyu Lee (2025-10): added ``__getstate__`` and ``__setstate__`` to support
541
+ ``do_pickle=True`` for cached methods.
542
+ """
543
+ # ****************************************************************************
544
+ # Copyright (C) 2008 Nicolas M. Thiery <nthiery at users.sf.net>
545
+ # Copyright (C) 2013 Simon A. King <simon.king at uni-jena.de>
546
+ #
547
+ # Distributed under the terms of the GNU General Public License (GPL)
548
+ #
549
+ # This code is distributed in the hope that it will be useful,
550
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
551
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
552
+ # General Public License for more details.
553
+ #
554
+ # The full text of the GPL is available at:
555
+ #
556
+ # https://www.gnu.org/licenses/
557
+ # *****************************************************************************
558
+
559
+ from sage.misc.cachefunc import weak_cached_function
560
+ from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall
561
+ from sage.misc.fast_methods import WithEqualityById
562
+
563
+
564
+ class WithPicklingByInitArgs(metaclass=ClasscallMetaclass):
565
+ r"""
566
+ Classes derived from :class:`WithPicklingByInitArgs` store the arguments
567
+ passed to :meth:`__init__` to implement pickling.
568
+
569
+ This class is for objects that are semantically immutable and determined
570
+ by the class and the arguments passed to :meth:`__init__`.
571
+ The class also provides implementations of :meth:`__copy__` and
572
+ :func:`__deepcopy__`, which simply return the object.
573
+ """
574
+
575
+ @staticmethod
576
+ def __classcall__(cls, *args, **options):
577
+ """
578
+ Construct a new object of this class and store the arguments passed to ``__init__``.
579
+
580
+ TESTS::
581
+
582
+ sage: from sage.structure.unique_representation import WithPicklingByInitArgs
583
+ sage: class MyClass(WithPicklingByInitArgs):
584
+ ....: def __init__(self, value):
585
+ ....: self.value = value
586
+ ....: def __eq__(self, other):
587
+ ....: if type(self) != type(other):
588
+ ....: return False
589
+ ....: return self.value == other.value
590
+ sage: import __main__
591
+ sage: __main__.MyClass = MyClass # This is only needed in doctests
592
+ sage: x = MyClass(1)
593
+ sage: x == loads(dumps(x))
594
+ True
595
+ sage: y = MyClass(1)
596
+ sage: x is y # No Cached/UniqueRepresentation behavior
597
+ False
598
+ """
599
+ instance = typecall(cls, *args, **options)
600
+ assert isinstance(instance, cls)
601
+ if instance.__class__.__reduce__ == WithPicklingByInitArgs.__reduce__:
602
+ instance._reduction = (cls, args, options)
603
+ instance.__class__.__getstate__ = WithPicklingByInitArgs.__getstate__
604
+ instance.__class__.__setstate__ = WithPicklingByInitArgs.__setstate__
605
+ return instance
606
+
607
+ def __reduce__(self):
608
+ """
609
+ Return the arguments that have been passed to
610
+ :meth:`__new__<object.__new__>` to construct this object,
611
+ as per the pickle protocol.
612
+
613
+ See also :class:`CachedRepresentation` and
614
+ :class:`UniqueRepresentation` for a discussion.
615
+
616
+ EXAMPLES::
617
+
618
+ sage: x = UniqueRepresentation()
619
+ sage: x.__reduce__() # indirect doctest
620
+ (<function unreduce at ...>,
621
+ (<class 'sage.structure.unique_representation.UniqueRepresentation'>, (), {}))
622
+ """
623
+ d = self.__getstate__()
624
+ if d:
625
+ return (unreduce, self._reduction, d)
626
+ return (unreduce, self._reduction)
627
+
628
+ def __copy__(self):
629
+ """
630
+ Return ``self``, as a semantic copy of ``self``.
631
+
632
+ This assumes that the object is semantically immutable.
633
+
634
+ EXAMPLES::
635
+
636
+ sage: x = UniqueRepresentation()
637
+ sage: x is copy(x) # indirect doctest
638
+ True
639
+ """
640
+ return self
641
+
642
+ def __deepcopy__(self, memo):
643
+ """
644
+ Return ``self``, as a semantic deep copy of ``self``.
645
+
646
+ This assumes that the object is semantically immutable.
647
+
648
+ EXAMPLES::
649
+
650
+ sage: from copy import deepcopy
651
+ sage: x = UniqueRepresentation()
652
+ sage: x is deepcopy(x) # indirect doctest
653
+ True
654
+ """
655
+ return self
656
+
657
+ def __getstate__(self):
658
+ """
659
+ Used for pickling.
660
+
661
+ An object of :class:`WithPicklingByInitArgs` does not keep its
662
+ dictionary when pickled, because the object is restored from the cache
663
+ or reconstructed afresh upon unpickling.
664
+
665
+ Cached-methods with ``do_pickle=True`` are exceptions and included to
666
+ the state of the pickled object.
667
+
668
+ EXAMPLES::
669
+
670
+ sage: from sage.structure.unique_representation import WithPicklingByInitArgs
671
+ sage: class X(WithPicklingByInitArgs):
672
+ ....: def __init__(self, x):
673
+ ....: self._x = x
674
+ ....: @cached_method(do_pickle=True)
675
+ ....: def genus(self):
676
+ ....: return len(self._x)
677
+ ....:
678
+ sage: import __main__; __main__.X = X # not needed in an interactive session
679
+ sage: a = X((1,2,3))
680
+ sage: a.genus()
681
+ 3
682
+ sage: a.genus.cache
683
+ 3
684
+ sage: s = dumps(a)
685
+ sage: a.genus.clear_cache()
686
+ sage: a.genus.cache
687
+ sage: b = loads(s)
688
+ sage: b.genus.cache
689
+ 3
690
+ """
691
+ # We filter out cached-method placeholders (CachedFunction) with
692
+ # do_pickle=True in __dict__ to keep them as the state of the pickled object.
693
+ #
694
+ # Note that the same code is used to get the state of UniqueFactory objects.
695
+ from sage.misc.cachefunc import CachedFunction
696
+ d = {}
697
+ try:
698
+ for key, value in self.__dict__.items():
699
+ if isinstance(value, CachedFunction) and value.is_pickled_with_cache():
700
+ d[key] = value
701
+ except AttributeError:
702
+ pass
703
+ return d
704
+
705
+ def __setstate__(self, d):
706
+ """
707
+ Used for unpickling.
708
+
709
+ EXAMPLES::
710
+
711
+ sage: from sage.structure.unique_representation import WithPicklingByInitArgs
712
+ sage: class X(WithPicklingByInitArgs):
713
+ ....: def __init__(self, x):
714
+ ....: self._x = x
715
+ ....: @cached_method(do_pickle=False)
716
+ ....: def genus(self):
717
+ ....: return len(self._x)
718
+ ....:
719
+ sage: import __main__; __main__.X = X # not needed in an interactive session
720
+ sage: a = X((1,2,3))
721
+ sage: a.genus()
722
+ 3
723
+ sage: a.genus.cache
724
+ 3
725
+ sage: s = dumps(a)
726
+ sage: a.genus.clear_cache()
727
+ sage: a.genus.cache
728
+ sage: b = loads(s)
729
+ sage: b.genus.cache
730
+ """
731
+ self.__dict__.update(d)
732
+
733
+
734
+ def unreduce(cls, args, keywords):
735
+ """
736
+ Calls a class on the given arguments::
737
+
738
+ sage: sage.structure.unique_representation.unreduce(Integer, (1,), {})
739
+ 1
740
+
741
+ .. TODO::
742
+
743
+ should reuse something preexisting ...
744
+
745
+ """
746
+ return cls(*args, **keywords)
747
+
748
+
749
+ class CachedRepresentation(WithPicklingByInitArgs):
750
+ """
751
+ Classes derived from CachedRepresentation inherit a weak cache for their
752
+ instances.
753
+
754
+ .. NOTE::
755
+
756
+ If this class is used as a base class, then instances are (weakly)
757
+ cached, according to the arguments used to create the instance.
758
+ Pickling is provided, of course by using the cache.
759
+
760
+ .. NOTE::
761
+
762
+ Using this class, one can have arbitrary hash and comparison.
763
+ Hence, *unique* representation behaviour is *not* provided.
764
+
765
+ .. SEEALSO::
766
+
767
+ :class:`UniqueRepresentation`, :mod:`~sage.structure.unique_representation`
768
+
769
+ EXAMPLES:
770
+
771
+ Providing a class with a weak cache for the instances is easy: Just
772
+ inherit from :class:`CachedRepresentation`::
773
+
774
+ sage: from sage.structure.unique_representation import CachedRepresentation
775
+ sage: class MyClass(CachedRepresentation):
776
+ ....: # all the rest as usual
777
+ ....: pass
778
+
779
+ We start with a simple class whose constructor takes a single
780
+ value as argument (TODO: find a more meaningful example)::
781
+
782
+ sage: class MyClass(CachedRepresentation):
783
+ ....: def __init__(self, value):
784
+ ....: self.value = value
785
+ ....: def __eq__(self, other):
786
+ ....: if type(self) != type(other):
787
+ ....: return False
788
+ ....: return self.value == other.value
789
+
790
+ Two coexisting instances of ``MyClass`` created with the same argument data
791
+ are guaranteed to share the same identity. Since :issue:`12215`, this is
792
+ only the case if there is some strong reference to the returned instance,
793
+ since otherwise it may be garbage collected::
794
+
795
+ sage: x = MyClass(1)
796
+ sage: y = MyClass(1)
797
+ sage: x is y # There is a strong reference
798
+ True
799
+ sage: z = MyClass(2)
800
+ sage: x is z
801
+ False
802
+
803
+ In particular, modifying any one of them modifies the other
804
+ (reference effect)::
805
+
806
+ sage: x.value = 3
807
+ sage: x.value, y.value
808
+ (3, 3)
809
+ sage: y.value = 1
810
+ sage: x.value, y.value
811
+ (1, 1)
812
+
813
+ The arguments can consist of any combination of positional or keyword
814
+ arguments, as taken by a usual :meth:`__init__ <object.__init__>`
815
+ function. However, all values passed in should be hashable::
816
+
817
+ sage: MyClass(value = [1,2,3])
818
+ Traceback (most recent call last):
819
+ ...
820
+ TypeError: ...unhashable type: 'list'...
821
+
822
+ .. rubric:: Argument preprocessing
823
+
824
+ Sometimes, one wants to do some preprocessing on the arguments, to
825
+ put them in some canonical form. The following example illustrates
826
+ how to achieve this; it takes as argument any iterable, and
827
+ canonicalizes it into a tuple (which is hashable!)::
828
+
829
+ sage: class MyClass2(CachedRepresentation):
830
+ ....: @staticmethod
831
+ ....: def __classcall__(cls, iterable):
832
+ ....: t = tuple(iterable)
833
+ ....: return super().__classcall__(cls, t)
834
+ ....:
835
+ ....: def __init__(self, value):
836
+ ....: self.value = value
837
+ sage: x = MyClass2([1,2,3])
838
+ sage: y = MyClass2(tuple([1,2,3]))
839
+ sage: z = MyClass2(i for i in [1,2,3])
840
+ sage: x.value
841
+ (1, 2, 3)
842
+ sage: x is y, y is z
843
+ (True, True)
844
+
845
+ A similar situation arises when the constructor accepts default
846
+ values for some of its parameters. Alas, the obvious
847
+ implementation does not work::
848
+
849
+ sage: class MyClass3(CachedRepresentation):
850
+ ....: def __init__(self, value=3):
851
+ ....: self.value = value
852
+ sage: MyClass3(3) is MyClass3()
853
+ False
854
+
855
+ Instead, one should do::
856
+
857
+ sage: class MyClass3(UniqueRepresentation):
858
+ ....: @staticmethod
859
+ ....: def __classcall__(cls, value=3):
860
+ ....: return super().__classcall__(cls, value)
861
+ ....:
862
+ ....: def __init__(self, value):
863
+ ....: self.value = value
864
+ sage: MyClass3(3) is MyClass3()
865
+ True
866
+
867
+ A bit of explanation is in order. First, the call ``MyClass2([1,2,3])``
868
+ triggers a call to ``MyClass2.__classcall__(MyClass2, [1,2,3])``. This is
869
+ an extension of the standard Python behavior, needed by
870
+ :class:`CachedRepresentation`, and implemented by the
871
+ :class:`~sage.misc.classcall_metaclass.ClasscallMetaclass`. Then,
872
+ ``MyClass2.__classcall__`` does the desired transformations on the
873
+ arguments. Finally, it uses ``super`` to call the default implementation
874
+ of ``__classcall__`` provided by :class:`CachedRepresentation`. This one
875
+ in turn handles the caching and, if needed, constructs and initializes a
876
+ new object in the class using :meth:`__new__<object.__new__>` and
877
+ :meth:`__init__<object.__init__>` as usual.
878
+
879
+ Constraints:
880
+
881
+ - :meth:`__classcall__` is a staticmethod (like, implicitly,
882
+ :meth:`__new__<object.__new__>`)
883
+ - the preprocessing on the arguments should be idempotent. That is, if
884
+ ``MyClass2.__classcall__(<arguments>)`` calls
885
+ ``CachedRepresentation.__classcall__(<preprocessed_arguments>)``, then
886
+ ``MyClass2.__classcall__(<preprocessed_arguments>)`` should also result
887
+ in a call to ``CachedRepresentation.__classcall__(<preprocessed_arguments>)``.
888
+ - ``MyClass2.__classcall__`` should return the result of
889
+ :meth:`CachedRepresentation.__classcall__` without modifying it.
890
+
891
+ Other than that ``MyClass2.__classcall__`` may play any tricks, like
892
+ acting as a factory and returning objects from other classes.
893
+
894
+ .. WARNING::
895
+
896
+ It is possible, but strongly discouraged, to let the ``__classcall__``
897
+ method of a class ``C`` return objects that are not instances of
898
+ ``C``. Of course, instances of a *subclass* of ``C`` are fine. Compare
899
+ the examples in :mod:`~sage.structure.unique_representation`.
900
+
901
+ We illustrate what is meant by an "idempotent" preprocessing. Imagine
902
+ that one has instances that are created with an integer-valued argument,
903
+ but only depend on the *square* of the argument. It would be a mistake to
904
+ square the given argument during preprocessing::
905
+
906
+ sage: class WrongUsage(CachedRepresentation):
907
+ ....: @staticmethod
908
+ ....: def __classcall__(cls, n):
909
+ ....: return super().__classcall__(cls, n^2)
910
+ ....: def __init__(self, n):
911
+ ....: self.n = n
912
+ ....: def __repr__(self):
913
+ ....: return "Something(%d)"%self.n
914
+ sage: import __main__
915
+ sage: __main__.WrongUsage = WrongUsage # This is only needed in doctests
916
+ sage: w = WrongUsage(3); w
917
+ Something(9)
918
+ sage: w._reduction
919
+ (<class '__main__.WrongUsage'>, (9,), {})
920
+
921
+ Indeed, the reduction data are obtained from the preprocessed
922
+ arguments. By consequence, if the resulting instance is pickled and
923
+ unpickled, the argument gets squared *again*::
924
+
925
+ sage: loads(dumps(w))
926
+ Something(81)
927
+
928
+ Instead, the preprocessing should only take the absolute value of the
929
+ given argument, while the squaring should happen inside of the
930
+ ``__init__`` method, where it won't mess with the cache::
931
+
932
+ sage: class BetterUsage(CachedRepresentation):
933
+ ....: @staticmethod
934
+ ....: def __classcall__(cls, n):
935
+ ....: return super().__classcall__(cls, abs(n))
936
+ ....: def __init__(self, n):
937
+ ....: self.n = n^2
938
+ ....: def __repr__(self):
939
+ ....: return "SomethingElse(%d)"%self.n
940
+ sage: __main__.BetterUsage = BetterUsage # This is only needed in doctests
941
+ sage: b = BetterUsage(3); b
942
+ SomethingElse(9)
943
+ sage: loads(dumps(b)) is b
944
+ True
945
+ sage: b is BetterUsage(-3)
946
+ True
947
+
948
+ .. rubric:: Cached representation and mutability
949
+
950
+ :class:`CachedRepresentation` is primarily intended for implementing
951
+ objects which are (at least semantically) immutable. This is in
952
+ particular assumed by the default implementations of ``copy`` and
953
+ ``deepcopy``::
954
+
955
+ sage: copy(x) is x
956
+ True
957
+ sage: from copy import deepcopy
958
+ sage: deepcopy(x) is x
959
+ True
960
+
961
+ However, in contrast to :class:`UniqueRepresentation`, using
962
+ :class:`CachedRepresentation` allows for a comparison that is not by
963
+ identity::
964
+
965
+ sage: t = MyClass(3)
966
+ sage: z = MyClass(2)
967
+ sage: t.value = 2
968
+
969
+ Now ``t`` and ``z`` are non-identical, but equal::
970
+
971
+ sage: t.value == z.value
972
+ True
973
+ sage: t == z
974
+ True
975
+ sage: t is z
976
+ False
977
+
978
+ .. rubric:: More on cached representation and identity
979
+
980
+ :class:`CachedRepresentation` is implemented by means of a cache.
981
+ This cache uses weak references in general, but strong references to
982
+ the most recently created objects. Hence, when all other references
983
+ to, say, ``MyClass(1)`` have been deleted, the instance is
984
+ eventually deleted from memory (after enough other objects have been
985
+ created to remove the strong reference to ``MyClass(1)``). A later
986
+ call to ``MyClass(1)`` reconstructs the instance from scratch::
987
+
988
+ sage: class SomeClass(UniqueRepresentation):
989
+ ....: def __init__(self, i):
990
+ ....: print("creating new instance for argument %s" % i)
991
+ ....: self.i = i
992
+ ....: def __del__(self):
993
+ ....: print("deleting instance for argument %s" % self.i)
994
+ sage: class OtherClass(UniqueRepresentation):
995
+ ....: def __init__(self, i):
996
+ ....: pass
997
+ sage: O = SomeClass(1)
998
+ creating new instance for argument 1
999
+ sage: O is SomeClass(1)
1000
+ True
1001
+ sage: O is SomeClass(2)
1002
+ creating new instance for argument 2
1003
+ False
1004
+ sage: L = [OtherClass(i) for i in range(200)]
1005
+ deleting instance for argument 2
1006
+ sage: del O
1007
+ deleting instance for argument 1
1008
+ sage: O = SomeClass(1)
1009
+ creating new instance for argument 1
1010
+ sage: del O
1011
+ sage: del L
1012
+ sage: L = [OtherClass(i) for i in range(200)]
1013
+ deleting instance for argument 1
1014
+
1015
+ .. rubric:: Cached representation and pickling
1016
+
1017
+ The default Python pickling implementation (by reconstructing an object
1018
+ from its class and dictionary, see "The pickle protocol" in the Python
1019
+ Library Reference) does not preserve cached representation, as Python has
1020
+ no chance to know whether and where the same object already exists.
1021
+
1022
+ :class:`CachedRepresentation` tries to ensure appropriate pickling by
1023
+ implementing a :meth:`__reduce__ <object.__reduce__>` method returning the
1024
+ arguments passed to the constructor::
1025
+
1026
+ sage: import __main__ # Fake MyClass being defined in a python module
1027
+ sage: __main__.MyClass = MyClass
1028
+ sage: x = MyClass(1)
1029
+ sage: loads(dumps(x)) is x
1030
+ True
1031
+
1032
+ :class:`CachedRepresentation` uses the :meth:`__reduce__
1033
+ <object.__reduce__>` pickle protocol rather than :meth:`__getnewargs__
1034
+ <object.__getnewargs__>` because the latter does not handle keyword
1035
+ arguments::
1036
+
1037
+ sage: x = MyClass(value = 1)
1038
+ sage: x.__reduce__()
1039
+ (<function unreduce at ...>, (<class '__main__.MyClass'>, (), {'value': 1}))
1040
+ sage: x is loads(dumps(x))
1041
+ True
1042
+
1043
+ .. NOTE::
1044
+
1045
+ The default implementation of :meth:`__reduce__ <object.__reduce__>`
1046
+ in :class:`CachedRepresentation` requires to store the constructor's
1047
+ arguments in the instance dictionary upon construction::
1048
+
1049
+ sage: x.__dict__
1050
+ {'_reduction': (<class '__main__.MyClass'>, (), {'value': 1}), 'value': 1}
1051
+
1052
+ It is often easy in a derived subclass to reconstruct the constructor's
1053
+ arguments from the instance data structure. When this is the case,
1054
+ :meth:`__reduce__ <object.__reduce__>` should be overridden; automagically
1055
+ the arguments won't be stored anymore::
1056
+
1057
+ sage: class MyClass3(UniqueRepresentation):
1058
+ ....: def __init__(self, value):
1059
+ ....: self.value = value
1060
+ ....:
1061
+ ....: def __reduce__(self):
1062
+ ....: return (MyClass3, (self.value,))
1063
+ sage: import __main__; __main__.MyClass3 = MyClass3 # Fake MyClass3 being defined in a python module
1064
+ sage: x = MyClass3(1)
1065
+ sage: loads(dumps(x)) is x
1066
+ True
1067
+ sage: x.__dict__
1068
+ {'value': 1}
1069
+
1070
+ .. rubric:: Migrating classes to ``CachedRepresentation`` and unpickling
1071
+
1072
+ We check that, when migrating a class to :class:`CachedRepresentation`,
1073
+ older pickles can still be reasonably unpickled. Let us create a
1074
+ (new style) class, and pickle one of its instances::
1075
+
1076
+ sage: class MyClass4():
1077
+ ....: def __init__(self, value):
1078
+ ....: self.value = value
1079
+ sage: import __main__; __main__.MyClass4 = MyClass4 # Fake MyClass4 being defined in a python module
1080
+ sage: pickle = dumps(MyClass4(1))
1081
+
1082
+ It can be unpickled::
1083
+
1084
+ sage: y = loads(pickle)
1085
+ sage: y.value
1086
+ 1
1087
+
1088
+ Now, we upgrade the class to derive from :class:`UniqueRepresentation`,
1089
+ which inherits from :class:`CachedRepresentation`::
1090
+
1091
+ sage: class MyClass4(UniqueRepresentation, object):
1092
+ ....: def __init__(self, value):
1093
+ ....: self.value = value
1094
+ sage: import __main__; __main__.MyClass4 = MyClass4 # Fake MyClass4 being defined in a python module
1095
+ sage: __main__.MyClass4 = MyClass4
1096
+
1097
+ The pickle can still be unpickled::
1098
+
1099
+ sage: y = loads(pickle)
1100
+ sage: y.value
1101
+ 1
1102
+
1103
+ Note however that, for the reasons explained above, unique
1104
+ representation is not guaranteed in this case::
1105
+
1106
+ sage: y is MyClass4(1)
1107
+ False
1108
+
1109
+ .. TODO::
1110
+
1111
+ Illustrate how this can be fixed on a case by case basis.
1112
+
1113
+ Now, we redo the same test for a class deriving from SageObject::
1114
+
1115
+ sage: class MyClass4(SageObject):
1116
+ ....: def __init__(self, value):
1117
+ ....: self.value = value
1118
+ sage: import __main__; __main__.MyClass4 = MyClass4 # Fake MyClass4 being defined in a python module
1119
+ sage: pickle = dumps(MyClass4(1))
1120
+
1121
+ sage: class MyClass4(UniqueRepresentation, SageObject):
1122
+ ....: def __init__(self, value):
1123
+ ....: self.value = value
1124
+ sage: __main__.MyClass4 = MyClass4
1125
+ sage: y = loads(pickle)
1126
+ sage: y.value
1127
+ 1
1128
+
1129
+ Caveat: unpickling instances of a formerly old-style class is not supported yet by default::
1130
+
1131
+ sage: class MyClass4:
1132
+ ....: def __init__(self, value):
1133
+ ....: self.value = value
1134
+ sage: import __main__; __main__.MyClass4 = MyClass4 # Fake MyClass4 being defined in a python module
1135
+ sage: pickle = dumps(MyClass4(1))
1136
+
1137
+ sage: class MyClass4(UniqueRepresentation, SageObject):
1138
+ ....: def __init__(self, value):
1139
+ ....: self.value = value
1140
+ sage: __main__.MyClass4 = MyClass4
1141
+ sage: y = loads(pickle) # todo: not implemented
1142
+ sage: y.value # todo: not implemented
1143
+ 1
1144
+
1145
+ .. rubric:: Rationale for the current implementation
1146
+
1147
+ :class:`CachedRepresentation` and derived classes use the
1148
+ :class:`~sage.misc.classcall_metaclass.ClasscallMetaclass`
1149
+ of the standard Python type. The following example explains why.
1150
+
1151
+ We define a variant of ``MyClass`` where the calls to
1152
+ :meth:`__init__<object.__init__>` are traced::
1153
+
1154
+ sage: class MyClass(CachedRepresentation):
1155
+ ....: def __init__(self, value):
1156
+ ....: print("initializing object")
1157
+ ....: self.value = value
1158
+
1159
+ Let us create an object twice::
1160
+
1161
+ sage: x = MyClass(1)
1162
+ initializing object
1163
+ sage: z = MyClass(1)
1164
+
1165
+ As desired the :meth:`__init__<object.__init__>` method was only called
1166
+ the first time, which is an important feature.
1167
+
1168
+ As far as we can tell, this is not achievable while just using
1169
+ :meth:`__new__<object.__new__>` and :meth:`__init__<object.__init__>` (as
1170
+ defined by type; see Section :python:`Basic Customization
1171
+ <reference/datamodel.html#basic-customization>` in the Python Reference
1172
+ Manual). Indeed, :meth:`__init__<object.__init__>` is called
1173
+ systematically on the result of :meth:`__new__<object.__new__>` whenever
1174
+ the result is an instance of the class.
1175
+
1176
+ Another difficulty is that argument preprocessing (as in the example
1177
+ above) cannot be handled by :meth:`__new__<object.__new__>`, since the
1178
+ unprocessed arguments will be passed down to
1179
+ :meth:`__init__<object.__init__>`.
1180
+ """
1181
+
1182
+ @weak_cached_function(cache=128) # automatically a staticmethod
1183
+ def __classcall__(cls, *args, **options):
1184
+ """
1185
+ Construct a new object of this class or reuse an existing one.
1186
+
1187
+ See also :class:`CachedRepresentation` and
1188
+ :class:`UniqueRepresentation` for a discussion.
1189
+
1190
+ EXAMPLES::
1191
+
1192
+ sage: x = UniqueRepresentation()
1193
+ sage: y = UniqueRepresentation()
1194
+ sage: x is y # indirect doctest
1195
+ True
1196
+ """
1197
+ return super().__classcall__(cls, *args, **options)
1198
+
1199
+ @classmethod
1200
+ def _clear_cache_(cls):
1201
+ """
1202
+ Remove all instances of this class from the cache.
1203
+
1204
+ EXAMPLES:
1205
+
1206
+ If ``cls`` overloads :meth:`~sage.structure.unique_representation.CachedRepresentation.__classcall__`,
1207
+ clearing the cache still works, because ``cls.mro()``
1208
+ is searched until a ``__classcall__`` with an attribute
1209
+ ``cache`` is found::
1210
+
1211
+ sage: class A(UniqueRepresentation):
1212
+ ....: def __init__(self, x):
1213
+ ....: pass
1214
+ sage: class B(A):
1215
+ ....: @staticmethod
1216
+ ....: def __classcall__(cls, *args, **kwds):
1217
+ ....: return super().__classcall__(cls, *args, **kwds)
1218
+ sage: class C(B): pass
1219
+ sage: a = A(1)
1220
+ sage: b = B(2)
1221
+ sage: c = C(3)
1222
+ sage: a is A(1)
1223
+ True
1224
+ sage: b is B(2)
1225
+ True
1226
+ sage: c is C(3)
1227
+ True
1228
+ sage: B._clear_cache_()
1229
+
1230
+ Now, all instances of (sub-classes of) ``B`` have disappeared
1231
+ from the cache::
1232
+
1233
+ sage: a is A(1)
1234
+ True
1235
+ sage: b is B(2)
1236
+ False
1237
+ sage: c is C(3)
1238
+ False
1239
+
1240
+ Here is a similar example, using a private classcall in the class
1241
+ ``B``, which is not inherited by ``C``::
1242
+
1243
+ sage: class A(UniqueRepresentation):
1244
+ ....: def __init__(self, x):
1245
+ ....: pass
1246
+ sage: class B(A):
1247
+ ....: @staticmethod
1248
+ ....: def __classcall_private__(cls, *args, **kwds):
1249
+ ....: print("Private B")
1250
+ ....: return super().__classcall__(cls, *args, **kwds)
1251
+ sage: class C(B): pass
1252
+ sage: a = A(1)
1253
+ sage: b = B(2)
1254
+ Private B
1255
+ sage: c = C(3)
1256
+ sage: a is A(1)
1257
+ True
1258
+ sage: b is B(2)
1259
+ Private B
1260
+ True
1261
+ sage: c is C(3)
1262
+ True
1263
+ sage: B._clear_cache_()
1264
+
1265
+ Again, all instances of (sub-classes of) ``B`` have disappeared
1266
+ from the cache::
1267
+
1268
+ sage: a is A(1)
1269
+ True
1270
+ sage: b is B(2)
1271
+ Private B
1272
+ False
1273
+ sage: c is C(3)
1274
+ False
1275
+ """
1276
+ cache = None
1277
+ # not clear why the loop below is taking the last C
1278
+ for C in cls.mro():
1279
+ try:
1280
+ cache = C.__classcall__.cache
1281
+ except AttributeError:
1282
+ pass
1283
+ del_list = [k for k in cache if issubclass(k[0][0], cls)]
1284
+ for k in del_list:
1285
+ del cache[k]
1286
+
1287
+
1288
+ class UniqueRepresentation(WithEqualityById, CachedRepresentation):
1289
+ r"""
1290
+ Classes derived from ``UniqueRepresentation`` inherit a unique
1291
+ representation behavior for their instances.
1292
+
1293
+ .. SEEALSO::
1294
+
1295
+ :mod:`~sage.structure.unique_representation`
1296
+
1297
+ EXAMPLES:
1298
+
1299
+ The short story: to construct a class whose instances have a
1300
+ unique representation behavior one just has to do::
1301
+
1302
+ sage: class MyClass(UniqueRepresentation):
1303
+ ....: # all the rest as usual
1304
+ ....: pass
1305
+
1306
+ Everything below is for the curious or for advanced usage.
1307
+
1308
+ .. rubric:: What is unique representation?
1309
+
1310
+ Instances of a class have a *unique representation behavior* when
1311
+ instances evaluate equal if and only if they are identical (i.e., share
1312
+ the same memory representation), if and only if they were created using
1313
+ equal arguments. For example, calling twice::
1314
+
1315
+ sage: f = SymmetricFunctions(QQ) # needs sage.combinat sage.modules
1316
+ sage: g = SymmetricFunctions(QQ) # needs sage.combinat sage.modules
1317
+
1318
+ to create the symmetric function algebra over `\QQ` actually gives back the
1319
+ same object::
1320
+
1321
+ sage: f == g # needs sage.combinat sage.modules
1322
+ True
1323
+ sage: f is g # needs sage.combinat sage.modules
1324
+ True
1325
+
1326
+ This is a standard design pattern. It allows for sharing cached data (say
1327
+ representation theoretical information about a group) as well as for very
1328
+ fast hashing and equality testing. This behaviour is typically desirable
1329
+ for parents and categories. It can also be useful for intensive
1330
+ computations where one wants to cache all the operations on a small set of
1331
+ elements (say the multiplication table of a small group), and access this
1332
+ cache as quickly as possible.
1333
+
1334
+ :class:`UniqueRepresentation` is very easy to use: a class just needs to
1335
+ derive from it, or make sure some of its super classes does. Also, it
1336
+ groups together the class and the factory in a single gadget::
1337
+
1338
+ sage: isinstance(SymmetricFunctions(CC), SymmetricFunctions) # needs sage.combinat sage.modules
1339
+ True
1340
+ sage: issubclass(SymmetricFunctions, UniqueRepresentation) # needs sage.combinat sage.modules
1341
+ True
1342
+
1343
+ This nice behaviour is not available when one just uses a factory::
1344
+
1345
+ sage: isinstance(GF(7), GF)
1346
+ Traceback (most recent call last):
1347
+ ...
1348
+ TypeError: isinstance() arg 2 must be a type...
1349
+
1350
+ sage: isinstance(GF, sage.structure.factory.UniqueFactory)
1351
+ True
1352
+
1353
+ In addition, :class:`~sage.structure.factory.UniqueFactory` only provides
1354
+ the *cached* representation behaviour, but not the *unique* representation
1355
+ behaviour---the examples in :mod:`~sage.structure.unique_representation`
1356
+ explain this difference.
1357
+
1358
+ On the other hand, the :class:`UniqueRepresentation` class is more
1359
+ intrusive, as it imposes a behavior (and a metaclass) on all the
1360
+ subclasses. In particular, the unique representation behaviour is imposed
1361
+ on *all* subclasses (unless the ``__classcall__`` method is overloaded and
1362
+ not called in the subclass, which is not recommended). Its implementation
1363
+ is also more technical, which leads to some subtleties.
1364
+
1365
+ EXAMPLES:
1366
+
1367
+ We start with a simple class whose constructor takes a single value as
1368
+ argument. This pattern is similar to what is done in
1369
+ :class:`sage.combinat.sf.sf.SymmetricFunctions`::
1370
+
1371
+ sage: class MyClass(UniqueRepresentation):
1372
+ ....: def __init__(self, value):
1373
+ ....: self.value = value
1374
+
1375
+ Two coexisting instances of ``MyClass`` created with the same argument
1376
+ data are guaranteed to share the same identity. Since :issue:`12215`, this
1377
+ is only the case if there is some strong reference to the returned
1378
+ instance, since otherwise it may be garbage collected::
1379
+
1380
+ sage: x = MyClass(1)
1381
+ sage: y = MyClass(1)
1382
+ sage: x is y # There is a strong reference
1383
+ True
1384
+ sage: z = MyClass(2)
1385
+ sage: x is z
1386
+ False
1387
+
1388
+ In particular, modifying any one of them modifies the other
1389
+ (reference effect)::
1390
+
1391
+ sage: x.value = 3
1392
+ sage: x.value, y.value
1393
+ (3, 3)
1394
+ sage: y.value = 1
1395
+ sage: x.value, y.value
1396
+ (1, 1)
1397
+
1398
+ When comparing two instances of a unique representation with ``==``
1399
+ or ``!=`` comparison by identity is used::
1400
+
1401
+ sage: x == y
1402
+ True
1403
+ sage: x is y
1404
+ True
1405
+ sage: z = MyClass(2)
1406
+ sage: x == z
1407
+ False
1408
+ sage: x is z
1409
+ False
1410
+ sage: x != y
1411
+ False
1412
+ sage: x != z
1413
+ True
1414
+
1415
+ A hash function equivalent to :meth:`object.__hash__` is used, which is
1416
+ compatible with comparison by identity. However this means that the hash
1417
+ function may change in between Sage sessions, or even within the same Sage
1418
+ session.
1419
+ ::
1420
+
1421
+ sage: hash(x) == object.__hash__(x)
1422
+ True
1423
+
1424
+ .. WARNING::
1425
+
1426
+ It is possible to inherit from
1427
+ :class:`~sage.structure.unique_representation.UniqueRepresentation`
1428
+ and then overload comparison in a way that destroys the unique
1429
+ representation property. We strongly recommend against it! You should
1430
+ use :class:`~sage.structure.unique_representation.CachedRepresentation`
1431
+ instead.
1432
+
1433
+ .. rubric:: Mixing super types and super classes
1434
+
1435
+ TESTS:
1436
+
1437
+ For the record, this test did fail with previous implementation
1438
+ attempts::
1439
+
1440
+ sage: class bla(UniqueRepresentation, SageObject):
1441
+ ....: pass
1442
+ sage: b = bla()
1443
+ """