Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/structure/element_wrapper.py
4036 views
1
"""
2
Wrapping Sage or Python objects as Sage elements
3
4
WARNING: This class has serious issues that can lead to subtle
5
segfaults. Do not use it unless you read trac 8200 first:
6
http://trac.sagemath.org/sage_trac/ticket/8200
7
"""
8
#*****************************************************************************
9
# Copyright (C) 2008-2010 Nicolas M. Thiery <nthiery at users.sf.net>
10
#
11
# Distributed under the terms of the GNU General Public License (GPL)
12
# http://www.gnu.org/licenses/
13
#******************************************************************************
14
15
from sage.structure.element import Element
16
from copy import copy
17
18
class ElementWrapper(Element):
19
r"""
20
A class for wrapping Sage or Python objects as Sage elements
21
22
WARNING: This class has serious issues that can lead to subtle
23
segfaults. Do not use it unless you read trac 8200 first:
24
http://trac.sagemath.org/sage_trac/ticket/8200
25
26
EXAMPLES::
27
28
sage: from sage.structure.element_wrapper import DummyParent
29
sage: parent = DummyParent("A parent")
30
31
sage: o = ElementWrapper("bla", parent = parent); o
32
'bla'
33
sage: isinstance(o, sage.structure.element.Element)
34
True
35
sage: o.parent()
36
A parent
37
sage: o.value
38
'bla'
39
40
Note that ``o`` is not *an instance of* ``str``, but rather
41
*contains a* ``str``. Therefore, ``o`` does not inherit the string
42
methods. On the other hand, it is provided with reasonable default
43
implementations for equality testing, hashing, etc.
44
45
The typical use case of `ElementWrapper` is for trivially
46
constructing new element classes from preexisting Sage or Python
47
classes, with a containment relation. Here we construct the
48
tropical monoid of integers endowed with ``min`` as
49
multiplication. There, it is desirable *not* to inherit the
50
``factor`` method from Integer::
51
52
sage: class MinMonoid(Parent):
53
... def _repr_(self):
54
... return "The min monoid"
55
...
56
sage: M = MinMonoid()
57
sage: class MinMonoidElement(ElementWrapper):
58
... wrapped_class = Integer
59
...
60
... def __mul__(self, other):
61
... return MinMonoidElement(min(self.value, other.value), parent = self.parent())
62
sage: x = MinMonoidElement(5, parent = M); x
63
5
64
sage: x.parent()
65
The min monoid
66
sage: x.value
67
5
68
sage: y = MinMonoidElement(3, parent = M)
69
sage: x * y
70
3
71
72
This example was voluntarily kept to a bare minimum. See the
73
examples in the categories (e.g. ``Semigroups().example()``) for
74
several full featured applications.
75
76
Caveat: the order between the value and the parent argument is
77
likely to change shortly. At this point, all the code using it in
78
the Sage library will be updated. There will be no transition period.
79
"""
80
81
wrapped_class = object
82
83
def __init__(self, value, parent):
84
"""
85
EXAMPLES::
86
87
sage: from sage.structure.element_wrapper import DummyParent
88
sage: a = ElementWrapper(1, parent = DummyParent("A parent"))
89
90
TESTS::
91
92
sage: TestSuite(a).run(skip = "_test_category")
93
94
Note: ElementWrapper is not intended to be used directly,
95
hence the failing category test.
96
"""
97
assert isinstance(value, self.wrapped_class)
98
Element.__init__(self, parent = parent)
99
self.value = value
100
101
def _repr_(self):
102
"""
103
EXAMPLES::
104
105
sage: from sage.structure.element_wrapper import DummyParent
106
sage: ElementWrapper(1, parent = DummyParent("A parent"))
107
1
108
"""
109
return repr(self.value)
110
111
def __hash__(self):
112
"""
113
Returns the same hash as for the wrapped element
114
115
EXAMPLES::
116
117
sage: from sage.structure.element_wrapper import DummyParent
118
sage: parent1 = DummyParent("A parent")
119
sage: parent2 = DummyParent("Another parent")
120
sage: hash(ElementWrapper(1, parent = parent1))
121
1
122
sage: hash(ElementWrapper(1, parent = parent2))
123
1
124
125
TODO: should this take the parent and/or the class into account?
126
"""
127
return hash(self.value)
128
129
def __eq__(self, other):
130
"""
131
Default implementation of equality testing: two elements are
132
equal if they have the same class, same parent, and same value.
133
134
EXAMPLES::
135
136
sage: from sage.structure.element_wrapper import DummyParent
137
sage: parent1 = DummyParent("A parent")
138
sage: parent2 = DummyParent("Another parent")
139
sage: parent1 == parent2
140
False
141
sage: l11 = ElementWrapper(1, parent = parent1)
142
sage: l12 = ElementWrapper(2, parent = parent1)
143
sage: l21 = ElementWrapper(1, parent = parent2)
144
sage: l22 = ElementWrapper(2, parent = parent2)
145
sage: l11 == l11
146
True
147
sage: l11 == l12
148
False
149
sage: l11 == l21
150
False
151
"""
152
return (self.__class__ is other.__class__ and
153
self.parent() == other.parent() and
154
self.value == other.value)
155
156
def __ne__(self, other):
157
"""
158
Default implementation of unequality testing by using
159
:meth:`.__eq__`.
160
161
EXAMPLES::
162
163
sage: from sage.structure.element_wrapper import DummyParent
164
sage: parent1 = DummyParent("A parent")
165
sage: parent2 = DummyParent("Another parent")
166
sage: parent1 == parent2
167
False
168
sage: l11 = ElementWrapper(1, parent = parent1)
169
sage: l12 = ElementWrapper(2, parent = parent1)
170
sage: l21 = ElementWrapper(1, parent = parent2)
171
sage: l22 = ElementWrapper(2, parent = parent2)
172
sage: l11 != l11
173
False
174
sage: l11 != l12
175
True
176
sage: l11 != l21
177
True
178
"""
179
return not self.__eq__(other)
180
181
def __lt__(self, other):
182
"""
183
Returns whether ``self < other``. With this default
184
implementation, they are always incomparable.
185
186
Note: another option would be to not define ``__lt__``, but
187
given the current implementation of SageObject, sorted(...)
188
would break.
189
190
TESTS::
191
192
sage: from sage.structure.element_wrapper import DummyParent
193
sage: parent = DummyParent("A parent")
194
sage: x = ElementWrapper(1, parent = parent)
195
sage: y = ElementWrapper(2, parent = parent)
196
sage: x.__lt__(x), x.__lt__(y), y.__lt__(x), x.__lt__(1)
197
(False, False, False, False)
198
sage: x < x, x < y, y < x, x < 1
199
(False, False, False, False)
200
sage: sorted([x,y])
201
[1, 2]
202
sage: sorted([y,x])
203
[2, 1]
204
"""
205
return False
206
207
def _lt_by_value(self, other):
208
"""
209
Returns whether ``self`` is strictly smaller than ``other``.
210
211
With this implementation 'by value', they are always
212
incomparable unless ``self`` and ``other`` have the same
213
class, parent, and self.value < other.value.
214
215
EXAMPLES::
216
217
sage: from sage.structure.element_wrapper import DummyParent
218
sage: class MyElement(ElementWrapper):
219
... __lt__ = ElementWrapper._lt_by_value
220
...
221
sage: parent1 = DummyParent("A parent")
222
sage: parent2 = DummyParent("Another parent")
223
sage: l11 = MyElement(1, parent = parent1)
224
sage: l12 = MyElement(2, parent = parent1)
225
sage: l21 = MyElement(1, parent = parent2)
226
sage: l22 = MyElement(2, parent = parent2)
227
sage: l11 < l11
228
False
229
sage: l11 < l12, l12 < l11 # values differ
230
(True, False)
231
sage: l11 < l21 # parents differ
232
False
233
sage: l11 < 1 # class differ
234
False
235
sage: 1 < l11 # random, since it depends on what the Integer 1 decides to do, which may just involve memory locations
236
False
237
"""
238
return self.__class__ is other.__class__ and self.parent() == other.parent() and self.value < other.value
239
240
def _cmp_by_value(self, other):
241
"""
242
Implementation of ``cmp`` by comparing first values, then
243
parents, then class. This behavior (which implies a total
244
order) is not always desirable and hard to override. Hence
245
derived subclasses that want to take advantage of this
246
feature need to explicitely set :meth:`.__cmp__`.
247
248
EXAMPLES::
249
250
sage: class MyElement(ElementWrapper):
251
... __cmp__ = ElementWrapper._cmp_by_value
252
...
253
sage: from sage.structure.element_wrapper import DummyParent
254
sage: parent1 = DummyParent("A parent")
255
sage: parent2 = DummyParent("Another parent")
256
sage: parent1 == parent2
257
False
258
sage: l11 = MyElement(1, parent = parent1)
259
sage: l12 = MyElement(2, parent = parent1)
260
sage: l21 = MyElement(1, parent = parent2)
261
sage: l22 = MyElement(2, parent = parent2)
262
sage: cmp(l11, l11)
263
0
264
sage: cmp(l11, l12), cmp(l12, l11) # values differ
265
(-1, 1)
266
sage: cmp(l11, l21) in [-1, 1] # parents differ
267
True
268
sage: cmp(l21, l11) == -cmp(l11, l21)
269
True
270
sage: cmp(l11, 1) in [-1,1] # class differ
271
True
272
"""
273
if self.__class__ != other.__class__:
274
return cmp(self.__class__, other.__class__)
275
if self.parent() != other.parent():
276
return cmp(self.parent(), other.parent())
277
return cmp(self.value, other.value)
278
279
def __copy__(self):
280
"""
281
Copy self and in particular its ``value`` attribute.
282
283
EXAMPLES::
284
285
sage: from sage.structure.element_wrapper import DummyParent
286
sage: parent = DummyParent("A parent")
287
sage: o1 = ElementWrapper([1], parent=parent); o1
288
[1]
289
sage: o2 = copy(o1); o2
290
[1]
291
sage: o1 is o2, o1.__dict__ is o2.__dict__
292
(False, False)
293
sage: o2.value[0] = 3; o2
294
[3]
295
sage: o1
296
[1]
297
sage: class bla(ElementWrapper): pass
298
sage: o3 = bla([1], parent=parent)
299
sage: o4 = copy(o3)
300
sage: o3.value[0] = 3; o4
301
[1]
302
sage: o3.__class__
303
<class '__main__.bla'>
304
sage: o4.__class__
305
<class '__main__.bla'>
306
"""
307
# Note : copy(super(ElementWrapper, self)) does not work.
308
res = super(ElementWrapper, self).__copy__()
309
res.value = copy(self.value)
310
return res
311
312
313
from sage.structure.parent import Parent
314
from sage.structure.unique_representation import UniqueRepresentation
315
class DummyParent(UniqueRepresentation, Parent):
316
"""
317
A class for creating dummy parents for testing ElementWrapper
318
"""
319
def __init__(self, name):
320
"""
321
EXAMPLES::
322
323
sage: from sage.structure.element_wrapper import DummyParent
324
sage: parent = DummyParent("A Parent")
325
sage: TestSuite(parent).run(skip = ["_test_an_element", "_test_category", "_test_elements", "_test_elements_eq", "_test_some_elements"])
326
"""
327
self.name = name
328
329
def _repr_(self):
330
"""
331
EXAMPLES::
332
333
sage: from sage.structure.element_wrapper import DummyParent
334
sage: DummyParent("A Parent")
335
A Parent
336
"""
337
return self.name
338
339
from sage.categories.sets_cat import Sets
340
class ElementWrapperTester(ElementWrapper):
341
"""
342
Test class for the default :meth:`.__copy` method of subclasses of
343
:class:`ElementWrapper`.
344
345
TESTS::
346
347
sage: from sage.structure.element_wrapper import ElementWrapperTester
348
sage: x = ElementWrapperTester()
349
sage: x.append(2); y = copy(x); y.append(42)
350
sage: type(y)
351
<class 'sage.structure.element_wrapper.ElementWrapperTester'>
352
sage: x, y
353
([n=1, value=[2]], [n=2, value=[2, 42]])
354
sage: x.append(21); x.append(7)
355
sage: x, y
356
([n=3, value=[2, 21, 7]], [n=2, value=[2, 42]])
357
sage: x.__dict__, y.__dict__
358
({'value': [2, 21, 7], 'n': 3}, {'value': [2, 42], 'n': 2})
359
"""
360
def __init__(self):
361
"""
362
TESTS::
363
364
sage: from sage.structure.element_wrapper import ElementWrapperTester
365
sage: x = ElementWrapperTester(); x
366
[n=0, value=[]]
367
"""
368
super(ElementWrapperTester, self).__init__([], parent = Sets().example("facade"))
369
self.n = 0
370
371
def append(self, x):
372
"""
373
TESTS::
374
375
sage: from sage.structure.element_wrapper import ElementWrapperTester
376
sage: x = ElementWrapperTester()
377
sage: x.append(2); x
378
[n=1, value=[2]]
379
"""
380
self.n +=1
381
self.value.append(x)
382
383
def _repr_(self):
384
"""
385
TESTS::
386
387
sage: from sage.structure.element_wrapper import ElementWrapperTester
388
sage: x = ElementWrapperTester
389
sage: x = ElementWrapperTester(); x
390
[n=0, value=[]]
391
sage: x.value = [2,32]; x
392
[n=0, value=[2, 32]]
393
"""
394
return "[n=%s, value=%s]"%(self.n, self.value)
395
396