passagemath-objects 10.6.47__cp311-cp311-macosx_13_0_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_objects/.dylibs/libgmp.10.dylib +0 -0
- passagemath_objects/__init__.py +3 -0
- passagemath_objects-10.6.47.dist-info/METADATA +115 -0
- passagemath_objects-10.6.47.dist-info/RECORD +280 -0
- passagemath_objects-10.6.47.dist-info/WHEEL +6 -0
- passagemath_objects-10.6.47.dist-info/top_level.txt +3 -0
- sage/all__sagemath_objects.py +37 -0
- sage/arith/all__sagemath_objects.py +5 -0
- sage/arith/long.pxd +411 -0
- sage/arith/numerical_approx.cpython-311-darwin.so +0 -0
- sage/arith/numerical_approx.pxd +35 -0
- sage/arith/numerical_approx.pyx +75 -0
- sage/arith/power.cpython-311-darwin.so +0 -0
- sage/arith/power.pxd +31 -0
- sage/arith/power.pyx +127 -0
- sage/categories/action.cpython-311-darwin.so +0 -0
- sage/categories/action.pxd +29 -0
- sage/categories/action.pyx +641 -0
- sage/categories/algebra_functor.py +745 -0
- sage/categories/all__sagemath_objects.py +33 -0
- sage/categories/basic.py +62 -0
- sage/categories/cartesian_product.py +295 -0
- sage/categories/category.py +3401 -0
- sage/categories/category_cy_helper.cpython-311-darwin.so +0 -0
- sage/categories/category_cy_helper.pxd +8 -0
- sage/categories/category_cy_helper.pyx +322 -0
- sage/categories/category_singleton.cpython-311-darwin.so +0 -0
- sage/categories/category_singleton.pxd +3 -0
- sage/categories/category_singleton.pyx +342 -0
- sage/categories/category_types.py +637 -0
- sage/categories/category_with_axiom.py +2876 -0
- sage/categories/covariant_functorial_construction.py +703 -0
- sage/categories/facade_sets.py +228 -0
- sage/categories/functor.cpython-311-darwin.so +0 -0
- sage/categories/functor.pxd +7 -0
- sage/categories/functor.pyx +691 -0
- sage/categories/homset.py +1338 -0
- sage/categories/homsets.py +364 -0
- sage/categories/isomorphic_objects.py +73 -0
- sage/categories/map.cpython-311-darwin.so +0 -0
- sage/categories/map.pxd +34 -0
- sage/categories/map.pyx +2106 -0
- sage/categories/morphism.cpython-311-darwin.so +0 -0
- sage/categories/morphism.pxd +14 -0
- sage/categories/morphism.pyx +895 -0
- sage/categories/objects.py +167 -0
- sage/categories/primer.py +1696 -0
- sage/categories/pushout.py +4834 -0
- sage/categories/quotients.py +64 -0
- sage/categories/realizations.py +200 -0
- sage/categories/sets_cat.py +3290 -0
- sage/categories/sets_with_partial_maps.py +52 -0
- sage/categories/subobjects.py +64 -0
- sage/categories/subquotients.py +21 -0
- sage/categories/with_realizations.py +311 -0
- sage/cpython/__init__.py +19 -0
- sage/cpython/_py2_random.py +619 -0
- sage/cpython/all.py +3 -0
- sage/cpython/atexit.cpython-311-darwin.so +0 -0
- sage/cpython/atexit.pyx +269 -0
- sage/cpython/builtin_types.cpython-311-darwin.so +0 -0
- sage/cpython/builtin_types.pyx +7 -0
- sage/cpython/cython_metaclass.cpython-311-darwin.so +0 -0
- sage/cpython/cython_metaclass.h +117 -0
- sage/cpython/cython_metaclass.pxd +3 -0
- sage/cpython/cython_metaclass.pyx +130 -0
- sage/cpython/debug.cpython-311-darwin.so +0 -0
- sage/cpython/debug.pyx +302 -0
- sage/cpython/dict_del_by_value.cpython-311-darwin.so +0 -0
- sage/cpython/dict_del_by_value.pxd +9 -0
- sage/cpython/dict_del_by_value.pyx +191 -0
- sage/cpython/dict_internal.h +245 -0
- sage/cpython/getattr.cpython-311-darwin.so +0 -0
- sage/cpython/getattr.pxd +9 -0
- sage/cpython/getattr.pyx +439 -0
- sage/cpython/pycore_long.h +97 -0
- sage/cpython/pycore_long.pxd +10 -0
- sage/cpython/python_debug.h +44 -0
- sage/cpython/python_debug.pxd +47 -0
- sage/cpython/pyx_visit.h +13 -0
- sage/cpython/string.cpython-311-darwin.so +0 -0
- sage/cpython/string.pxd +76 -0
- sage/cpython/string.pyx +34 -0
- sage/cpython/string_impl.h +60 -0
- sage/cpython/type.cpython-311-darwin.so +0 -0
- sage/cpython/type.pxd +2 -0
- sage/cpython/type.pyx +40 -0
- sage/cpython/wrapperdescr.pxd +67 -0
- sage/ext/all__sagemath_objects.py +3 -0
- sage/ext/ccobject.h +64 -0
- sage/ext/cplusplus.pxd +17 -0
- sage/ext/mod_int.h +30 -0
- sage/ext/mod_int.pxd +24 -0
- sage/ext/stdsage.pxd +39 -0
- sage/groups/all__sagemath_objects.py +1 -0
- sage/groups/group.cpython-311-darwin.so +0 -0
- sage/groups/group.pxd +14 -0
- sage/groups/group.pyx +322 -0
- sage/groups/old.cpython-311-darwin.so +0 -0
- sage/groups/old.pxd +14 -0
- sage/groups/old.pyx +219 -0
- sage/libs/all__sagemath_objects.py +3 -0
- sage/libs/gmp/__init__.py +1 -0
- sage/libs/gmp/all.pxd +6 -0
- sage/libs/gmp/binop.pxd +23 -0
- sage/libs/gmp/misc.pxd +8 -0
- sage/libs/gmp/mpf.pxd +88 -0
- sage/libs/gmp/mpn.pxd +57 -0
- sage/libs/gmp/mpq.pxd +57 -0
- sage/libs/gmp/mpz.pxd +202 -0
- sage/libs/gmp/pylong.cpython-311-darwin.so +0 -0
- sage/libs/gmp/pylong.pxd +12 -0
- sage/libs/gmp/pylong.pyx +150 -0
- sage/libs/gmp/random.pxd +25 -0
- sage/libs/gmp/randomize.pxd +59 -0
- sage/libs/gmp/types.pxd +53 -0
- sage/libs/gmpxx.pxd +19 -0
- sage/misc/abstract_method.py +276 -0
- sage/misc/all__sagemath_objects.py +43 -0
- sage/misc/bindable_class.py +253 -0
- sage/misc/c3_controlled.cpython-311-darwin.so +0 -0
- sage/misc/c3_controlled.pxd +2 -0
- sage/misc/c3_controlled.pyx +1402 -0
- sage/misc/cachefunc.cpython-311-darwin.so +0 -0
- sage/misc/cachefunc.pxd +43 -0
- sage/misc/cachefunc.pyx +3781 -0
- sage/misc/call.py +188 -0
- sage/misc/classcall_metaclass.cpython-311-darwin.so +0 -0
- sage/misc/classcall_metaclass.pxd +14 -0
- sage/misc/classcall_metaclass.pyx +599 -0
- sage/misc/constant_function.cpython-311-darwin.so +0 -0
- sage/misc/constant_function.pyx +130 -0
- sage/misc/decorators.py +747 -0
- sage/misc/fast_methods.cpython-311-darwin.so +0 -0
- sage/misc/fast_methods.pxd +20 -0
- sage/misc/fast_methods.pyx +351 -0
- sage/misc/flatten.py +90 -0
- sage/misc/fpickle.cpython-311-darwin.so +0 -0
- sage/misc/fpickle.pyx +177 -0
- sage/misc/function_mangling.cpython-311-darwin.so +0 -0
- sage/misc/function_mangling.pxd +11 -0
- sage/misc/function_mangling.pyx +308 -0
- sage/misc/inherit_comparison.cpython-311-darwin.so +0 -0
- sage/misc/inherit_comparison.pxd +5 -0
- sage/misc/inherit_comparison.pyx +105 -0
- sage/misc/instancedoc.cpython-311-darwin.so +0 -0
- sage/misc/instancedoc.pyx +331 -0
- sage/misc/lazy_attribute.cpython-311-darwin.so +0 -0
- sage/misc/lazy_attribute.pyx +607 -0
- sage/misc/lazy_format.py +135 -0
- sage/misc/lazy_import.cpython-311-darwin.so +0 -0
- sage/misc/lazy_import.pyx +1299 -0
- sage/misc/lazy_import_cache.py +36 -0
- sage/misc/lazy_list.cpython-311-darwin.so +0 -0
- sage/misc/lazy_list.pxd +19 -0
- sage/misc/lazy_list.pyx +1187 -0
- sage/misc/lazy_string.cpython-311-darwin.so +0 -0
- sage/misc/lazy_string.pxd +7 -0
- sage/misc/lazy_string.pyx +546 -0
- sage/misc/misc.py +1066 -0
- sage/misc/misc_c.cpython-311-darwin.so +0 -0
- sage/misc/misc_c.pxd +3 -0
- sage/misc/misc_c.pyx +766 -0
- sage/misc/namespace_package.py +37 -0
- sage/misc/nested_class.cpython-311-darwin.so +0 -0
- sage/misc/nested_class.pxd +3 -0
- sage/misc/nested_class.pyx +394 -0
- sage/misc/persist.cpython-311-darwin.so +0 -0
- sage/misc/persist.pyx +1251 -0
- sage/misc/prandom.py +418 -0
- sage/misc/randstate.cpython-311-darwin.so +0 -0
- sage/misc/randstate.pxd +30 -0
- sage/misc/randstate.pyx +1059 -0
- sage/misc/repr.py +203 -0
- sage/misc/reset.cpython-311-darwin.so +0 -0
- sage/misc/reset.pyx +196 -0
- sage/misc/sage_ostools.cpython-311-darwin.so +0 -0
- sage/misc/sage_ostools.pyx +323 -0
- sage/misc/sage_timeit.py +275 -0
- sage/misc/sage_timeit_class.cpython-311-darwin.so +0 -0
- sage/misc/sage_timeit_class.pyx +120 -0
- sage/misc/sage_unittest.py +637 -0
- sage/misc/sageinspect.py +2768 -0
- sage/misc/session.cpython-311-darwin.so +0 -0
- sage/misc/session.pyx +392 -0
- sage/misc/superseded.py +557 -0
- sage/misc/test_nested_class.py +228 -0
- sage/misc/timing.py +264 -0
- sage/misc/unknown.py +222 -0
- sage/misc/verbose.py +253 -0
- sage/misc/weak_dict.cpython-311-darwin.so +0 -0
- sage/misc/weak_dict.pxd +15 -0
- sage/misc/weak_dict.pyx +1231 -0
- sage/modules/all__sagemath_objects.py +1 -0
- sage/modules/module.cpython-311-darwin.so +0 -0
- sage/modules/module.pxd +5 -0
- sage/modules/module.pyx +329 -0
- sage/rings/all__sagemath_objects.py +3 -0
- sage/rings/integer_fake.h +22 -0
- sage/rings/integer_fake.pxd +55 -0
- sage/sets/all__sagemath_objects.py +3 -0
- sage/sets/pythonclass.cpython-311-darwin.so +0 -0
- sage/sets/pythonclass.pxd +9 -0
- sage/sets/pythonclass.pyx +247 -0
- sage/structure/__init__.py +4 -0
- sage/structure/all.py +30 -0
- sage/structure/category_object.cpython-311-darwin.so +0 -0
- sage/structure/category_object.pxd +28 -0
- sage/structure/category_object.pyx +1087 -0
- sage/structure/coerce.cpython-311-darwin.so +0 -0
- sage/structure/coerce.pxd +44 -0
- sage/structure/coerce.pyx +2107 -0
- sage/structure/coerce_actions.cpython-311-darwin.so +0 -0
- sage/structure/coerce_actions.pxd +27 -0
- sage/structure/coerce_actions.pyx +988 -0
- sage/structure/coerce_dict.cpython-311-darwin.so +0 -0
- sage/structure/coerce_dict.pxd +51 -0
- sage/structure/coerce_dict.pyx +1557 -0
- sage/structure/coerce_exceptions.py +23 -0
- sage/structure/coerce_maps.cpython-311-darwin.so +0 -0
- sage/structure/coerce_maps.pxd +28 -0
- sage/structure/coerce_maps.pyx +718 -0
- sage/structure/debug_options.cpython-311-darwin.so +0 -0
- sage/structure/debug_options.pxd +6 -0
- sage/structure/debug_options.pyx +54 -0
- sage/structure/dynamic_class.py +541 -0
- sage/structure/element.cpython-311-darwin.so +0 -0
- sage/structure/element.pxd +272 -0
- sage/structure/element.pyx +4772 -0
- sage/structure/element_wrapper.cpython-311-darwin.so +0 -0
- sage/structure/element_wrapper.pxd +12 -0
- sage/structure/element_wrapper.pyx +582 -0
- sage/structure/factorization.py +1422 -0
- sage/structure/factorization_integer.py +105 -0
- sage/structure/factory.cpython-311-darwin.so +0 -0
- sage/structure/factory.pyx +786 -0
- sage/structure/formal_sum.py +489 -0
- sage/structure/gens_py.py +73 -0
- sage/structure/global_options.py +1743 -0
- sage/structure/indexed_generators.py +863 -0
- sage/structure/list_clone.cpython-311-darwin.so +0 -0
- sage/structure/list_clone.pxd +65 -0
- sage/structure/list_clone.pyx +1867 -0
- sage/structure/list_clone_demo.cpython-311-darwin.so +0 -0
- sage/structure/list_clone_demo.pyx +248 -0
- sage/structure/list_clone_timings.py +179 -0
- sage/structure/list_clone_timings_cy.cpython-311-darwin.so +0 -0
- sage/structure/list_clone_timings_cy.pyx +86 -0
- sage/structure/mutability.cpython-311-darwin.so +0 -0
- sage/structure/mutability.pxd +21 -0
- sage/structure/mutability.pyx +348 -0
- sage/structure/nonexact.py +69 -0
- sage/structure/parent.cpython-311-darwin.so +0 -0
- sage/structure/parent.pxd +112 -0
- sage/structure/parent.pyx +3093 -0
- sage/structure/parent_base.cpython-311-darwin.so +0 -0
- sage/structure/parent_base.pxd +13 -0
- sage/structure/parent_base.pyx +44 -0
- sage/structure/parent_gens.cpython-311-darwin.so +0 -0
- sage/structure/parent_gens.pxd +22 -0
- sage/structure/parent_gens.pyx +377 -0
- sage/structure/parent_old.cpython-311-darwin.so +0 -0
- sage/structure/parent_old.pxd +25 -0
- sage/structure/parent_old.pyx +294 -0
- sage/structure/proof/__init__.py +1 -0
- sage/structure/proof/all.py +243 -0
- sage/structure/proof/proof.py +300 -0
- sage/structure/richcmp.cpython-311-darwin.so +0 -0
- sage/structure/richcmp.pxd +213 -0
- sage/structure/richcmp.pyx +495 -0
- sage/structure/sage_object.cpython-311-darwin.so +0 -0
- sage/structure/sage_object.pxd +3 -0
- sage/structure/sage_object.pyx +988 -0
- sage/structure/sage_object_test.py +19 -0
- sage/structure/sequence.py +937 -0
- sage/structure/set_factories.py +1178 -0
- sage/structure/set_factories_example.py +527 -0
- sage/structure/support_view.py +179 -0
- sage/structure/test_factory.py +56 -0
- sage/structure/unique_representation.py +1359 -0
|
@@ -0,0 +1,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")
|