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