Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/structure/list_clone.pyx
8814 views
1
r"""
2
Elements, Array and Lists With Clone Protocol
3
4
This module defines several classes which are subclasses of
5
:class:`Element<sage.structure.element.Element>` and which roughly implement
6
the "prototype" design pattern (see [Pro]_, [GOF]_). Those classes are
7
intended to be used to model *mathematical* objects, which are by essence
8
immutable. However, in many occasions, one wants to construct the
9
data-structure encoding of a new mathematical object by small modifications of
10
the data structure encoding some already built object. For the resulting
11
data-structure to correctly encode the mathematical object, some structural
12
invariants must hold. One problem is that, in many cases, during the
13
modification process, there is no possibility but to break the invariants.
14
15
For example, in a list modeling a permutation of `\{1,\dots,n\}`, the integers
16
must be distinct. A very common operation is to take a permutation to make a
17
copy with some small modifications, like exchanging two consecutive values in
18
the list or cycling some values. Though the result is clearly a permutations
19
there's no way to avoid breaking the permutations invariants at some point
20
during the modifications.
21
22
The main purpose of this module is to define the class
23
24
- :class:`ClonableElement` as an abstract super class,
25
26
and its subclasses:
27
28
- :class:`ClonableArray` for arrays (lists of fixed length) of objects;
29
- :class:`ClonableList` for (resizable) lists of objects;
30
- :class:`NormalizedClonableList` for lists of objects with a normalization method;
31
- :class:`ClonableIntArray` for arrays of int.
32
33
.. seealso:: The following parents from :mod:`sage.structure.list_clone_demo`
34
demonstrate how to use them:
35
36
- ``IncreasingArrays()`` (see
37
:class:`~sage.structure.list_clone_demo.IncreasingArray`
38
and the parent class
39
:class:`~sage.structure.list_clone_demo.IncreasingArrays`)
40
- ``IncreasingLists()`` (see
41
:class:`~sage.structure.list_clone_demo.IncreasingList`
42
and the parent class
43
:class:`~sage.structure.list_clone_demo.IncreasingLists`)
44
- ``SortedLists()`` (see
45
:class:`~sage.structure.list_clone_demo.SortedList`
46
and the parent class
47
:class:`~sage.structure.list_clone_demo.SortedLists`)
48
- ``IncreasingIntArrays()`` (see
49
:class:`~sage.structure.list_clone_demo.IncreasingIntArray`
50
and the parent class
51
:class:`~sage.structure.list_clone_demo.IncreasingIntArrays`)
52
53
EXAMPLES:
54
55
We now demonstrate how
56
:class:`~sage.structure.list_clone_demo.IncreasingArray` works, creating an
57
instance ``el`` through its parent ``IncreasingArrays()``::
58
59
sage: from sage.structure.list_clone_demo import IncreasingArrays
60
sage: P = IncreasingArrays()
61
sage: P([1, 4 ,8])
62
[1, 4, 8]
63
64
If one tries to create this way a list which in not increasing, an error is
65
raised::
66
67
sage: IncreasingArrays()([5, 4 ,8])
68
Traceback (most recent call last):
69
...
70
ValueError: array is not increasing
71
72
Once created modifying ``el`` is forbidden::
73
74
sage: el = P([1, 4 ,8])
75
sage: el[1] = 3
76
Traceback (most recent call last):
77
...
78
ValueError: object is immutable; please change a copy instead.
79
80
However, you can modify a temporarily mutable clone::
81
82
sage: with el.clone() as elc:
83
....: elc[1] = 3
84
sage: [el, elc]
85
[[1, 4, 8], [1, 3, 8]]
86
87
We check that the original and the modified copy now are in a proper immutable
88
state::
89
90
sage: el.is_immutable(), elc.is_immutable()
91
(True, True)
92
sage: elc[1] = 5
93
Traceback (most recent call last):
94
...
95
ValueError: object is immutable; please change a copy instead.
96
97
You can break the property that the list is increasing during the
98
modification::
99
100
sage: with el.clone() as elc2:
101
....: elc2[1] = 12
102
....: print elc2
103
....: elc2[2] = 25
104
[1, 12, 8]
105
sage: elc2
106
[1, 12, 25]
107
108
But this property must be restored at the end of the ``with`` block; otherwise
109
an error is raised::
110
111
sage: with elc2.clone() as el3:
112
....: el3[1] = 100
113
Traceback (most recent call last):
114
...
115
ValueError: array is not increasing
116
117
Finally, as an alternative to the ``with`` syntax one can use::
118
119
sage: el4 = copy(elc2)
120
sage: el4[1] = 10
121
sage: el4.set_immutable()
122
sage: el4.check()
123
124
REFERENCES:
125
126
.. [Pro] Prototype pattern
127
http://en.wikipedia.org/wiki/Prototype_pattern
128
129
.. [GOF] Design Patterns: Elements of Reusable Object-Oriented
130
Software. E. Gamma; R. Helm; R. Johnson; J. Vlissides (1994).
131
Addison-Wesley. ISBN 0-201-63361-2.
132
133
AUTHORS:
134
135
- Florent Hivert (2010-03): initial revision
136
"""
137
#*****************************************************************************
138
# Copyright (C) 2009-2010 Florent Hivert <[email protected]>
139
#
140
# Distributed under the terms of the GNU General Public License (GPL)
141
# http://www.gnu.org/licenses/
142
#*****************************************************************************
143
144
145
include "sage/ext/stdsage.pxi"
146
from cpython.list cimport *
147
from cpython.int cimport *
148
from cpython.ref cimport *
149
150
import sage
151
from sage.structure.element cimport Element
152
from sage.structure.element import Element
153
from sage.structure.parent cimport Parent
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 [Pro]_, [GOF]_). 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 satisfies 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):
295
"""
296
Check that ``self`` is mutable.
297
298
Raise a ``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):
313
"""
314
Returns ``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):
334
"""
335
Returns ``True`` if ``self`` is immutable (can not 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
Returns a clone that is mutable copy of ``self``.
422
423
INPUT:
424
425
- ``check`` -- a 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`` -- a list
503
- ``check`` -- a boolean specifying if the invariant must be checked
504
using method :meth:`check`.
505
- ``immutable`` -- a boolean telling wether the created element is
506
immutable (defaults to ``True``)
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 __nonzero__(self):
569
"""
570
Tests if self is not empty.
571
572
EXAMPLES::
573
574
sage: from sage.structure.list_clone_demo import IncreasingArrays
575
sage: IncreasingArrays()([1,2,3]).__nonzero__()
576
True
577
sage: IncreasingArrays()([]).__nonzero__()
578
False
579
"""
580
return bool(self._list)
581
582
cpdef list _get_list(self):
583
"""
584
Returns 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
Returns 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
Returns 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
<type 'list'>
650
"""
651
if PY_TYPE_CHECK(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
Returns 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 self._list.__iter__()
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 self._list.__contains__(item)
761
762
cpdef int index(self, x, start=None, stop=None):
763
"""
764
Returns 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: 5 is 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):
787
"""
788
Returns 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
# __hash__ is not properly inherited if comparison is changed
804
# see <http://groups.google.com/group/cython-users/t/e89a9bd2ff20fd5a>
805
def __hash__(self):
806
"""
807
Returns the hash value of ``self``.
808
809
TESTS::
810
811
sage: from sage.structure.list_clone_demo import IncreasingArrays
812
sage: el = IncreasingArrays()([1,2,3])
813
sage: hash(el) # random
814
-309690657
815
sage: el1 = copy(el); hash(el1)
816
Traceback (most recent call last):
817
...
818
ValueError: cannot hash a mutable object.
819
"""
820
if self._hash == 0:
821
if not self._is_immutable:
822
raise ValueError, "cannot hash a mutable object."
823
else:
824
self._hash = self._hash_()
825
return self._hash
826
827
def __richcmp__(left, right, int op):
828
"""
829
TESTS::
830
831
sage: from sage.structure.list_clone_demo import IncreasingArrays
832
sage: el = IncreasingArrays()([1,2,4])
833
sage: elc = copy(el)
834
sage: elc == el # indirect doctest
835
True
836
"""
837
return (<Element>left)._richcmp(right, op)
838
839
# See protocol in comment in sage/structure/element.pyx
840
cdef int _cmp_c_impl(left, Element right) except -2:
841
"""
842
TEST::
843
844
sage: from sage.structure.list_clone_demo import IncreasingArrays
845
sage: el1 = IncreasingArrays()([1,2,4])
846
sage: el2 = IncreasingArrays()([1,2,3])
847
sage: el1 == el1, el2 == el2, el1 == el2 # indirect doctest
848
(True, True, False)
849
sage: el1 <= el2, el1 >= el2, el2 <= el1 # indirect doctest
850
(False, True, True)
851
"""
852
cdef ClonableArray rgt = <ClonableArray>right
853
return cmp(left._list, rgt._list)
854
855
cpdef ClonableArray __copy__(self):
856
"""
857
Returns a copy of ``self``
858
859
TESTS::
860
861
sage: from sage.structure.list_clone_demo import IncreasingArrays
862
sage: el = IncreasingArrays()([1,2,4])
863
sage: elc = copy(el)
864
sage: el[:] == elc[:]
865
True
866
sage: el is elc
867
False
868
869
We check that empty lists are correctly copied::
870
871
sage: el = IncreasingArrays()([])
872
sage: elc = copy(el)
873
sage: el is elc
874
False
875
sage: elc.__nonzero__()
876
False
877
sage: elc.is_mutable()
878
True
879
880
We check that element with a ``__dict__`` are correctly copied::
881
882
sage: IL = IncreasingArrays()
883
sage: class myClass(IL.element_class): pass
884
sage: el = myClass(IL, [])
885
sage: el.toto = 2
886
sage: elc = copy(el)
887
sage: elc.toto
888
2
889
"""
890
cdef ClonableArray res
891
#res = type(self).__new__(type(self), self._parent)
892
res = PY_NEW_SAME_TYPE(self)
893
res._parent = self._parent
894
res._list = self._list[:]
895
if HAS_DICTIONARY(self):
896
res.__dict__ = self.__dict__.copy()
897
return res
898
899
cpdef check(self):
900
"""
901
Check that ``self`` fulfill the invariants
902
903
This is an abstract method. Subclasses are supposed to overload
904
``check``.
905
906
EXAMPLES::
907
908
sage: from sage.structure.list_clone import ClonableArray
909
sage: ClonableArray(Parent(), [1,2,3]) # indirect doctest
910
Traceback (most recent call last):
911
...
912
AssertionError: This should never be called, please overload the check method
913
sage: from sage.structure.list_clone_demo import IncreasingArrays
914
sage: el = IncreasingArrays()([1,2,4]) # indirect doctest
915
"""
916
assert False, "This should never be called, please overload the check method"
917
918
cpdef long _hash_(self):
919
"""
920
Return the hash value of ``self``.
921
922
TESTS::
923
924
sage: from sage.structure.list_clone_demo import IncreasingArrays
925
sage: el = IncreasingArrays()([1,2,3])
926
sage: el._hash_() # random
927
-309711137
928
sage: type(el._hash_()) == int
929
True
930
"""
931
cdef long hv
932
hv = hash(tuple(self._list))
933
return hash(self._parent) + hv
934
935
def __reduce__(self):
936
"""
937
TESTS::
938
939
sage: from sage.structure.list_clone_demo import IncreasingArrays
940
sage: el = IncreasingArrays()([1,2,4])
941
sage: loads(dumps(el))
942
[1, 2, 4]
943
sage: t = el.__reduce__(); t
944
(<built-in function _make_array_clone>, (<type 'sage.structure.list_clone_demo.IncreasingArray'>, <class 'sage.structure.list_clone_demo.IncreasingArrays_with_category'>, [1, 2, 4], True, True, None))
945
sage: t[0](*t[1])
946
[1, 2, 4]
947
"""
948
# Warning: don't pickle the hash value as it can change upon unpickling.
949
if HAS_DICTIONARY(self):
950
dic = self.__dict__
951
else:
952
dic = None
953
return (sage.structure.list_clone._make_array_clone,
954
(type(self), self._parent, self._list,
955
self._needs_check, self._is_immutable, dic))
956
957
958
##### Needed for unpikling #####
959
def _make_array_clone(clas, parent, list, needs_check, is_immutable, dic):
960
"""
961
Helpler to unpikle :class:`list_clone` instances.
962
963
TESTS::
964
965
sage: from sage.structure.list_clone import _make_array_clone
966
sage: from sage.structure.list_clone_demo import IncreasingArrays
967
sage: ILs = IncreasingArrays()
968
sage: el = _make_array_clone(ILs.element_class, ILs, [1,2,3], True, True, None)
969
sage: el
970
[1, 2, 3]
971
sage: el == ILs([1,2,3])
972
True
973
974
We check that element with a ``__dict__`` are correctly pickled::
975
976
sage: IL = IncreasingArrays()
977
sage: class myClass(IL.element_class): pass
978
sage: import __main__
979
sage: __main__.myClass = myClass
980
sage: el = myClass(IL, [])
981
sage: el.toto = 2
982
sage: elc = loads(dumps(el))
983
sage: elc.toto
984
2
985
"""
986
cdef ClonableArray res
987
res = <ClonableArray> PY_NEW(clas)
988
res._parent = parent
989
res._list = list
990
res._needs_check = needs_check
991
res._is_immutable = is_immutable
992
if dic is not None:
993
res.__dict__ = dic
994
return res
995
996
997
############################################################################
998
### Clonable (Resizable) Lists ###
999
############################################################################
1000
cdef class ClonableList(ClonableArray):
1001
"""
1002
List with clone protocol
1003
1004
The class of objects which are
1005
:class:`Element<sage.structure.element.Element>` behave as lists and
1006
implement the clone protocol. See :class:`ClonableElement` for details
1007
about clone protocol.
1008
1009
.. seealso:: :class:`~sage.structure.list_clone_demo.IncreasingList` for
1010
an example of usage.
1011
"""
1012
cpdef append(self, el):
1013
"""
1014
Appends ``el`` to ``self``
1015
1016
INPUT: ``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
Extends ``self`` by the content of the iterable ``it``
1044
1045
INPUT: ``it`` -- any iterable
1046
1047
EXAMPLES::
1048
1049
sage: from sage.structure.list_clone_demo import IncreasingLists
1050
sage: el = IncreasingLists()([1, 4, 5, 8, 9])
1051
sage: el.extend((10,11))
1052
Traceback (most recent call last):
1053
...
1054
ValueError: object is immutable; please change a copy instead.
1055
1056
sage: with el.clone() as elc:
1057
....: elc.extend((10,11))
1058
sage: elc
1059
[1, 4, 5, 8, 9, 10, 11]
1060
1061
sage: el2 = IncreasingLists()([15, 16])
1062
sage: with el.clone() as elc:
1063
....: elc.extend(el2)
1064
sage: elc
1065
[1, 4, 5, 8, 9, 15, 16]
1066
1067
sage: with el.clone() as elc:
1068
....: elc.extend((6,7))
1069
Traceback (most recent call last):
1070
...
1071
ValueError: array is not increasing
1072
"""
1073
self._require_mutable()
1074
self._list.extend(it)
1075
1076
cpdef insert(self, int index, el):
1077
"""
1078
Inserts ``el`` in ``self`` at position ``index``
1079
1080
INPUT:
1081
1082
- ``el`` -- any object
1083
- ``index`` -- any int
1084
1085
EXAMPLES::
1086
1087
sage: from sage.structure.list_clone_demo import IncreasingLists
1088
sage: el = IncreasingLists()([1, 4, 5, 8, 9])
1089
sage: el.insert(3, 6)
1090
Traceback (most recent call last):
1091
...
1092
ValueError: object is immutable; please change a copy instead.
1093
sage: with el.clone() as elc:
1094
....: elc.insert(3, 6)
1095
sage: elc
1096
[1, 4, 5, 6, 8, 9]
1097
sage: with el.clone() as elc:
1098
....: elc.insert(2, 6)
1099
Traceback (most recent call last):
1100
...
1101
ValueError: array is not increasing
1102
"""
1103
self._require_mutable()
1104
self._list.insert(index, el)
1105
1106
cpdef pop(self, int index=-1):
1107
"""
1108
Remove ``self[index]`` from ``self`` and returns it
1109
1110
INPUT: ``index`` - any int, default to -1
1111
1112
EXAMPLES::
1113
1114
sage: from sage.structure.list_clone_demo import IncreasingLists
1115
sage: el = IncreasingLists()([1, 4, 5, 8, 9])
1116
sage: el.pop()
1117
Traceback (most recent call last):
1118
...
1119
ValueError: object is immutable; please change a copy instead.
1120
sage: with el.clone() as elc:
1121
....: print elc.pop()
1122
9
1123
sage: elc
1124
[1, 4, 5, 8]
1125
sage: with el.clone() as elc:
1126
....: print elc.pop(2)
1127
5
1128
sage: elc
1129
[1, 4, 8, 9]
1130
"""
1131
self._require_mutable()
1132
return self._list.pop(index)
1133
1134
cpdef remove(self, el):
1135
"""
1136
Remove the first occurence of ``el`` from ``self``
1137
1138
INPUT: ``el`` - any object
1139
1140
EXAMPLES::
1141
1142
sage: from sage.structure.list_clone_demo import IncreasingLists
1143
sage: el = IncreasingLists()([1, 4, 5, 8, 9])
1144
sage: el.remove(4)
1145
Traceback (most recent call last):
1146
...
1147
ValueError: object is immutable; please change a copy instead.
1148
sage: with el.clone() as elc:
1149
....: elc.remove(4)
1150
sage: elc
1151
[1, 5, 8, 9]
1152
sage: with el.clone() as elc:
1153
....: elc.remove(10)
1154
Traceback (most recent call last):
1155
...
1156
ValueError: list.remove(x): x not in list
1157
"""
1158
self._require_mutable()
1159
return self._list.remove(el)
1160
1161
def __setitem__(self, key, value):
1162
"""
1163
Set the ith element of ``self``
1164
1165
An exception is raised if ``self`` is immutable.
1166
1167
EXAMPLES::
1168
1169
sage: from sage.structure.list_clone_demo import IncreasingLists
1170
sage: el = IncreasingLists()([1,2,4,10,15,17])
1171
sage: el[1] = 3
1172
Traceback (most recent call last):
1173
...
1174
ValueError: object is immutable; please change a copy instead.
1175
1176
sage: with el.clone() as elc:
1177
....: elc[3] = 7
1178
sage: elc
1179
[1, 2, 4, 7, 15, 17]
1180
1181
sage: with el.clone(check=False) as elc:
1182
....: elc[1:3] = [3,5,6,8]
1183
sage: elc
1184
[1, 3, 5, 6, 8, 10, 15, 17]
1185
"""
1186
self._require_mutable()
1187
self._list[key] = value
1188
1189
def __delitem__(self, key):
1190
"""
1191
Remove the ith element of ``self``
1192
1193
An exception is raised if ``self`` is immutable.
1194
1195
EXAMPLES::
1196
1197
sage: from sage.structure.list_clone_demo import IncreasingLists
1198
sage: el = IncreasingLists()([1, 4, 5, 8, 9])
1199
sage: del el[3]
1200
Traceback (most recent call last):
1201
...
1202
ValueError: object is immutable; please change a copy instead.
1203
sage: with el.clone() as elc:
1204
....: del elc[3]
1205
sage: elc
1206
[1, 4, 5, 9]
1207
sage: with el.clone() as elc:
1208
....: del elc[1:3]
1209
sage: elc
1210
[1, 8, 9]
1211
"""
1212
self._require_mutable()
1213
del self._list[key]
1214
1215
1216
############################################################################
1217
### Clonable Arrays of int ##
1218
############################################################################
1219
cdef class ClonableIntArray(ClonableElement):
1220
"""
1221
Array of int with clone protocol
1222
1223
The class of objects which are
1224
:class:`Element<sage.structure.element.Element>` behave as list of int and
1225
implement the clone protocol. See :class:`ClonableElement` for details
1226
about clone protocol.
1227
1228
1229
INPUT:
1230
1231
- ``parent`` -- a :class:`Parent<sage.structure.parent.Parent>`
1232
- ``lst`` -- a list
1233
- ``check`` -- a boolean specifying if the invariant must be checked
1234
using method :meth:`check`
1235
- ``immutable`` -- a boolean telling wether the created element is
1236
immutable (defaults to ``True``)
1237
1238
.. seealso:: :class:`~sage.structure.list_clone_demo.IncreasingIntArray`
1239
for an example of usage.
1240
"""
1241
def __cinit__(self):
1242
self._len = -1
1243
self._list = NULL
1244
1245
def __init__(self, Parent parent, lst, check = True, immutable = True):
1246
"""
1247
Initialize ``self``
1248
1249
TESTS::
1250
1251
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1252
sage: IncreasingIntArrays()([1,2,3])
1253
[1, 2, 3]
1254
sage: IncreasingIntArrays()((1,2,3))
1255
[1, 2, 3]
1256
1257
sage: IncreasingIntArrays()(None)
1258
Traceback (most recent call last):
1259
...
1260
TypeError: object of type 'NoneType' has no len()
1261
1262
sage: el = IncreasingIntArrays()([3,2,1])
1263
Traceback (most recent call last):
1264
...
1265
ValueError: array is not increasing
1266
1267
sage: el = IncreasingIntArrays()([1,2,4])
1268
sage: list(iter(el))
1269
[1, 2, 4]
1270
sage: list(iter(IncreasingIntArrays()([])))
1271
[]
1272
1273
You are not supposed to do the following (giving a wrong list and
1274
desactivating checks)::
1275
1276
sage: broken = IncreasingIntArrays()([3,2,1], False)
1277
"""
1278
cdef int i
1279
self._parent = parent
1280
1281
if self._list is not NULL:
1282
raise ValueError, "resizing is forbidden"
1283
self._alloc_(len(lst))
1284
for i from 0 <= i < self._len:
1285
self._list[i] = lst[i]
1286
1287
self._is_immutable = immutable
1288
if check:
1289
self.check()
1290
1291
cpdef _alloc_(self, int size):
1292
"""
1293
Allocate the array part of ``self`` for a given size
1294
1295
This can be used to initialize ``self`` without passing a list
1296
1297
INPUT: ``size`` - an int
1298
1299
EXAMPLES::
1300
1301
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1302
sage: el = IncreasingIntArrays()([], check=False)
1303
sage: el._alloc_(3)
1304
sage: el._setitem(0, 1); el._setitem(1, 5); el._setitem(2, 8)
1305
sage: el
1306
[1, 5, 8]
1307
sage: copy(el)
1308
[1, 5, 8]
1309
1310
TESTS::
1311
1312
sage: el._alloc_(-1)
1313
Traceback (most recent call last):
1314
...
1315
AssertionError: Negative size is forbidden
1316
"""
1317
assert size >= 0, "Negative size is forbidden"
1318
self._is_immutable = False
1319
if self._list is NULL:
1320
self._len = size
1321
self._list = <int *>sage_malloc(sizeof(int) * self._len)
1322
else:
1323
self._len = size
1324
self._list = <int *>sage_realloc(self._list, sizeof(int) * self._len)
1325
1326
def __dealloc__(self):
1327
if self._list is not NULL:
1328
sage_free(self._list)
1329
self._len = -1
1330
self._list = NULL
1331
1332
def _repr_(self):
1333
"""
1334
TESTS::
1335
1336
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1337
sage: IncreasingIntArrays()([1,2,3])
1338
[1, 2, 3]
1339
"""
1340
return '['+', '.join(["%i"%(self._list[i]) for i in range(self._len)])+']'
1341
1342
def __nonzero__(self):
1343
"""
1344
EXAMPLES::
1345
1346
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1347
sage: IncreasingIntArrays()([1,2,3]).__nonzero__()
1348
True
1349
sage: IncreasingIntArrays()([]).__nonzero__()
1350
False
1351
"""
1352
return self._len != 0
1353
1354
def __len__(self):
1355
"""
1356
Returns the len of ``self``
1357
1358
EXAMPLES::
1359
1360
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1361
sage: len(IncreasingIntArrays()([1,2,3]))
1362
3
1363
"""
1364
return self._len
1365
1366
def __iter__(self):
1367
"""
1368
Iterate over the items of self.
1369
1370
EXAMPLE::
1371
1372
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1373
sage: I = IncreasingIntArrays()(range(5))
1374
sage: I == range(5)
1375
False
1376
sage: list(I) == range(5) # indirect doctest
1377
True
1378
"""
1379
return self.list().__iter__()
1380
1381
cpdef list list(self):
1382
"""
1383
Convert self into a Python list.
1384
1385
EXAMPLE::
1386
1387
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1388
sage: I = IncreasingIntArrays()(range(5))
1389
sage: I == range(5)
1390
False
1391
sage: I.list() == range(5)
1392
True
1393
sage: I = IncreasingIntArrays()(range(1000))
1394
sage: I.list() == range(1000)
1395
True
1396
"""
1397
cdef int i
1398
cdef list L = <list> PyList_New(self._len)
1399
cdef object o
1400
for i from 0<=i<self._len:
1401
o = PyInt_FromLong(self._list[i])
1402
Py_INCREF(o)
1403
PyList_SET_ITEM(L, i, o)
1404
return L
1405
1406
def __getitem__(self, key):
1407
"""
1408
Returns the ith element of ``self``
1409
1410
EXAMPLES::
1411
1412
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1413
sage: el = IncreasingIntArrays()([1,2,3])
1414
sage: el[1]
1415
2
1416
sage: el[1:2]
1417
[2]
1418
sage: el[4]
1419
Traceback (most recent call last):
1420
...
1421
IndexError: list index out of range
1422
sage: el[-1]
1423
3
1424
sage: el[-1:]
1425
[3]
1426
sage: el[:]
1427
[1, 2, 3]
1428
sage: el[1:3]
1429
[2, 3]
1430
sage: type(el[:])
1431
<type 'list'>
1432
sage: list(el)
1433
[1, 2, 3]
1434
sage: it = iter(el); it.next(), it.next()
1435
(1, 2)
1436
"""
1437
cdef int start, stop, step, keyi
1438
cdef list res
1439
cdef slice keysl
1440
# print key
1441
if PY_TYPE_CHECK(key, slice):
1442
keysl = <slice> key
1443
start, stop, step = keysl.indices(self._len)
1444
res = []
1445
for i in range(start, stop, step):
1446
res.append(self._getitem(i))
1447
return res
1448
keyi = <int> key
1449
# print key, key, self._len, self._len+keyi
1450
if keyi < 0:
1451
keyi += self._len
1452
if 0 <= keyi < self._len:
1453
return self._list[keyi]
1454
else:
1455
raise IndexError, "list index out of range"
1456
1457
def __setitem__(self, int key, value):
1458
"""
1459
Set the ith element of ``self``
1460
1461
An exception is raised if ``self`` is immutable.
1462
1463
EXAMPLES::
1464
1465
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1466
sage: el = IncreasingIntArrays()([1,2,4])
1467
sage: elc = copy(el)
1468
sage: elc[1] = 3; elc
1469
[1, 3, 4]
1470
sage: el[1] = 3
1471
Traceback (most recent call last):
1472
...
1473
ValueError: object is immutable; please change a copy instead.
1474
"""
1475
if 0 <= key < self._len:
1476
self._require_mutable()
1477
self._list[key] = value
1478
else:
1479
raise IndexError, "list index out of range"
1480
1481
cpdef object _getitem(self, int key):
1482
"""
1483
Same as :meth:`__getitem__`
1484
1485
This is much faster when used with Cython and the index is known to be
1486
an int.
1487
1488
EXAMPLES::
1489
1490
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1491
sage: IncreasingIntArrays()([1,2,3])._getitem(1)
1492
2
1493
"""
1494
if 0 <= key < self._len:
1495
return self._list[key]
1496
else:
1497
raise IndexError, "list index out of range"
1498
1499
cpdef _setitem(self, int key, value):
1500
"""
1501
Same as :meth:`__setitem__`
1502
1503
This is much faster when used with Cython and the index is known to be
1504
an int.
1505
1506
EXAMPLES::
1507
1508
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1509
sage: el = IncreasingIntArrays()([1,2,4])
1510
sage: elc = copy(el)
1511
sage: elc._setitem(1, 3); elc
1512
[1, 3, 4]
1513
sage: el._setitem(1, 3)
1514
Traceback (most recent call last):
1515
...
1516
ValueError: object is immutable; please change a copy instead.
1517
"""
1518
if 0 <= key < self._len:
1519
self._require_mutable()
1520
self._list[key] = value
1521
else:
1522
raise IndexError, "list index out of range"
1523
1524
def __contains__(self, int item):
1525
"""
1526
EXAMPLES::
1527
1528
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1529
sage: c = IncreasingIntArrays()([1,2,4])
1530
sage: 1 in c
1531
True
1532
sage: 5 in c
1533
False
1534
"""
1535
cdef int i
1536
for i from 0 <= i < self._len:
1537
if item == self._list[i]:
1538
return True
1539
return False
1540
1541
cpdef int index(self, int item):
1542
"""
1543
EXAMPLES::
1544
1545
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1546
sage: c = IncreasingIntArrays()([1,2,4])
1547
sage: c.index(1)
1548
0
1549
sage: c.index(4)
1550
2
1551
sage: c.index(5)
1552
Traceback (most recent call last):
1553
...
1554
ValueError: list.index(x): x not in list
1555
"""
1556
cdef int i
1557
for i from 0 <= i < self._len:
1558
if item == self._list[i]:
1559
return i
1560
raise ValueError, "list.index(x): x not in list"
1561
1562
1563
# __hash__ is not properly inherited if comparison is changed
1564
# see <http://groups.google.com/group/cython-users/t/e89a9bd2ff20fd5a>
1565
def __hash__(self):
1566
"""
1567
Return the hash value of ``self``.
1568
1569
TESTS::
1570
1571
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1572
sage: el = IncreasingIntArrays()([1,2,3])
1573
sage: hash(el) # random
1574
-309690657
1575
sage: el1 = copy(el); hash(el1)
1576
Traceback (most recent call last):
1577
...
1578
ValueError: cannot hash a mutable object.
1579
"""
1580
if self._hash == 0:
1581
if not self._is_immutable:
1582
raise ValueError, "cannot hash a mutable object."
1583
else:
1584
self._hash = self._hash_()
1585
return self._hash
1586
1587
def __richcmp__(left, right, int op):
1588
"""
1589
TESTS::
1590
1591
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1592
sage: el = IncreasingIntArrays()([1,2,4])
1593
sage: elc = copy(el)
1594
sage: elc == el # indirect doctest
1595
True
1596
"""
1597
return (<Element>left)._richcmp(right, op)
1598
1599
# See protocol in comment in sage/structure/element.pyx
1600
cdef int _cmp_c_impl(left, Element right) except -2:
1601
"""
1602
TEST::
1603
1604
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1605
sage: el1 = IncreasingIntArrays()([1,2,4])
1606
sage: el2 = IncreasingIntArrays()([1,2,3])
1607
sage: el1 == el1, el2 == el2, el1 == el2 # indirect doctest
1608
(True, True, False)
1609
sage: el1 <= el2, el1 >= el2, el2 <= el1 # indirect doctest
1610
(False, True, True)
1611
"""
1612
cdef int i, minlen, reslen
1613
cdef ClonableIntArray rgt = <ClonableIntArray>right
1614
if left is right:
1615
return 0
1616
if left._list is NULL:
1617
if rgt._list is NULL:
1618
return 0
1619
else:
1620
return -1
1621
elif rgt._list is NULL:
1622
return 1
1623
if left._len < rgt._len:
1624
minlen = left._len
1625
reslen = -1
1626
elif left._len > rgt._len:
1627
minlen = rgt._len
1628
reslen = +1
1629
else:
1630
minlen = rgt._len
1631
reslen = 0
1632
for i from 0 <= i < minlen:
1633
if left._list[i] != rgt._list[i]:
1634
if left._list[i] < rgt._list[i]:
1635
return -1
1636
else:
1637
return 1
1638
return reslen
1639
1640
cpdef ClonableIntArray __copy__(self):
1641
"""
1642
Returns a copy of ``self``
1643
1644
TESTS::
1645
1646
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1647
sage: el = IncreasingIntArrays()([1,2,4])
1648
sage: elc = copy(el)
1649
sage: el[:] == elc[:]
1650
True
1651
sage: el is elc
1652
False
1653
1654
We check that void lists are correctly copied::
1655
1656
sage: el = IncreasingIntArrays()([])
1657
sage: elc = copy(el)
1658
sage: el is elc
1659
False
1660
sage: elc.__nonzero__()
1661
True
1662
sage: elc.is_mutable()
1663
True
1664
1665
We check that element with a ``__dict__`` are correctly copied::
1666
1667
sage: IL = IncreasingIntArrays()
1668
sage: class myClass(IL.element_class): pass
1669
sage: el = myClass(IL, [])
1670
sage: el.toto = 2
1671
sage: elc = copy(el)
1672
sage: elc.toto
1673
2
1674
"""
1675
cdef ClonableIntArray res
1676
res = PY_NEW_SAME_TYPE(self)
1677
res._parent = self._parent
1678
if self:
1679
res._alloc_(self._len)
1680
for i from 0 <= i < res._len:
1681
res._list[i] = self._list[i]
1682
if HAS_DICTIONARY(self):
1683
res.__dict__ = self.__dict__.copy()
1684
return res
1685
1686
cpdef check(self):
1687
"""
1688
Check that ``self`` fulfill the invariants
1689
1690
This is an abstract method. Subclasses are supposed to overload
1691
``check``.
1692
1693
EXAMPLES::
1694
1695
sage: from sage.structure.list_clone import ClonableArray
1696
sage: ClonableArray(Parent(), [1,2,3]) # indirect doctest
1697
Traceback (most recent call last):
1698
...
1699
AssertionError: This should never be called, please overload the check method
1700
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1701
sage: el = IncreasingIntArrays()([1,2,4]) # indirect doctest
1702
"""
1703
assert False, "This should never be called, please overload the check method"
1704
1705
cpdef long _hash_(self):
1706
"""
1707
Return the hash value of ``self``.
1708
1709
TESTS::
1710
1711
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1712
sage: el = IncreasingIntArrays()([1,2,3])
1713
sage: el._hash_() # random
1714
-309711137
1715
sage: type(el._hash_()) == int
1716
True
1717
"""
1718
cdef long hv
1719
if self._list == NULL:
1720
hv = hash(None)
1721
else:
1722
hv = hash(tuple(self))
1723
return hash(self._parent) + hv
1724
1725
def __reduce__(self):
1726
"""
1727
TESTS::
1728
1729
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1730
sage: el = IncreasingIntArrays()([1,2,4])
1731
sage: loads(dumps(el))
1732
[1, 2, 4]
1733
sage: t = el.__reduce__(); t
1734
(<built-in function _make_int_array_clone>, (<type 'sage.structure.list_clone_demo.IncreasingIntArray'>, <class 'sage.structure.list_clone_demo.IncreasingIntArrays_with_category'>, [1, 2, 4], True, True, None))
1735
sage: t[0](*t[1])
1736
[1, 2, 4]
1737
"""
1738
# Warning: don't pickle the hash value as it can change upon unpickling.
1739
if HAS_DICTIONARY(self):
1740
dic = self.__dict__
1741
else:
1742
dic = None
1743
return (sage.structure.list_clone._make_int_array_clone,
1744
(type(self), self._parent, self[:],
1745
self._needs_check, self._is_immutable, dic))
1746
1747
1748
##### Needed for unpikling #####
1749
def _make_int_array_clone(clas, parent, lst, needs_check, is_immutable, dic):
1750
"""
1751
Helpler to unpikle :class:`list_clone` instances.
1752
1753
TESTS::
1754
1755
sage: from sage.structure.list_clone import _make_int_array_clone
1756
sage: from sage.structure.list_clone_demo import IncreasingIntArrays
1757
sage: ILs = IncreasingIntArrays()
1758
sage: el = _make_int_array_clone(ILs.element_class, ILs, [1,2,3], True, True, None)
1759
sage: el
1760
[1, 2, 3]
1761
sage: el == ILs([1,2,3])
1762
True
1763
1764
We check that element with a ``__dict__`` are correctly pickled::
1765
1766
sage: IL = IncreasingIntArrays()
1767
sage: class myClass(IL.element_class): pass
1768
sage: import __main__
1769
sage: __main__.myClass = myClass
1770
sage: el = myClass(IL, [])
1771
sage: el.toto = 2
1772
sage: elc = loads(dumps(el))
1773
sage: elc.toto
1774
2
1775
"""
1776
cdef ClonableIntArray res
1777
res = <ClonableIntArray> PY_NEW(clas)
1778
ClonableIntArray.__init__(res, parent, lst, needs_check, is_immutable)
1779
if dic is not None:
1780
res.__dict__ = dic
1781
return res
1782
1783
1784
1785
cdef class NormalizedClonableList(ClonableList):
1786
"""
1787
List with clone protocol and normal form
1788
1789
This is a subclass of :class:`ClonableList` which call a method
1790
:meth:`normalize` at creation and after any modification of its instance.
1791
1792
.. seealso:: :class:`~sage.structure.list_clone_demo.SortedList` for an
1793
example of usage.
1794
1795
EXAMPLES:
1796
1797
We construct a sorted list through its parent::
1798
1799
sage: from sage.structure.list_clone_demo import SortedLists
1800
sage: SL = SortedLists()
1801
sage: sl1 = SL([4,2,6,1]); sl1
1802
[1, 2, 4, 6]
1803
1804
Normalization is also performed atfer modification::
1805
1806
sage: with sl1.clone() as sl2:
1807
....: sl2[1] = 12
1808
sage: sl2
1809
[1, 4, 6, 12]
1810
"""
1811
1812
def __init__(self, Parent parent, lst, check = True, immutable = True):
1813
r"""
1814
TESTS::
1815
1816
sage: from sage.structure.list_clone_demo import SortedList, SortedLists
1817
sage: SortedList(SortedLists(), [2,3,1])
1818
[1, 2, 3]
1819
"""
1820
ClonableList.__init__(self, parent, lst, False, False)
1821
self.normalize()
1822
self._is_immutable = immutable
1823
if check:
1824
self.check()
1825
1826
def __exit__(self, typ, value, tracback):
1827
r"""
1828
TESTS::
1829
1830
sage: from sage.structure.list_clone_demo import SortedList, SortedLists
1831
sage: l = SortedList(SortedLists(), [2,3,1], immutable=False); l
1832
[1, 2, 3]
1833
sage: l[1] = 5; l
1834
[1, 5, 3]
1835
sage: l.__exit__(None, None, None)
1836
False
1837
sage: l
1838
[1, 3, 5]
1839
"""
1840
self.normalize()
1841
return ClonableList.__exit__(self, typ, value, tracback)
1842
1843
cpdef normalize(self):
1844
"""
1845
Normalize ``self``
1846
1847
This is an abstract method. Subclasses are supposed to overload
1848
:meth:`normalize`. The call ``self.normalize()`` is supposed to
1849
1850
- call ``self._require_mutable()`` to check that ``self`` is in a
1851
proper mutable state
1852
- modify ``self`` to put it in a normal form
1853
1854
EXAMPLES::
1855
1856
sage: from sage.structure.list_clone_demo import SortedList, SortedLists
1857
sage: l = SortedList(SortedLists(), [2,3,2], False, False)
1858
sage: l
1859
[2, 2, 3]
1860
sage: l.check()
1861
Traceback (most recent call last):
1862
...
1863
ValueError: list is not strictly increasing
1864
"""
1865
assert False, "This should never be called, please overload the normalize method"
1866
1867
1868