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,1867 @@
1
+ # sage_setup: distribution = sagemath-objects
2
+ r"""
3
+ Elements, Array and Lists With Clone Protocol
4
+
5
+ This module defines several classes which are subclasses of
6
+ :class:`Element<sage.structure.element.Element>` and which roughly implement
7
+ the "prototype" design pattern (see [Prototype_pattern]_, [GHJV1994]_). Those classes are
8
+ intended to be used to model *mathematical* objects, which are by essence
9
+ immutable. However, in many occasions, one wants to construct the
10
+ data-structure encoding of a new mathematical object by small modifications of
11
+ the data structure encoding some already built object. For the resulting
12
+ data-structure to correctly encode the mathematical object, some structural
13
+ invariants must hold. One problem is that, in many cases, during the
14
+ modification process, there is no possibility but to break the invariants.
15
+
16
+ For example, in a list modeling a permutation of `\{1,\dots,n\}`, the integers
17
+ must be distinct. A very common operation is to take a permutation to make a
18
+ copy with some small modifications, like exchanging two consecutive values in
19
+ the list or cycling some values. Though the result is clearly a permutations
20
+ there's no way to avoid breaking the permutations invariants at some point
21
+ during the modifications.
22
+
23
+ The main purpose of this module is to define the class
24
+
25
+ - :class:`ClonableElement` as an abstract super class,
26
+
27
+ and its subclasses:
28
+
29
+ - :class:`ClonableArray` for arrays (lists of fixed length) of objects;
30
+ - :class:`ClonableList` for (resizable) lists of objects;
31
+ - :class:`NormalizedClonableList` for lists of objects with a normalization method;
32
+ - :class:`ClonableIntArray` for arrays of int.
33
+
34
+ .. SEEALSO:: The following parents from :mod:`sage.structure.list_clone_demo`
35
+ demonstrate how to use them:
36
+
37
+ - ``IncreasingArrays()`` (see
38
+ :class:`~sage.structure.list_clone_demo.IncreasingArray`
39
+ and the parent class
40
+ :class:`~sage.structure.list_clone_demo.IncreasingArrays`)
41
+ - ``IncreasingLists()`` (see
42
+ :class:`~sage.structure.list_clone_demo.IncreasingList`
43
+ and the parent class
44
+ :class:`~sage.structure.list_clone_demo.IncreasingLists`)
45
+ - ``SortedLists()`` (see
46
+ :class:`~sage.structure.list_clone_demo.SortedList`
47
+ and the parent class
48
+ :class:`~sage.structure.list_clone_demo.SortedLists`)
49
+ - ``IncreasingIntArrays()`` (see
50
+ :class:`~sage.structure.list_clone_demo.IncreasingIntArray`
51
+ and the parent class
52
+ :class:`~sage.structure.list_clone_demo.IncreasingIntArrays`)
53
+
54
+ EXAMPLES:
55
+
56
+ We now demonstrate how
57
+ :class:`~sage.structure.list_clone_demo.IncreasingArray` works, creating an
58
+ instance ``el`` through its parent ``IncreasingArrays()``::
59
+
60
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
61
+ sage: P = IncreasingArrays()
62
+ sage: P([1, 4 ,8])
63
+ [1, 4, 8]
64
+
65
+ If one tries to create this way a list which in not increasing, an error is
66
+ raised::
67
+
68
+ sage: IncreasingArrays()([5, 4 ,8])
69
+ Traceback (most recent call last):
70
+ ...
71
+ ValueError: array is not increasing
72
+
73
+ Once created modifying ``el`` is forbidden::
74
+
75
+ sage: el = P([1, 4 ,8])
76
+ sage: el[1] = 3
77
+ Traceback (most recent call last):
78
+ ...
79
+ ValueError: object is immutable; please change a copy instead.
80
+
81
+ However, you can modify a temporarily mutable clone::
82
+
83
+ sage: with el.clone() as elc:
84
+ ....: elc[1] = 3
85
+ sage: [el, elc]
86
+ [[1, 4, 8], [1, 3, 8]]
87
+
88
+ We check that the original and the modified copy now are in a proper immutable
89
+ state::
90
+
91
+ sage: el.is_immutable(), elc.is_immutable()
92
+ (True, True)
93
+ sage: elc[1] = 5
94
+ Traceback (most recent call last):
95
+ ...
96
+ ValueError: object is immutable; please change a copy instead.
97
+
98
+ You can break the property that the list is increasing during the
99
+ modification::
100
+
101
+ sage: with el.clone() as elc2:
102
+ ....: elc2[1] = 12
103
+ ....: print(elc2)
104
+ ....: elc2[2] = 25
105
+ [1, 12, 8]
106
+ sage: elc2
107
+ [1, 12, 25]
108
+
109
+ But this property must be restored at the end of the ``with`` block; otherwise
110
+ an error is raised::
111
+
112
+ sage: with elc2.clone() as el3:
113
+ ....: el3[1] = 100
114
+ Traceback (most recent call last):
115
+ ...
116
+ ValueError: array is not increasing
117
+
118
+ Finally, as an alternative to the ``with`` syntax one can use::
119
+
120
+ sage: el4 = copy(elc2)
121
+ sage: el4[1] = 10
122
+ sage: el4.set_immutable()
123
+ sage: el4.check()
124
+
125
+ REFERENCES:
126
+
127
+ - [Prototype_pattern]_
128
+ - [GHJV1994]_
129
+
130
+ AUTHORS:
131
+
132
+ - Florent Hivert (2010-03): initial revision
133
+ """
134
+ # ****************************************************************************
135
+ # Copyright (C) 2009-2010 Florent Hivert <Florent.Hivert@univ-rouen.fr>
136
+ #
137
+ # This program is free software: you can redistribute it and/or modify
138
+ # it under the terms of the GNU General Public License as published by
139
+ # the Free Software Foundation, either version 2 of the License, or
140
+ # (at your option) any later version.
141
+ # https://www.gnu.org/licenses/
142
+ # ****************************************************************************
143
+
144
+ from cpython.list cimport *
145
+ from cpython.long cimport *
146
+ from cpython.ref cimport *
147
+
148
+ from cysignals.memory cimport check_reallocarray, sig_free
149
+
150
+ from sage.ext.stdsage cimport HAS_DICTIONARY
151
+ from sage.structure.element cimport Element
152
+ from sage.structure.parent cimport Parent
153
+ from sage.structure.richcmp cimport richcmp, rich_to_bool
154
+
155
+ ############################################################################
156
+ # Basic clone elements #
157
+ ############################################################################
158
+ cdef class ClonableElement(Element):
159
+ r"""
160
+ Abstract class for elements with clone protocol.
161
+
162
+ This class is a subclass of :class:`Element<sage.structure.element.Element>`
163
+ and implements the "prototype" design pattern (see [Prototype_pattern]_, [GHJV1994]_). The role
164
+ of this class is:
165
+
166
+ - to manage copy and mutability and hashing of elements
167
+ - to ensure that at the end of a piece of code an object is restored in a
168
+ meaningful mathematical state.
169
+
170
+ A class ``C`` inheriting from :class:`ClonableElement` must implement
171
+ the following two methods
172
+
173
+ - ``obj.__copy__()`` -- returns a fresh copy of obj
174
+ - ``obj.check()`` -- returns nothing, raise an exception if ``obj``
175
+ doesn't satisfy the data structure invariants
176
+
177
+ and ensure to call ``obj._require_mutable()`` at the beginning of any
178
+ modifying method.
179
+
180
+ Additionally, one can also implement
181
+
182
+ - ``obj._hash_()`` -- return the hash value of ``obj``
183
+
184
+ Then, given an instance ``obj`` of ``C``, the following sequences of
185
+ instructions ensures that the invariants of ``new_obj`` are properly
186
+ restored at the end::
187
+
188
+ with obj.clone() as new_obj:
189
+ ...
190
+ # lot of invariant breaking modifications on new_obj
191
+ ...
192
+ # invariants are ensured to be fulfilled
193
+
194
+ The following equivalent sequence of instructions can be used if speed is
195
+ needed, in particular in Cython code::
196
+
197
+ new_obj = obj.__copy__()
198
+ ...
199
+ # lot of invariant breaking modifications on new_obj
200
+ ...
201
+ new_obj.set_immutable()
202
+ new_obj.check()
203
+ # invariants are ensured to be fulfilled
204
+
205
+ Finally, if the class implements the ``_hash_`` method, then
206
+ :class:`ClonableElement` ensures that the hash value can only be
207
+ computed on an immutable object. It furthermore caches it so that
208
+ it is only computed once.
209
+
210
+ .. warning:: for the hash caching mechanism to work correctly, the hash
211
+ value cannot be 0.
212
+
213
+ EXAMPLES:
214
+
215
+ The following code shows a minimal example of usage of
216
+ :class:`ClonableElement`. We implement a class or pairs `(x,y)`
217
+ such that `x < y`::
218
+
219
+ sage: from sage.structure.list_clone import ClonableElement
220
+ sage: class IntPair(ClonableElement):
221
+ ....: def __init__(self, parent, x, y):
222
+ ....: ClonableElement.__init__(self, parent=parent)
223
+ ....: self._x = x
224
+ ....: self._y = y
225
+ ....: self.set_immutable()
226
+ ....: self.check()
227
+ ....: def _repr_(self):
228
+ ....: return "(x=%s, y=%s)"%(self._x, self._y)
229
+ ....: def check(self):
230
+ ....: if self._x >= self._y:
231
+ ....: raise ValueError("Incorrectly ordered pair")
232
+ ....: def get_x(self): return self._x
233
+ ....: def get_y(self): return self._y
234
+ ....: def set_x(self, v): self._require_mutable(); self._x = v
235
+ ....: def set_y(self, v): self._require_mutable(); self._y = v
236
+
237
+ .. NOTE:: we don't need to define ``__copy__`` since it is properly
238
+ inherited from :class:`Element<sage.structure.element.Element>`.
239
+
240
+ We now demonstrate the behavior. Let's create an ``IntPair``::
241
+
242
+ sage: myParent = Parent()
243
+ sage: el = IntPair(myParent, 1, 3); el
244
+ (x=1, y=3)
245
+ sage: el.get_x()
246
+ 1
247
+
248
+ Modifying it is forbidden::
249
+
250
+ sage: el.set_x(4)
251
+ Traceback (most recent call last):
252
+ ...
253
+ ValueError: object is immutable; please change a copy instead.
254
+
255
+ However, you can modify a mutable copy::
256
+
257
+ sage: with el.clone() as el1:
258
+ ....: el1.set_x(2)
259
+ sage: [el, el1]
260
+ [(x=1, y=3), (x=2, y=3)]
261
+
262
+ We check that the original and the modified copy are in a proper immutable
263
+ state::
264
+
265
+ sage: el.is_immutable(), el1.is_immutable()
266
+ (True, True)
267
+ sage: el1.set_x(4)
268
+ Traceback (most recent call last):
269
+ ...
270
+ ValueError: object is immutable; please change a copy instead.
271
+
272
+ A modification which doesn't restore the invariant `x < y` at the end is
273
+ illegal and raise an exception::
274
+
275
+ sage: with el.clone() as elc2:
276
+ ....: elc2.set_x(5)
277
+ Traceback (most recent call last):
278
+ ...
279
+ ValueError: Incorrectly ordered pair
280
+ """
281
+ def __cinit__(self):
282
+ """
283
+ TESTS::
284
+
285
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
286
+ sage: el = IncreasingArrays()([1,2,3]) # indirect doctest
287
+ sage: el.is_immutable()
288
+ True
289
+ """
290
+ self._needs_check = True
291
+ self._is_immutable = False
292
+ self._hash = 0
293
+
294
+ cpdef bint _require_mutable(self) except -2:
295
+ """
296
+ Check that ``self`` is mutable.
297
+
298
+ Raise a :exc:`ValueError` if ``self`` is immutable.
299
+
300
+ TESTS::
301
+
302
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
303
+ sage: el = IncreasingArrays()([1,2,3])
304
+ sage: el._require_mutable()
305
+ Traceback (most recent call last):
306
+ ...
307
+ ValueError: object is immutable; please change a copy instead.
308
+ """
309
+ if self._is_immutable:
310
+ raise ValueError("object is immutable; please change a copy instead.")
311
+
312
+ cpdef bint is_mutable(self) noexcept:
313
+ """
314
+ Return ``True`` if ``self`` is mutable (can be changed) and ``False``
315
+ if it is not.
316
+
317
+ To make this object immutable use ``self.set_immutable()``.
318
+
319
+ EXAMPLES::
320
+
321
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
322
+ sage: el = IncreasingArrays()([1,2,3])
323
+ sage: el.is_mutable()
324
+ False
325
+ sage: copy(el).is_mutable()
326
+ True
327
+ sage: with el.clone() as el1:
328
+ ....: print([el.is_mutable(), el1.is_mutable()])
329
+ [False, True]
330
+ """
331
+ return not self._is_immutable
332
+
333
+ cpdef bint is_immutable(self) noexcept:
334
+ """
335
+ Return ``True`` if ``self`` is immutable (cannot be changed)
336
+ and ``False`` if it is not.
337
+
338
+ To make ``self`` immutable use ``self.set_immutable()``.
339
+
340
+ EXAMPLES::
341
+
342
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
343
+ sage: el = IncreasingArrays()([1,2,3])
344
+ sage: el.is_immutable()
345
+ True
346
+ sage: copy(el).is_immutable()
347
+ False
348
+ sage: with el.clone() as el1:
349
+ ....: print([el.is_immutable(), el1.is_immutable()])
350
+ [True, False]
351
+ """
352
+ return self._is_immutable
353
+
354
+ cpdef set_immutable(self):
355
+ """
356
+ Makes ``self`` immutable, so it can never again be changed.
357
+
358
+ EXAMPLES::
359
+
360
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
361
+ sage: el = IncreasingArrays()([1,2,3])
362
+ sage: el1 = copy(el); el1.is_mutable()
363
+ True
364
+ sage: el1.set_immutable(); el1.is_mutable()
365
+ False
366
+ sage: el1[2] = 4
367
+ Traceback (most recent call last):
368
+ ...
369
+ ValueError: object is immutable; please change a copy instead.
370
+ """
371
+ self._is_immutable = True
372
+
373
+ cpdef _set_mutable(self):
374
+ """
375
+ Makes ``self`` mutable, so it can be changed.
376
+
377
+ .. warning:: for internal use only. Casual users should make a copy
378
+ using either the :meth:`__copy__` method or the :meth:`clone`
379
+ protocol. Use only if you really know what you are doing. You
380
+ should in particular make sure that you are the only owner of
381
+ your object.
382
+
383
+ TESTS::
384
+
385
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
386
+ sage: el = IncreasingArrays()([1,2,3])
387
+ sage: el._set_mutable(); el.is_mutable()
388
+ True
389
+ sage: hash(el)
390
+ Traceback (most recent call last):
391
+ ...
392
+ ValueError: cannot hash a mutable object.
393
+ """
394
+ self._hash = 0
395
+ self._is_immutable = False
396
+
397
+ def __hash__(self):
398
+ """
399
+ Return the hash value of ``self``.
400
+
401
+ TESTS::
402
+
403
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
404
+ sage: el = IncreasingArrays()([1,2,3])
405
+ sage: hash(el) # random
406
+ -309690657
407
+ sage: el1 = copy(el); hash(el1)
408
+ Traceback (most recent call last):
409
+ ...
410
+ ValueError: cannot hash a mutable object.
411
+ """
412
+ if self._hash == 0:
413
+ if not self._is_immutable:
414
+ raise ValueError("cannot hash a mutable object.")
415
+ else:
416
+ self._hash = self._hash_()
417
+ return self._hash
418
+
419
+ cpdef ClonableElement clone(self, bint check=True):
420
+ """
421
+ Return a clone that is mutable copy of ``self``.
422
+
423
+ INPUT:
424
+
425
+ - ``check`` -- boolean indicating if ``self.check()`` must be called
426
+ after modifications
427
+
428
+ EXAMPLES::
429
+
430
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
431
+ sage: el = IncreasingArrays()([1,2,3])
432
+ sage: with el.clone() as el1:
433
+ ....: el1[2] = 5
434
+ sage: el1
435
+ [1, 2, 5]
436
+ """
437
+ cdef ClonableElement res
438
+ res = self.__copy__()
439
+ res._needs_check = check
440
+ return res
441
+
442
+ def __enter__(self):
443
+ """
444
+ Implement the ``self`` guarding clone protocol.
445
+
446
+ TESTS::
447
+
448
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
449
+ sage: el = IncreasingArrays()([1,2,3])
450
+ sage: el.clone().__enter__()
451
+ [1, 2, 3]
452
+ """
453
+ self._require_mutable()
454
+ return self
455
+
456
+ def __exit__(self, typ, value, tracback):
457
+ """
458
+ Implement the ``self`` guarding clone protocol.
459
+
460
+ .. NOTE:: The input argument are required by the ``with`` protocol but
461
+ are ignored.
462
+
463
+ TESTS::
464
+
465
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
466
+ sage: el = IncreasingArrays()([1,2,3])
467
+ sage: el1 = el.clone().__enter__()
468
+ sage: el1.__exit__(None, None, None)
469
+ False
470
+
471
+ Lets try to make a broken list::
472
+
473
+ sage: elc2 = el.clone().__enter__()
474
+ sage: elc2[1] = 7
475
+ sage: elc2.__exit__(None, None, None)
476
+ Traceback (most recent call last):
477
+ ...
478
+ ValueError: array is not increasing
479
+ """
480
+ self.set_immutable()
481
+ if __debug__ and self._needs_check:
482
+ self.check()
483
+ # is there a way if check() fails to replace self by a invalid object ?
484
+ return False
485
+
486
+
487
+ ############################################################################
488
+ # The most common case of clone object : list with constraints #
489
+ ############################################################################
490
+ cdef class ClonableArray(ClonableElement):
491
+ """
492
+ Array with clone protocol.
493
+
494
+ The class of objects which are
495
+ :class:`Element<sage.structure.element.Element>` behave as arrays
496
+ (i.e. lists of fixed length) and implement the clone protocol. See
497
+ :class:`ClonableElement` for details about clone protocol.
498
+
499
+ INPUT:
500
+
501
+ - ``parent`` -- a :class:`Parent<sage.structure.parent.Parent>`
502
+ - ``lst`` -- list
503
+ - ``check`` -- boolean specifying if the invariant must be checked
504
+ using method :meth:`check`
505
+ - ``immutable`` -- boolean (default: ``True``); whether the created element
506
+ is immutable
507
+
508
+ .. SEEALSO:: :class:`~sage.structure.list_clone_demo.IncreasingArray` for
509
+ an example of usage.
510
+
511
+ EXAMPLES::
512
+
513
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
514
+ sage: IA = IncreasingArrays()
515
+ sage: ia1 = IA([1, 4, 6]); ia1
516
+ [1, 4, 6]
517
+ sage: with ia1.clone() as ia2:
518
+ ....: ia2[1] = 5
519
+ sage: ia2
520
+ [1, 5, 6]
521
+ sage: with ia1.clone() as ia2:
522
+ ....: ia2[1] = 7
523
+ Traceback (most recent call last):
524
+ ...
525
+ ValueError: array is not increasing
526
+ """
527
+ def __init__(self, Parent parent, lst, check=True, immutable=True):
528
+ """
529
+ Initialize ``self``.
530
+
531
+ TESTS::
532
+
533
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
534
+ sage: IncreasingArrays()([1,2,3])
535
+ [1, 2, 3]
536
+
537
+ sage: el = IncreasingArrays()([3,2,1])
538
+ Traceback (most recent call last):
539
+ ...
540
+ ValueError: array is not increasing
541
+
542
+ sage: IncreasingArrays()(None)
543
+ Traceback (most recent call last):
544
+ ...
545
+ TypeError: 'NoneType' object is not iterable
546
+
547
+ You are not supposed to do the following (giving a wrong list and
548
+ desactivating checks)::
549
+
550
+ sage: broken = IncreasingArrays()([3,2,1], False)
551
+ """
552
+ self._parent = parent
553
+ self._list = list(lst)
554
+ self._is_immutable = immutable
555
+ if check:
556
+ self.check()
557
+
558
+ def _repr_(self):
559
+ """
560
+ TESTS::
561
+
562
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
563
+ sage: IncreasingArrays()([1,2,3])
564
+ [1, 2, 3]
565
+ """
566
+ return repr(self._list)
567
+
568
+ def __bool__(self):
569
+ """
570
+ Test if ``self`` is not empty.
571
+
572
+ EXAMPLES::
573
+
574
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
575
+ sage: bool(IncreasingArrays()([1,2,3]))
576
+ True
577
+ sage: bool(IncreasingArrays()([]))
578
+ False
579
+ """
580
+ return bool(self._list)
581
+
582
+ cpdef list _get_list(self):
583
+ """
584
+ Return the list embedded in ``self``.
585
+
586
+ .. warning:: No copy is performed. As a consequence, modifying the
587
+ returned list is not allowed.
588
+
589
+ TESTS::
590
+
591
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
592
+ sage: el = IncreasingArrays()([1,2,3])
593
+ sage: el._get_list()
594
+ [1, 2, 3]
595
+ """
596
+ return self._list
597
+
598
+ cpdef _set_list(self, list lst):
599
+ """
600
+ Set the list embedded in ``self``.
601
+
602
+ .. warning:: No copy is performed. Modifying the list after calling
603
+ ``_set_list`` on it is not allowed.
604
+
605
+ TESTS::
606
+
607
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
608
+ sage: el = IncreasingArrays()([1,2,3])
609
+ sage: el._set_list([1,4,5])
610
+ sage: el
611
+ [1, 4, 5]
612
+ """
613
+ self._list = lst
614
+
615
+ def __len__(self):
616
+ """
617
+ Return the ``len`` of ``self``.
618
+
619
+ EXAMPLES::
620
+
621
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
622
+ sage: len(IncreasingArrays()([1,2,3]))
623
+ 3
624
+ """
625
+ return len(self._list)
626
+
627
+ def __getitem__(self, key):
628
+ """
629
+ Return the ``key``-th element of ``self``.
630
+
631
+ It also works with slice returning a python list in this case.
632
+
633
+ EXAMPLES::
634
+
635
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
636
+ sage: IncreasingArrays()([1,2,3])[1]
637
+ 2
638
+ sage: IncreasingArrays()([1,2,3])[7]
639
+ Traceback (most recent call last):
640
+ ...
641
+ IndexError: list index out of range
642
+ sage: IncreasingArrays()([1,2,3])[-1]
643
+ 3
644
+ sage: IncreasingArrays()([1,2,3])[-1:]
645
+ [3]
646
+ sage: IncreasingArrays()([1,2,3])[:]
647
+ [1, 2, 3]
648
+ sage: type(IncreasingArrays()([1,2,3])[:])
649
+ <... 'list'>
650
+ """
651
+ if isinstance(key, slice):
652
+ self._list[key.start:key.stop:key.step]
653
+ return self._list[key]
654
+
655
+ def __setitem__(self, int key, value):
656
+ """
657
+ Set the ``i``-th element of ``self``.
658
+
659
+ An exception is raised if ``self`` is immutable.
660
+
661
+ EXAMPLES::
662
+
663
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
664
+ sage: el = IncreasingArrays()([1,2,4,10])
665
+ sage: elc = copy(el)
666
+ sage: elc[1] = 3; elc
667
+ [1, 3, 4, 10]
668
+ sage: el[1] = 3
669
+ Traceback (most recent call last):
670
+ ...
671
+ ValueError: object is immutable; please change a copy instead.
672
+ sage: elc[5] = 3
673
+ Traceback (most recent call last):
674
+ ...
675
+ IndexError: list assignment index out of range
676
+ """
677
+ self._require_mutable()
678
+ self._list[key] = value
679
+
680
+ cpdef object _getitem(self, int key):
681
+ """
682
+ Same as :meth:`__getitem__`.
683
+
684
+ This is much faster when used with Cython and ``key`` is known to be
685
+ an ``int``.
686
+
687
+ EXAMPLES::
688
+
689
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
690
+ sage: IncreasingArrays()([1,2,3])._getitem(1)
691
+ 2
692
+ sage: IncreasingArrays()([1,2,3])._getitem(5)
693
+ Traceback (most recent call last):
694
+ ...
695
+ IndexError: list index out of range
696
+ """
697
+ return self._list[key]
698
+
699
+ cpdef _setitem(self, int key, value):
700
+ """
701
+ Same as :meth:`__setitem__`.
702
+
703
+ This is much faster when used with Cython and ``key`` is known to be
704
+ an ``int``.
705
+
706
+ EXAMPLES::
707
+
708
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
709
+ sage: el = IncreasingArrays()([1,2,4])
710
+ sage: elc = copy(el)
711
+ sage: elc._setitem(1, 3); elc
712
+ [1, 3, 4]
713
+ sage: el._setitem(1, 3)
714
+ Traceback (most recent call last):
715
+ ...
716
+ ValueError: object is immutable; please change a copy instead.
717
+ sage: elc._setitem(5, 5)
718
+ Traceback (most recent call last):
719
+ ...
720
+ IndexError: list assignment index out of range
721
+ """
722
+ self._require_mutable()
723
+ self._list[key] = value
724
+
725
+ def __iter__(self):
726
+ """
727
+ Return an iterator for ``self``::
728
+
729
+ EXAMPLES::
730
+
731
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
732
+ sage: el = IncreasingArrays()([1,2,4])
733
+ sage: list(iter(el))
734
+ [1, 2, 4]
735
+
736
+ As a consequence ``min``, ``max`` behave properly::
737
+
738
+ sage: el = IncreasingArrays()([1,4,8])
739
+ sage: min(el), max(el)
740
+ (1, 8)
741
+
742
+ TESTS::
743
+
744
+ sage: list(iter(IncreasingArrays()([])))
745
+ []
746
+ """
747
+ return iter(self._list)
748
+
749
+ def __contains__(self, item):
750
+ """
751
+ EXAMPLES::
752
+
753
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
754
+ sage: c = IncreasingArrays()([1,2,4])
755
+ sage: 1 in c
756
+ True
757
+ sage: 5 in c
758
+ False
759
+ """
760
+ return item in self._list
761
+
762
+ cpdef int index(self, x, start=None, stop=None) except -1:
763
+ """
764
+ Return the smallest ``k`` such that ``s[k] == x`` and ``i <= k < j``
765
+
766
+ EXAMPLES::
767
+
768
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
769
+ sage: c = IncreasingArrays()([1,2,4])
770
+ sage: c.index(1)
771
+ 0
772
+ sage: c.index(4)
773
+ 2
774
+ sage: c.index(5)
775
+ Traceback (most recent call last):
776
+ ...
777
+ ValueError: ...not in list
778
+ """
779
+ if start is None:
780
+ return self._list.index(x)
781
+ elif stop is None:
782
+ return self._list.index(x, start)
783
+ else:
784
+ return self._list.index(x, start, stop)
785
+
786
+ cpdef int count(self, key) except -1:
787
+ """
788
+ Return number of ``i``'s for which ``s[i] == key``
789
+
790
+ EXAMPLES::
791
+
792
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
793
+ sage: c = IncreasingArrays()([1,2,2,4])
794
+ sage: c.count(1)
795
+ 1
796
+ sage: c.count(2)
797
+ 2
798
+ sage: c.count(3)
799
+ 0
800
+ """
801
+ return self._list.count(key)
802
+
803
+ def __hash__(self):
804
+ """
805
+ Return the hash value of ``self``.
806
+
807
+ TESTS::
808
+
809
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
810
+ sage: el = IncreasingArrays()([1,2,3])
811
+ sage: hash(el) # random
812
+ -309690657
813
+ sage: el1 = copy(el); hash(el1)
814
+ Traceback (most recent call last):
815
+ ...
816
+ ValueError: cannot hash a mutable object.
817
+ """
818
+ if self._hash == 0:
819
+ if not self._is_immutable:
820
+ raise ValueError("cannot hash a mutable object.")
821
+ else:
822
+ self._hash = self._hash_()
823
+ return self._hash
824
+
825
+ # See protocol in comment in sage/structure/element.pyx
826
+ cpdef _richcmp_(left, right, int op):
827
+ """
828
+ TESTS::
829
+
830
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
831
+ sage: el = IncreasingArrays()([1,2,4])
832
+ sage: elc = copy(el)
833
+ sage: elc == el # indirect doctest
834
+ True
835
+
836
+ ::
837
+
838
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
839
+ sage: el1 = IncreasingArrays()([1,2,4])
840
+ sage: el2 = IncreasingArrays()([1,2,3])
841
+ sage: el1 == el1, el2 == el2, el1 == el2 # indirect doctest
842
+ (True, True, False)
843
+ sage: el1 <= el2, el1 >= el2, el2 <= el1 # indirect doctest
844
+ (False, True, True)
845
+ """
846
+ cdef ClonableArray rgt = <ClonableArray>right
847
+ return richcmp(left._list, rgt._list, op)
848
+
849
+ cpdef ClonableArray __copy__(self):
850
+ """
851
+ Return a copy of ``self``.
852
+
853
+ TESTS::
854
+
855
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
856
+ sage: el = IncreasingArrays()([1,2,4])
857
+ sage: elc = copy(el)
858
+ sage: el[:] == elc[:]
859
+ True
860
+ sage: el is elc
861
+ False
862
+
863
+ We check that empty lists are correctly copied::
864
+
865
+ sage: el = IncreasingArrays()([])
866
+ sage: elc = copy(el)
867
+ sage: el is elc
868
+ False
869
+ sage: bool(elc)
870
+ False
871
+ sage: elc.is_mutable()
872
+ True
873
+
874
+ We check that element with a ``__dict__`` are correctly copied::
875
+
876
+ sage: IL = IncreasingArrays()
877
+ sage: class myClass(IL.element_class): pass
878
+ sage: el = myClass(IL, [])
879
+ sage: el.toto = 2
880
+ sage: elc = copy(el)
881
+ sage: elc.toto
882
+ 2
883
+ """
884
+ cdef ClonableArray res
885
+ cdef type t = type(self)
886
+ res = t.__new__(t)
887
+ res._parent = self._parent
888
+ res._list = self._list[:]
889
+ if HAS_DICTIONARY(self):
890
+ res.__dict__ = self.__dict__.copy()
891
+ return res
892
+
893
+ cpdef check(self):
894
+ """
895
+ Check that ``self`` fulfill the invariants.
896
+
897
+ This is an abstract method. Subclasses are supposed to overload
898
+ ``check``.
899
+
900
+ EXAMPLES::
901
+
902
+ sage: from sage.structure.list_clone import ClonableArray
903
+ sage: ClonableArray(Parent(), [1,2,3]) # indirect doctest
904
+ Traceback (most recent call last):
905
+ ...
906
+ NotImplementedError: this should never be called, please overload the check method
907
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
908
+ sage: el = IncreasingArrays()([1,2,4]) # indirect doctest
909
+ """
910
+ raise NotImplementedError("this should never be called, please overload the check method")
911
+
912
+ cpdef long _hash_(self) except? -1:
913
+ """
914
+ Return the hash value of ``self``.
915
+
916
+ TESTS::
917
+
918
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
919
+ sage: el = IncreasingArrays()([1,2,3])
920
+ sage: el._hash_() # random
921
+ -309711137
922
+ sage: type(el._hash_()) == int
923
+ True
924
+ """
925
+ return hash(tuple(self._list))
926
+
927
+ def __reduce__(self):
928
+ """
929
+ TESTS::
930
+
931
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
932
+ sage: el = IncreasingArrays()([1,2,4])
933
+ sage: loads(dumps(el))
934
+ [1, 2, 4]
935
+ sage: t = el.__reduce__(); t
936
+ (<built-in function _make_array_clone>,
937
+ (<class 'sage.structure.list_clone_demo.IncreasingArray'>,
938
+ <sage.structure.list_clone_demo.IncreasingArrays_with_category object at ...>,
939
+ [1, 2, 4],
940
+ True,
941
+ True,
942
+ None))
943
+ sage: t[0](*t[1])
944
+ [1, 2, 4]
945
+ """
946
+ # Warning: don't pickle the hash value as it can change upon unpickling.
947
+ if HAS_DICTIONARY(self):
948
+ dic = self.__dict__
949
+ else:
950
+ dic = None
951
+ return (_make_array_clone,
952
+ (type(self), self._parent, self._list,
953
+ self._needs_check, self._is_immutable, dic))
954
+
955
+
956
+ ##### Needed for unpickling #####
957
+ def _make_array_clone(clas, parent, list, needs_check, is_immutable, dic):
958
+ """
959
+ Helpler to unpickle :class:`list_clone` instances.
960
+
961
+ TESTS::
962
+
963
+ sage: from sage.structure.list_clone import _make_array_clone
964
+ sage: from sage.structure.list_clone_demo import IncreasingArrays
965
+ sage: ILs = IncreasingArrays()
966
+ sage: el = _make_array_clone(ILs.element_class, ILs, [1,2,3], True, True, None)
967
+ sage: el
968
+ [1, 2, 3]
969
+ sage: el == ILs([1,2,3])
970
+ True
971
+
972
+ We check that element with a ``__dict__`` are correctly pickled::
973
+
974
+ sage: IL = IncreasingArrays()
975
+ sage: class myClass(IL.element_class): pass
976
+ sage: import __main__
977
+ sage: __main__.myClass = myClass
978
+ sage: el = myClass(IL, [])
979
+ sage: el.toto = 2
980
+ sage: elc = loads(dumps(el))
981
+ sage: elc.toto
982
+ 2
983
+ """
984
+ cdef ClonableArray res
985
+ res = <ClonableArray> clas.__new__(clas)
986
+ res._parent = parent
987
+ res._list = list
988
+ res._needs_check = needs_check
989
+ res._is_immutable = is_immutable
990
+ if dic is not None:
991
+ res.__dict__ = dic
992
+ return res
993
+
994
+
995
+ ############################################################################
996
+ ### Clonable (Resizable) Lists ###
997
+ ############################################################################
998
+ cdef class ClonableList(ClonableArray):
999
+ """
1000
+ List with clone protocol.
1001
+
1002
+ The class of objects which are
1003
+ :class:`Element<sage.structure.element.Element>` behave as lists and
1004
+ implement the clone protocol. See :class:`ClonableElement` for details
1005
+ about clone protocol.
1006
+
1007
+ .. SEEALSO:: :class:`~sage.structure.list_clone_demo.IncreasingList` for
1008
+ an example of usage.
1009
+ """
1010
+ cpdef append(self, el):
1011
+ """
1012
+ Appends ``el`` to ``self``.
1013
+
1014
+ INPUT:
1015
+
1016
+ - ``el`` -- any object
1017
+
1018
+ EXAMPLES::
1019
+
1020
+ sage: from sage.structure.list_clone_demo import IncreasingLists
1021
+ sage: el = IncreasingLists()([1])
1022
+ sage: el.append(3)
1023
+ Traceback (most recent call last):
1024
+ ...
1025
+ ValueError: object is immutable; please change a copy instead.
1026
+ sage: with el.clone() as elc:
1027
+ ....: elc.append(4)
1028
+ ....: elc.append(6)
1029
+ sage: elc
1030
+ [1, 4, 6]
1031
+ sage: with el.clone() as elc:
1032
+ ....: elc.append(4)
1033
+ ....: elc.append(2)
1034
+ Traceback (most recent call last):
1035
+ ...
1036
+ ValueError: array is not increasing
1037
+ """
1038
+ self._require_mutable()
1039
+ self._list.append(el)
1040
+
1041
+ cpdef extend(self, it):
1042
+ """
1043
+ Extend ``self`` by the content of the iterable ``it``.
1044
+
1045
+ INPUT:
1046
+
1047
+ - ``it`` -- any iterable
1048
+
1049
+ EXAMPLES::
1050
+
1051
+ sage: from sage.structure.list_clone_demo import IncreasingLists
1052
+ sage: el = IncreasingLists()([1, 4, 5, 8, 9])
1053
+ sage: el.extend((10,11))
1054
+ Traceback (most recent call last):
1055
+ ...
1056
+ ValueError: object is immutable; please change a copy instead.
1057
+
1058
+ sage: with el.clone() as elc:
1059
+ ....: elc.extend((10,11))
1060
+ sage: elc
1061
+ [1, 4, 5, 8, 9, 10, 11]
1062
+
1063
+ sage: el2 = IncreasingLists()([15, 16])
1064
+ sage: with el.clone() as elc:
1065
+ ....: elc.extend(el2)
1066
+ sage: elc
1067
+ [1, 4, 5, 8, 9, 15, 16]
1068
+
1069
+ sage: with el.clone() as elc:
1070
+ ....: elc.extend((6,7))
1071
+ Traceback (most recent call last):
1072
+ ...
1073
+ ValueError: array is not increasing
1074
+ """
1075
+ self._require_mutable()
1076
+ self._list.extend(it)
1077
+
1078
+ cpdef insert(self, int index, el):
1079
+ """
1080
+ Inserts ``el`` in ``self`` at position ``index``.
1081
+
1082
+ INPUT:
1083
+
1084
+ - ``el`` -- any object
1085
+ - ``index`` -- any int
1086
+
1087
+ EXAMPLES::
1088
+
1089
+ sage: from sage.structure.list_clone_demo import IncreasingLists
1090
+ sage: el = IncreasingLists()([1, 4, 5, 8, 9])
1091
+ sage: el.insert(3, 6)
1092
+ Traceback (most recent call last):
1093
+ ...
1094
+ ValueError: object is immutable; please change a copy instead.
1095
+ sage: with el.clone() as elc:
1096
+ ....: elc.insert(3, 6)
1097
+ sage: elc
1098
+ [1, 4, 5, 6, 8, 9]
1099
+ sage: with el.clone() as elc:
1100
+ ....: elc.insert(2, 6)
1101
+ Traceback (most recent call last):
1102
+ ...
1103
+ ValueError: array is not increasing
1104
+ """
1105
+ self._require_mutable()
1106
+ self._list.insert(index, el)
1107
+
1108
+ cpdef pop(self, int index=-1):
1109
+ """
1110
+ Remove ``self[index]`` from ``self`` and returns it.
1111
+
1112
+ INPUT:
1113
+
1114
+ - ``index`` -- integer (default: -1)
1115
+
1116
+ EXAMPLES::
1117
+
1118
+ sage: from sage.structure.list_clone_demo import IncreasingLists
1119
+ sage: el = IncreasingLists()([1, 4, 5, 8, 9])
1120
+ sage: el.pop()
1121
+ Traceback (most recent call last):
1122
+ ...
1123
+ ValueError: object is immutable; please change a copy instead.
1124
+ sage: with el.clone() as elc:
1125
+ ....: print(elc.pop())
1126
+ 9
1127
+ sage: elc
1128
+ [1, 4, 5, 8]
1129
+ sage: with el.clone() as elc:
1130
+ ....: print(elc.pop(2))
1131
+ 5
1132
+ sage: elc
1133
+ [1, 4, 8, 9]
1134
+ """
1135
+ self._require_mutable()
1136
+ return self._list.pop(index)
1137
+
1138
+ cpdef remove(self, el):
1139
+ """
1140
+ Remove the first occurrence of ``el`` from ``self``.
1141
+
1142
+ INPUT:
1143
+
1144
+ - ``el`` -- any object
1145
+
1146
+ EXAMPLES::
1147
+
1148
+ sage: from sage.structure.list_clone_demo import IncreasingLists
1149
+ sage: el = IncreasingLists()([1, 4, 5, 8, 9])
1150
+ sage: el.remove(4)
1151
+ Traceback (most recent call last):
1152
+ ...
1153
+ ValueError: object is immutable; please change a copy instead.
1154
+ sage: with el.clone() as elc:
1155
+ ....: elc.remove(4)
1156
+ sage: elc
1157
+ [1, 5, 8, 9]
1158
+ sage: with el.clone() as elc:
1159
+ ....: elc.remove(10)
1160
+ Traceback (most recent call last):
1161
+ ...
1162
+ ValueError: list.remove(x): x not in list
1163
+ """
1164
+ self._require_mutable()
1165
+ return self._list.remove(el)
1166
+
1167
+ def __setitem__(self, key, value):
1168
+ """
1169
+ Set the i-th element of ``self``.
1170
+
1171
+ An exception is raised if ``self`` is immutable.
1172
+
1173
+ EXAMPLES::
1174
+
1175
+ sage: from sage.structure.list_clone_demo import IncreasingLists
1176
+ sage: el = IncreasingLists()([1,2,4,10,15,17])
1177
+ sage: el[1] = 3
1178
+ Traceback (most recent call last):
1179
+ ...
1180
+ ValueError: object is immutable; please change a copy instead.
1181
+
1182
+ sage: with el.clone() as elc:
1183
+ ....: elc[3] = 7
1184
+ sage: elc
1185
+ [1, 2, 4, 7, 15, 17]
1186
+
1187
+ sage: with el.clone(check=False) as elc:
1188
+ ....: elc[1:3] = [3,5,6,8]
1189
+ sage: elc
1190
+ [1, 3, 5, 6, 8, 10, 15, 17]
1191
+ """
1192
+ self._require_mutable()
1193
+ self._list[key] = value
1194
+
1195
+ def __delitem__(self, key):
1196
+ """
1197
+ Remove the i-th element of ``self``.
1198
+
1199
+ An exception is raised if ``self`` is immutable.
1200
+
1201
+ EXAMPLES::
1202
+
1203
+ sage: from sage.structure.list_clone_demo import IncreasingLists
1204
+ sage: el = IncreasingLists()([1, 4, 5, 8, 9])
1205
+ sage: del el[3]
1206
+ Traceback (most recent call last):
1207
+ ...
1208
+ ValueError: object is immutable; please change a copy instead.
1209
+ sage: with el.clone() as elc:
1210
+ ....: del elc[3]
1211
+ sage: elc
1212
+ [1, 4, 5, 9]
1213
+ sage: with el.clone() as elc:
1214
+ ....: del elc[1:3]
1215
+ sage: elc
1216
+ [1, 8, 9]
1217
+ """
1218
+ self._require_mutable()
1219
+ del self._list[key]
1220
+
1221
+
1222
+ ############################################################################
1223
+ ### Clonable Arrays of int ##
1224
+ ############################################################################
1225
+ cdef class ClonableIntArray(ClonableElement):
1226
+ """
1227
+ Array of integers with clone protocol.
1228
+
1229
+ The class of objects which are
1230
+ :class:`Element<sage.structure.element.Element>` behave as list of int and
1231
+ implement the clone protocol. See :class:`ClonableElement` for details
1232
+ about clone protocol.
1233
+
1234
+
1235
+ INPUT:
1236
+
1237
+ - ``parent`` -- a :class:`Parent<sage.structure.parent.Parent>`
1238
+ - ``lst`` -- list
1239
+ - ``check`` -- boolean specifying if the invariant must be checked
1240
+ using method :meth:`check`
1241
+ - ``immutable`` -- boolean (default: ``True``); whether the created element
1242
+ is immutable
1243
+
1244
+ .. SEEALSO:: :class:`~sage.structure.list_clone_demo.IncreasingIntArray`
1245
+ for an example of usage.
1246
+ """
1247
+ def __cinit__(self):
1248
+ self._len = -1
1249
+ self._list = NULL
1250
+
1251
+ def __init__(self, Parent parent, lst, check=True, immutable=True):
1252
+ """
1253
+ Initialize ``self``.
1254
+
1255
+ TESTS::
1256
+
1257
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1258
+ sage: IncreasingIntArrays()([1,2,3])
1259
+ [1, 2, 3]
1260
+ sage: IncreasingIntArrays()((1,2,3))
1261
+ [1, 2, 3]
1262
+
1263
+ sage: IncreasingIntArrays()(None)
1264
+ Traceback (most recent call last):
1265
+ ...
1266
+ TypeError: object of type 'NoneType' has no len()
1267
+
1268
+ sage: el = IncreasingIntArrays()([3,2,1])
1269
+ Traceback (most recent call last):
1270
+ ...
1271
+ ValueError: array is not increasing
1272
+
1273
+ sage: el = IncreasingIntArrays()([1,2,4])
1274
+ sage: list(iter(el))
1275
+ [1, 2, 4]
1276
+ sage: list(iter(IncreasingIntArrays()([])))
1277
+ []
1278
+
1279
+ You are not supposed to do the following (giving a wrong list and
1280
+ desactivating checks)::
1281
+
1282
+ sage: broken = IncreasingIntArrays()([3,2,1], False)
1283
+ """
1284
+ cdef int i
1285
+ self._parent = parent
1286
+
1287
+ if self._list is not NULL:
1288
+ raise ValueError("resizing is forbidden")
1289
+ self._alloc_(len(lst))
1290
+ for i in range(self._len):
1291
+ self._list[i] = lst[i]
1292
+
1293
+ self._is_immutable = immutable
1294
+ if check:
1295
+ self.check()
1296
+
1297
+ cpdef _alloc_(self, int size):
1298
+ """
1299
+ Allocate the array part of ``self`` for a given size.
1300
+
1301
+ This can be used to initialize ``self`` without passing a list
1302
+
1303
+ INPUT:
1304
+
1305
+ - ``size`` -- integer
1306
+
1307
+ EXAMPLES::
1308
+
1309
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1310
+ sage: el = IncreasingIntArrays()([], check=False)
1311
+ sage: el._alloc_(3)
1312
+ sage: el._setitem(0, 1); el._setitem(1, 5); el._setitem(2, 8)
1313
+ sage: el
1314
+ [1, 5, 8]
1315
+ sage: copy(el)
1316
+ [1, 5, 8]
1317
+
1318
+ TESTS::
1319
+
1320
+ sage: el._alloc_(-1)
1321
+ Traceback (most recent call last):
1322
+ ...
1323
+ AssertionError: Negative size is forbidden
1324
+ """
1325
+ assert size >= 0, "Negative size is forbidden"
1326
+ self._is_immutable = False
1327
+ self._list = <int *>check_reallocarray(self._list, size, sizeof(int))
1328
+ self._len = size
1329
+
1330
+ def __dealloc__(self):
1331
+ sig_free(self._list)
1332
+ self._len = -1
1333
+ self._list = NULL
1334
+
1335
+ def _repr_(self):
1336
+ """
1337
+ TESTS::
1338
+
1339
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1340
+ sage: IncreasingIntArrays()([1,2,3])
1341
+ [1, 2, 3]
1342
+ """
1343
+ return '[' + ', '.join("%i" % self._list[i]
1344
+ for i in range(self._len)) + ']'
1345
+
1346
+ def __bool__(self):
1347
+ """
1348
+ EXAMPLES::
1349
+
1350
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1351
+ sage: bool(IncreasingIntArrays()([1,2,3]))
1352
+ True
1353
+ sage: bool(IncreasingIntArrays()([]))
1354
+ False
1355
+ """
1356
+ return self._len != 0
1357
+
1358
+ def __len__(self):
1359
+ """
1360
+ Return the len of ``self``.
1361
+
1362
+ EXAMPLES::
1363
+
1364
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1365
+ sage: len(IncreasingIntArrays()([1,2,3]))
1366
+ 3
1367
+ """
1368
+ return self._len
1369
+
1370
+ def __iter__(self):
1371
+ """
1372
+ Iterate over the items of ``self``.
1373
+
1374
+ EXAMPLES::
1375
+
1376
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1377
+ sage: I = IncreasingIntArrays()(range(5))
1378
+ sage: I == list(range(5))
1379
+ False
1380
+ sage: list(I) == list(range(5)) # indirect doctest
1381
+ True
1382
+ """
1383
+ return iter(self.list())
1384
+
1385
+ cpdef list list(self):
1386
+ """
1387
+ Convert ``self`` into a Python list.
1388
+
1389
+ EXAMPLES::
1390
+
1391
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1392
+ sage: I = IncreasingIntArrays()(range(5))
1393
+ sage: I == list(range(5))
1394
+ False
1395
+ sage: I.list() == list(range(5))
1396
+ True
1397
+ sage: I = IncreasingIntArrays()(range(1000))
1398
+ sage: I.list() == list(range(1000))
1399
+ True
1400
+ """
1401
+ cdef int i
1402
+ cdef list L = <list> PyList_New(self._len)
1403
+ cdef object o
1404
+ for i in range(self._len):
1405
+ o = PyLong_FromLong(self._list[i])
1406
+ Py_INCREF(o)
1407
+ PyList_SET_ITEM(L, i, o)
1408
+ return L
1409
+
1410
+ def __getitem__(self, key):
1411
+ """
1412
+ Return the i-th element of ``self``.
1413
+
1414
+ EXAMPLES::
1415
+
1416
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1417
+ sage: el = IncreasingIntArrays()([1,2,3])
1418
+ sage: el[1]
1419
+ 2
1420
+ sage: el[1:2]
1421
+ [2]
1422
+ sage: el[4]
1423
+ Traceback (most recent call last):
1424
+ ...
1425
+ IndexError: list index out of range
1426
+ sage: el[-1]
1427
+ 3
1428
+ sage: el[-1:]
1429
+ [3]
1430
+ sage: el[:]
1431
+ [1, 2, 3]
1432
+ sage: el[1:3]
1433
+ [2, 3]
1434
+ sage: type(el[:])
1435
+ <... 'list'>
1436
+ sage: list(el)
1437
+ [1, 2, 3]
1438
+ sage: it = iter(el); next(it), next(it)
1439
+ (1, 2)
1440
+ """
1441
+ cdef int start, stop, step, keyi
1442
+ cdef list res
1443
+ cdef slice keysl
1444
+ if isinstance(key, slice):
1445
+ keysl = <slice> key
1446
+ start, stop, step = keysl.indices(self._len)
1447
+ res = []
1448
+ for i in range(start, stop, step):
1449
+ res.append(self._getitem(i))
1450
+ return res
1451
+ keyi = <int> key
1452
+ if keyi < 0:
1453
+ keyi += self._len
1454
+ if 0 <= keyi < self._len:
1455
+ return self._list[keyi]
1456
+ else:
1457
+ raise IndexError("list index out of range")
1458
+
1459
+ def __setitem__(self, int key, value):
1460
+ """
1461
+ Set the i-th element of ``self``.
1462
+
1463
+ An exception is raised if ``self`` is immutable.
1464
+
1465
+ EXAMPLES::
1466
+
1467
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1468
+ sage: el = IncreasingIntArrays()([1,2,4])
1469
+ sage: elc = copy(el)
1470
+ sage: elc[1] = 3; elc
1471
+ [1, 3, 4]
1472
+ sage: el[1] = 3
1473
+ Traceback (most recent call last):
1474
+ ...
1475
+ ValueError: object is immutable; please change a copy instead.
1476
+ """
1477
+ if 0 <= key < self._len:
1478
+ self._require_mutable()
1479
+ self._list[key] = value
1480
+ else:
1481
+ raise IndexError("list index out of range")
1482
+
1483
+ cpdef object _getitem(self, int key):
1484
+ """
1485
+ Same as :meth:`__getitem__`.
1486
+
1487
+ This is much faster when used with Cython and the index is known to be
1488
+ an int.
1489
+
1490
+ EXAMPLES::
1491
+
1492
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1493
+ sage: IncreasingIntArrays()([1,2,3])._getitem(1)
1494
+ 2
1495
+ """
1496
+ if 0 <= key < self._len:
1497
+ return self._list[key]
1498
+ else:
1499
+ raise IndexError("list index out of range")
1500
+
1501
+ cpdef _setitem(self, int key, value):
1502
+ """
1503
+ Same as :meth:`__setitem__`.
1504
+
1505
+ This is much faster when used with Cython and the index is known to be
1506
+ an int.
1507
+
1508
+ EXAMPLES::
1509
+
1510
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1511
+ sage: el = IncreasingIntArrays()([1,2,4])
1512
+ sage: elc = copy(el)
1513
+ sage: elc._setitem(1, 3); elc
1514
+ [1, 3, 4]
1515
+ sage: el._setitem(1, 3)
1516
+ Traceback (most recent call last):
1517
+ ...
1518
+ ValueError: object is immutable; please change a copy instead.
1519
+ """
1520
+ if 0 <= key < self._len:
1521
+ self._require_mutable()
1522
+ self._list[key] = value
1523
+ else:
1524
+ raise IndexError("list index out of range")
1525
+
1526
+ def __contains__(self, int item):
1527
+ """
1528
+ EXAMPLES::
1529
+
1530
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1531
+ sage: c = IncreasingIntArrays()([1,2,4])
1532
+ sage: 1 in c
1533
+ True
1534
+ sage: 5 in c
1535
+ False
1536
+ """
1537
+ cdef int i
1538
+ for i in range(self._len):
1539
+ if item == self._list[i]:
1540
+ return True
1541
+ return False
1542
+
1543
+ cpdef int index(self, int item) except -1:
1544
+ """
1545
+ EXAMPLES::
1546
+
1547
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1548
+ sage: c = IncreasingIntArrays()([1,2,4])
1549
+ sage: c.index(1)
1550
+ 0
1551
+ sage: c.index(4)
1552
+ 2
1553
+ sage: c.index(5)
1554
+ Traceback (most recent call last):
1555
+ ...
1556
+ ValueError: list.index(x): x not in list
1557
+ """
1558
+ cdef int i
1559
+ for i in range(self._len):
1560
+ if item == self._list[i]:
1561
+ return i
1562
+ raise ValueError("list.index(x): x not in list")
1563
+
1564
+ # __hash__ is not properly inherited if comparison is changed
1565
+ # see <http://groups.google.com/group/cython-users/t/e89a9bd2ff20fd5a>
1566
+ def __hash__(self):
1567
+ """
1568
+ Return the hash value of ``self``.
1569
+
1570
+ TESTS::
1571
+
1572
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1573
+ sage: el = IncreasingIntArrays()([1,2,3])
1574
+ sage: hash(el) # random
1575
+ -309690657
1576
+ sage: el1 = copy(el); hash(el1)
1577
+ Traceback (most recent call last):
1578
+ ...
1579
+ ValueError: cannot hash a mutable object.
1580
+ """
1581
+ if self._hash == 0:
1582
+ if not self._is_immutable:
1583
+ raise ValueError("cannot hash a mutable object.")
1584
+ else:
1585
+ self._hash = self._hash_()
1586
+ return self._hash
1587
+
1588
+ # See protocol in comment in sage/structure/element.pyx
1589
+ cpdef _richcmp_(left, right, int op):
1590
+ """
1591
+ TESTS::
1592
+
1593
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1594
+ sage: el = IncreasingIntArrays()([1,2,4])
1595
+ sage: elc = copy(el)
1596
+ sage: elc == el # indirect doctest
1597
+ True
1598
+
1599
+ ::
1600
+
1601
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1602
+ sage: el1 = IncreasingIntArrays()([1,2,4])
1603
+ sage: el2 = IncreasingIntArrays()([1,2,3])
1604
+ sage: el1 == el1, el2 == el2, el1 == el2 # indirect doctest
1605
+ (True, True, False)
1606
+ sage: el1 <= el2, el1 >= el2, el2 <= el1 # indirect doctest
1607
+ (False, True, True)
1608
+ """
1609
+ cdef int i, minlen, reslen
1610
+ cdef ClonableIntArray rgt = <ClonableIntArray>right
1611
+ if left is right:
1612
+ return rich_to_bool(op, 0)
1613
+ if left._list is NULL:
1614
+ if rgt._list is NULL:
1615
+ return rich_to_bool(op, 0)
1616
+ else:
1617
+ return rich_to_bool(op, -1)
1618
+ elif rgt._list is NULL:
1619
+ return rich_to_bool(op, 1)
1620
+ if left._len < rgt._len:
1621
+ minlen = left._len
1622
+ reslen = -1
1623
+ elif left._len > rgt._len:
1624
+ minlen = rgt._len
1625
+ reslen = +1
1626
+ else:
1627
+ minlen = rgt._len
1628
+ reslen = 0
1629
+ for i in range(minlen):
1630
+ if left._list[i] != rgt._list[i]:
1631
+ if left._list[i] < rgt._list[i]:
1632
+ return rich_to_bool(op, -1)
1633
+ else:
1634
+ return rich_to_bool(op, 1)
1635
+ return rich_to_bool(op, reslen)
1636
+
1637
+ cpdef ClonableIntArray __copy__(self):
1638
+ """
1639
+ Return a copy of ``self``.
1640
+
1641
+ TESTS::
1642
+
1643
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1644
+ sage: el = IncreasingIntArrays()([1,2,4])
1645
+ sage: elc = copy(el)
1646
+ sage: el[:] == elc[:]
1647
+ True
1648
+ sage: el is elc
1649
+ False
1650
+
1651
+ We check that void lists are correctly copied::
1652
+
1653
+ sage: el = IncreasingIntArrays()([])
1654
+ sage: elc = copy(el)
1655
+ sage: el is elc
1656
+ False
1657
+ sage: bool(elc)
1658
+ True
1659
+ sage: elc.is_mutable()
1660
+ True
1661
+
1662
+ We check that element with a ``__dict__`` are correctly copied::
1663
+
1664
+ sage: IL = IncreasingIntArrays()
1665
+ sage: class myClass(IL.element_class): pass
1666
+ sage: el = myClass(IL, [])
1667
+ sage: el.toto = 2
1668
+ sage: elc = copy(el)
1669
+ sage: elc.toto
1670
+ 2
1671
+ """
1672
+ cdef ClonableIntArray res
1673
+ cdef type t = type(self)
1674
+ res = t.__new__(t)
1675
+ res._parent = self._parent
1676
+ if self:
1677
+ res._alloc_(self._len)
1678
+ for i in range(self._len):
1679
+ res._list[i] = self._list[i]
1680
+ if HAS_DICTIONARY(self):
1681
+ res.__dict__ = self.__dict__.copy()
1682
+ return res
1683
+
1684
+ cpdef check(self):
1685
+ """
1686
+ Check that ``self`` fulfill the invariants.
1687
+
1688
+ This is an abstract method. Subclasses are supposed to overload
1689
+ ``check``.
1690
+
1691
+ EXAMPLES::
1692
+
1693
+ sage: from sage.structure.list_clone import ClonableArray
1694
+ sage: ClonableArray(Parent(), [1,2,3]) # indirect doctest
1695
+ Traceback (most recent call last):
1696
+ ...
1697
+ NotImplementedError: this should never be called, please overload the check method
1698
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1699
+ sage: el = IncreasingIntArrays()([1,2,4]) # indirect doctest
1700
+ """
1701
+ raise NotImplementedError("this should never be called, please overload the check method")
1702
+
1703
+ cpdef long _hash_(self) except? -1:
1704
+ """
1705
+ Return the hash value of ``self``.
1706
+
1707
+ TESTS::
1708
+
1709
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1710
+ sage: el = IncreasingIntArrays()([1,2,3])
1711
+ sage: el._hash_() # random
1712
+ -309711137
1713
+ sage: type(el._hash_()) == int
1714
+ True
1715
+ """
1716
+ cdef long hv
1717
+ if self._list == NULL:
1718
+ hv = hash(None)
1719
+ else:
1720
+ hv = hash(tuple(self))
1721
+ return hv
1722
+
1723
+ def __reduce__(self):
1724
+ """
1725
+ TESTS::
1726
+
1727
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1728
+ sage: el = IncreasingIntArrays()([1,2,4])
1729
+ sage: loads(dumps(el))
1730
+ [1, 2, 4]
1731
+ sage: t = el.__reduce__(); t
1732
+ (<built-in function _make_int_array_clone>,
1733
+ (<class 'sage.structure.list_clone_demo.IncreasingIntArray'>,
1734
+ <sage.structure.list_clone_demo.IncreasingIntArrays_with_category object at ...>,
1735
+ [1, 2, 4],
1736
+ True,
1737
+ True,
1738
+ None))
1739
+ sage: t[0](*t[1])
1740
+ [1, 2, 4]
1741
+ """
1742
+ # Warning: don't pickle the hash value as it can change upon unpickling.
1743
+ if HAS_DICTIONARY(self):
1744
+ dic = self.__dict__
1745
+ else:
1746
+ dic = None
1747
+ return (_make_int_array_clone,
1748
+ (type(self), self._parent, self[:],
1749
+ self._needs_check, self._is_immutable, dic))
1750
+
1751
+
1752
+ ##### Needed for unpickling #####
1753
+ def _make_int_array_clone(clas, parent, lst, needs_check, is_immutable, dic):
1754
+ """
1755
+ Helpler to unpickle :class:`list_clone` instances.
1756
+
1757
+ TESTS::
1758
+
1759
+ sage: from sage.structure.list_clone import _make_int_array_clone
1760
+ sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1761
+ sage: ILs = IncreasingIntArrays()
1762
+ sage: el = _make_int_array_clone(ILs.element_class, ILs, [1,2,3], True, True, None)
1763
+ sage: el
1764
+ [1, 2, 3]
1765
+ sage: el == ILs([1,2,3])
1766
+ True
1767
+
1768
+ We check that element with a ``__dict__`` are correctly pickled::
1769
+
1770
+ sage: IL = IncreasingIntArrays()
1771
+ sage: class myClass(IL.element_class): pass
1772
+ sage: import __main__
1773
+ sage: __main__.myClass = myClass
1774
+ sage: el = myClass(IL, [])
1775
+ sage: el.toto = 2
1776
+ sage: elc = loads(dumps(el))
1777
+ sage: elc.toto
1778
+ 2
1779
+ """
1780
+ cdef ClonableIntArray res
1781
+ res = <ClonableIntArray> clas.__new__(clas)
1782
+ ClonableIntArray.__init__(res, parent, lst, needs_check, is_immutable)
1783
+ if dic is not None:
1784
+ res.__dict__ = dic
1785
+ return res
1786
+
1787
+
1788
+ cdef class NormalizedClonableList(ClonableList):
1789
+ """
1790
+ List with clone protocol and normal form.
1791
+
1792
+ This is a subclass of :class:`ClonableList` which call a method
1793
+ :meth:`normalize` at creation and after any modification of its instance.
1794
+
1795
+ .. SEEALSO:: :class:`~sage.structure.list_clone_demo.SortedList` for an
1796
+ example of usage.
1797
+
1798
+ EXAMPLES:
1799
+
1800
+ We construct a sorted list through its parent::
1801
+
1802
+ sage: from sage.structure.list_clone_demo import SortedLists
1803
+ sage: SL = SortedLists()
1804
+ sage: sl1 = SL([4,2,6,1]); sl1
1805
+ [1, 2, 4, 6]
1806
+
1807
+ Normalization is also performed atfer modification::
1808
+
1809
+ sage: with sl1.clone() as sl2:
1810
+ ....: sl2[1] = 12
1811
+ sage: sl2
1812
+ [1, 4, 6, 12]
1813
+ """
1814
+ def __init__(self, Parent parent, lst, check=True, immutable=True):
1815
+ r"""
1816
+ TESTS::
1817
+
1818
+ sage: from sage.structure.list_clone_demo import SortedList, SortedLists
1819
+ sage: SortedList(SortedLists(), [2,3,1])
1820
+ [1, 2, 3]
1821
+ """
1822
+ ClonableList.__init__(self, parent, lst, False, False)
1823
+ self.normalize()
1824
+ self._is_immutable = immutable
1825
+ if check:
1826
+ self.check()
1827
+
1828
+ def __exit__(self, typ, value, tracback):
1829
+ r"""
1830
+ TESTS::
1831
+
1832
+ sage: from sage.structure.list_clone_demo import SortedList, SortedLists
1833
+ sage: l = SortedList(SortedLists(), [2,3,1], immutable=False); l
1834
+ [1, 2, 3]
1835
+ sage: l[1] = 5; l
1836
+ [1, 5, 3]
1837
+ sage: l.__exit__(None, None, None)
1838
+ False
1839
+ sage: l
1840
+ [1, 3, 5]
1841
+ """
1842
+ self.normalize()
1843
+ return ClonableList.__exit__(self, typ, value, tracback)
1844
+
1845
+ cpdef normalize(self):
1846
+ """
1847
+ Normalize ``self``.
1848
+
1849
+ This is an abstract method. Subclasses are supposed to overload
1850
+ :meth:`normalize`. The call ``self.normalize()`` is supposed to
1851
+
1852
+ - call ``self._require_mutable()`` to check that ``self`` is in a
1853
+ proper mutable state
1854
+ - modify ``self`` to put it in a normal form
1855
+
1856
+ EXAMPLES::
1857
+
1858
+ sage: from sage.structure.list_clone_demo import SortedList, SortedLists
1859
+ sage: l = SortedList(SortedLists(), [2,3,2], False, False)
1860
+ sage: l
1861
+ [2, 2, 3]
1862
+ sage: l.check()
1863
+ Traceback (most recent call last):
1864
+ ...
1865
+ ValueError: list is not strictly increasing
1866
+ """
1867
+ raise NotImplementedError("This should never be called, please overload the normalize method")