Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/misc/fast_methods.pyx
8814 views
1
"""
2
Fast methods via Cython
3
4
This module provides extension classes with useful methods of cython speed,
5
that python classes can inherit.
6
7
.. NOTE::
8
9
In its original version, this module provides a cython base class
10
:class:`WithEqualityById` implementing unique instance behaviour, and a
11
cython base class :class:`FastHashable_class`, which has a quite fast hash
12
whose value can be freely chosen at initialisation time.
13
14
AUTHOR:
15
16
- Simon King (2013-02)
17
18
"""
19
20
#******************************************************************************
21
# Copyright (C) 2013 Simon A. King <simon.king at uni-jena.de>
22
#
23
# Distributed under the terms of the GNU General Public License (GPL)
24
#
25
# This code is distributed in the hope that it will be useful,
26
# but WITHOUT ANY WARRANTY; without even the implied warranty of
27
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28
# General Public License for more details.
29
#
30
# The full text of the GPL is available at:
31
#
32
# http://www.gnu.org/licenses/
33
#******************************************************************************
34
35
include "sage/ext/python_rich_object.pxi"
36
from cpython.bool cimport *
37
from cpython.ref cimport *
38
39
cdef int SIZEOF_VOID_P_SHIFT = 8*sizeof(void *) - 4
40
41
cdef class WithEqualityById:
42
"""
43
Provide hash and equality test based on identity.
44
45
.. NOTE::
46
47
This class provides the unique representation behaviour of
48
:class:`~sage.structure.unique_representation.UniqueRepresentation`,
49
together with :class:`~sage.structure.unique_representation.CachedRepresentation`.
50
51
EXAMPLES:
52
53
Any instance of :class:`~sage.structure.unique_representation.UniqueRepresentation`
54
inherits from :class:`WithEqualityById`.
55
::
56
57
sage: class MyParent(Parent):
58
... def __init__(self, x):
59
... self.x = x
60
... def __cmp__(self,other):
61
... return cmp(self.x^2,other.x^2)
62
... def __hash__(self):
63
... return hash(self.x)
64
sage: class MyUniqueParent(UniqueRepresentation, MyParent): pass
65
sage: issubclass(MyUniqueParent, sage.misc.fast_methods.WithEqualityById)
66
True
67
68
Inheriting from :class:`WithEqualityById` provides unique representation
69
behaviour. In particular, the comparison inherited from ``MyParent``
70
is overloaded::
71
72
sage: a = MyUniqueParent(1)
73
sage: b = MyUniqueParent(2)
74
sage: c = MyUniqueParent(1)
75
sage: a is c
76
True
77
sage: d = MyUniqueParent(-1)
78
sage: a == d
79
False
80
81
Note, however, that Python distinguishes between "comparison by cmp"
82
and "comparison by binary relations"::
83
84
sage: cmp(a,d)
85
0
86
87
The comparison inherited from ``MyParent`` will be used in those cases
88
in which identity does not give sufficient information to find the relation::
89
90
sage: a < b
91
True
92
sage: b > d
93
True
94
95
The hash inherited from ``MyParent`` is replaced by a hash that coincides
96
with :class:`object`'s hash::
97
98
sage: hash(a) == hash(a.x)
99
False
100
sage: hash(a) == object.__hash__(a)
101
True
102
103
.. WARNING::
104
105
It is possible to inherit from
106
:class:`~sage.structure.unique_representation.UniqueRepresentation`
107
and then overload equality test in a way that destroys the unique
108
representation property. We strongly recommend against it! You should
109
use :class:`~sage.structure.unique_representation.CachedRepresentation`
110
instead.
111
112
::
113
114
sage: class MyNonUniqueParent(MyUniqueParent):
115
... def __eq__(self, other):
116
... return self.x^2 == other.x^2
117
sage: a = MyNonUniqueParent(1)
118
sage: d = MyNonUniqueParent(-1)
119
sage: a is MyNonUniqueParent(1)
120
True
121
sage: a == d
122
True
123
sage: a is d
124
False
125
126
"""
127
def __hash__(self):
128
"""
129
The hash provided by this class coincides with that of ``<type 'object'>``.
130
131
TESTS::
132
133
sage: class MyParent(Parent):
134
... def __init__(self, x):
135
... self.x = x
136
... def __cmp__(self,other):
137
... return cmp(self.x^2,other.x^2)
138
... def __hash__(self):
139
... return hash(self.x)
140
sage: class MyUniqueParent(UniqueRepresentation, MyParent): pass
141
sage: issubclass(MyUniqueParent, sage.misc.fast_methods.WithEqualityById)
142
True
143
sage: a = MyUniqueParent(1)
144
sage: hash(a) == hash(a.x)
145
False
146
sage: hash(a) == object.__hash__(a)
147
True
148
149
"""
150
# This is the default hash function in Python's object.c:
151
cdef long x
152
cdef size_t y = <size_t><void *>self
153
y = (y >> 4) | (y << SIZEOF_VOID_P_SHIFT)
154
x = <long>y
155
if x==-1:
156
x = -2
157
return x
158
159
def __richcmp__(self, other, int m):
160
"""
161
Equality test provided by this class is by identity.
162
163
TESTS::
164
165
sage: class MyParent(Parent):
166
... def __init__(self, x):
167
... self.x = x
168
... def __cmp__(self,other):
169
... return cmp(self.x^2,other.x^2)
170
... def __hash__(self):
171
... return hash(self.x)
172
sage: class MyUniqueParent(UniqueRepresentation, MyParent): pass
173
sage: issubclass(MyUniqueParent, sage.misc.fast_methods.WithEqualityById)
174
True
175
sage: a = MyUniqueParent(1)
176
sage: b = MyUniqueParent(-1)
177
178
Comparison with ``cmp`` is still using what is inherited
179
from ``MyParent``::
180
181
sage: cmp(a,b)
182
0
183
184
However, equality test takes into account identity::
185
186
sage: a == b
187
False
188
189
In cases in which rich comparison by identity gives no final answer,
190
the comparison inherited from ``MyParent`` is consulted again::
191
192
sage: a <= b and b >= a
193
True
194
sage: a < b
195
False
196
197
"""
198
cdef object out
199
if self is other:
200
if m == 2: # ==
201
return True
202
elif m == 3: # !=
203
return False
204
else:
205
# <= or >= or NotImplemented
206
return m==1 or m==5 or NotImplemented
207
else:
208
if m == 2:
209
return False
210
elif m == 3:
211
return True
212
else:
213
return NotImplemented
214
215
216
217
cdef class FastHashable_class:
218
"""
219
A class that has a fast hash method, returning a pre-assigned value.
220
221
NOTE:
222
223
This is for internal use only. The class has a cdef attribute ``_hash``,
224
that needs to be assigned (for example, by calling the init method, or by
225
a direct assignement using cython). This is slower than using
226
:func:`provide_hash_by_id`, but has the advantage that the hash can be
227
prescribed, by assigning a cdef attribute ``_hash``.
228
229
TESTS::
230
231
sage: from sage.misc.fast_methods import FastHashable_class
232
sage: H = FastHashable_class(123)
233
sage: hash(H)
234
123
235
236
"""
237
def __init__(self, h):
238
"""
239
TESTS::
240
241
sage: from sage.misc.fast_methods import FastHashable_class
242
sage: H = FastHashable_class(123)
243
sage: hash(H) # indirect doctest
244
123
245
246
"""
247
self._hash = h
248
def __hash__(self):
249
"""
250
TESTS::
251
252
sage: from sage.misc.fast_methods import FastHashable_class
253
sage: H = FastHashable_class(123)
254
sage: hash(H) # indirect doctest
255
123
256
257
"""
258
return self._hash
259
260