Ticket #14054: trac14054_fast_methods.patch
File trac14054_fast_methods.patch, 55.6 KB (added by , 9 years ago) |
---|
-
doc/en/reference/misc.rst
# HG changeset patch # User Simon King <simon.king@uni-jena.de> # Date 1361268866 -3600 # Node ID 935c3845daaa8c8f2ddc9b2273be08c711184fb8 # Parent efe3c1085e05c5ae339d6e1fb9dcf58a4b52aea3 #14054: Separate CachedRepresentation from UniqueRepresentation. diff --git a/doc/en/reference/misc.rst b/doc/en/reference/misc.rst
a b 46 46 sage/misc/nested_class 47 47 sage/misc/nested_class_test 48 48 sage/misc/classcall_metaclass 49 sage/misc/fast_methods 49 50 sage/misc/sage_unittest 50 51 sage/misc/randstate 51 52 sage/misc/cython -
module_list.py
diff --git a/module_list.py b/module_list.py
a b 1197 1197 Extension('sage.misc.classcall_metaclass', 1198 1198 sources = ['sage/misc/classcall_metaclass.pyx']), 1199 1199 1200 Extension('sage.misc.fast_methods', 1201 sources = ['sage/misc/fast_methods.pyx']), 1202 1200 1203 Extension('sage.misc.binary_tree', 1201 1204 sources = ['sage/misc/binary_tree.pyx']), 1202 1205 -
sage/algebras/iwahori_hecke_algebra.py
diff --git a/sage/algebras/iwahori_hecke_algebra.py b/sage/algebras/iwahori_hecke_algebra.py
a b 14 14 from sage.combinat.family import Family 15 15 from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement 16 16 from sage.misc.cachefunc import cached_method 17 from sage.structure.unique_representation import UniqueRepresentation 17 18 18 class IwahoriHeckeAlgebraT( CombinatorialFreeModule):19 class IwahoriHeckeAlgebraT(UniqueRepresentation, CombinatorialFreeModule): 19 20 r""" 20 21 INPUT: 21 22 -
sage/categories/category_singleton.pxd
diff --git a/sage/categories/category_singleton.pxd b/sage/categories/category_singleton.pxd
a b 1 cdef class FastHashable_class:2 cdef Py_ssize_t _hash3 4 1 cdef class Category_contains_method_by_parent_class: 5 2 cdef type _parent_class_of_category -
sage/categories/category_singleton.pyx
diff --git a/sage/categories/category_singleton.pyx b/sage/categories/category_singleton.pyx
a b 82 82 except AttributeError: 83 83 return False 84 84 85 cdef class FastHashable_class: 86 """ 87 A class that has a fast hash method, returning a pre-assigned value. 88 89 NOTE: 90 91 This is for internal use only. The class has a cdef attribute ``_hash``, 92 that needs to be assigned. 93 94 TESTS:: 95 96 sage: issubclass(Rings, sage.categories.category_singleton.FastHashable_class) 97 True 98 99 """ 100 def __hash__(self): 101 """ 102 TESTS:: 103 104 sage: hash(Rings()) == id(Rings) # indirect doctest 105 True 106 107 """ 108 return self._hash 109 110 111 class Category_singleton(FastHashable_class,Category): 85 class Category_singleton(Category): 112 86 """ 113 87 A base class for implementing singleton category 114 88 … … 274 248 sage: MySubStuff() 275 249 Category of my stuff 276 250 """ 277 cdef FastHashable_class obj278 251 if cls.__mro__[1] is not Category_singleton: 279 252 # Actually this type error is invisible. But it makes sure that 280 253 # the __classcall__ for Category_singleton is not overridden 281 254 # when someone is calling it. 282 255 raise TypeError, "%s is not a direct subclass of %s"%(cls,Category_singleton) 283 256 obj = UniqueRepresentation.__classcall__(cls) 284 obj._hash = <Py_ssize_t><void *>cls285 257 return ConstantFunction(obj) 286 258 287 # @lazy_class_attribute288 # def __hash__(cls):289 # """290 # The hash of the unique instance of a category singleton is the address of its class.291 #292 # EXAMPLES::293 #294 # sage: hash(Rings()) == hash(Rings) # indirect doctest295 # True296 #297 # """298 # return ConstantFunction(id(cls))299 300 259 @lazy_class_attribute 301 260 def __contains__(cls): 302 261 """ -
sage/categories/examples/algebras_with_basis.py
diff --git a/sage/categories/examples/algebras_with_basis.py b/sage/categories/examples/algebras_with_basis.py
a b 13 13 from sage.categories.all import AlgebrasWithBasis 14 14 from sage.combinat.free_module import CombinatorialFreeModule 15 15 from sage.combinat.words.words import Words 16 from sage.structure.unique_representation import UniqueRepresentation 16 17 17 class FreeAlgebra( CombinatorialFreeModule):18 class FreeAlgebra(UniqueRepresentation, CombinatorialFreeModule): 18 19 r""" 19 20 An example of an algebra with basis: the free algebra 20 21 -
sage/categories/primer.py
diff --git a/sage/categories/primer.py b/sage/categories/primer.py
a b 427 427 [<class 'sage.categories.examples.finite_semigroups.LeftRegularBand_with_category'>, 428 428 <class 'sage.categories.examples.finite_semigroups.LeftRegularBand'>, 429 429 <class 'sage.structure.unique_representation.UniqueRepresentation'>, 430 <class 'sage.structure.unique_representation.CachedRepresentation'>, 431 <type 'sage.misc.fast_methods.WithRichCmpById'>, 430 432 <type 'sage.structure.parent.Parent'>, 431 433 <type 'sage.structure.category_object.CategoryObject'>, 432 434 <type 'sage.structure.sage_object.SageObject'>, -
sage/categories/sets_cat.py
diff --git a/sage/categories/sets_cat.py b/sage/categories/sets_cat.py
a b 88 88 <class 'sage.categories.examples.sets_cat.PrimeNumbers_Inherits'> 89 89 <class 'sage.categories.examples.sets_cat.PrimeNumbers_Abstract'> 90 90 <class 'sage.structure.unique_representation.UniqueRepresentation'> 91 <class 'sage.structure.unique_representation.CachedRepresentation'> 92 <type 'sage.misc.fast_methods.WithRichCmpById'> 91 93 <type 'sage.structure.parent.Parent'> 92 94 <type 'sage.structure.category_object.CategoryObject'> 93 95 <type 'sage.structure.sage_object.SageObject'> -
sage/combinat/free_module.py
diff --git a/sage/combinat/free_module.py b/sage/combinat/free_module.py
a b 9 9 # Distributed under the terms of the GNU General Public License (GPL) 10 10 # http://www.gnu.org/licenses/ 11 11 #***************************************************************************** 12 from sage.structure.unique_representation import UniqueRepresentation12 from sage.structure.unique_representation import CachedRepresentation 13 13 from sage.structure.element import Element 14 14 from sage.structure.parent import Parent 15 15 from sage.structure.sage_object import have_same_parent … … 262 262 sage: F1.zero() == 0 263 263 True 264 264 sage: F1.zero() == F2.zero() 265 False265 True 266 266 sage: F1.an_element() == None 267 267 False 268 268 … … 870 870 else: 871 871 return q 872 872 873 class CombinatorialFreeModule( UniqueRepresentation, Module):873 class CombinatorialFreeModule(CachedRepresentation, Module): 874 874 r""" 875 875 Class for free modules with a named basis 876 876 … … 1000 1000 sage: F1 is F 1001 1001 True 1002 1002 1003 The constructed free module depends on the order of the basis and 1004 on the other parameters, like the prefix:: 1003 The identity of the constructed free module depends on the order of the 1004 basis and on the other parameters, like the prefix. However, the resulting 1005 modules evaluate equal (thus, violate the unique parent assumption):: 1005 1006 1006 1007 sage: F1 = CombinatorialFreeModule(QQ, (1,2,3,4)) 1007 1008 sage: F1 is F 1008 1009 True 1009 1010 sage: F1 = CombinatorialFreeModule(QQ, [4,3,2,1]) 1010 1011 sage: F1 == F 1011 False1012 True 1012 1013 sage: F2 = CombinatorialFreeModule(QQ, [1,2,3,4], prefix='F') 1013 1014 sage: F2 == F 1014 False1015 True 1015 1016 1016 1017 Because of this, if you create a free module with certain 1017 1018 parameters and then modify its prefix or other print options, this 1018 affects all modules which were defined using the same parameters:: 1019 affects all modules which were defined using the same parameters. 1020 Note, however, that :class:`CombinatorialFreeModule` has just a 1021 :class:`~sage.structure.unique_representation.CachedRepresentation`, 1022 but no :class:`~sage.structure.unique_representation.UniqueRepresentation`:: 1019 1023 1020 1024 sage: F2.print_options(prefix='x') 1021 1025 sage: F2.prefix() … … 1027 1031 'x' 1028 1032 sage: F4 = CombinatorialFreeModule(QQ, [1,2,3,4], prefix='F', bracket=True) 1029 1033 sage: F4 == F2 # F4 was NOT defined just like F2 1030 False1034 True 1031 1035 sage: F4.prefix() 1032 1036 'F' 1033 1037 … … 1221 1225 # self._repr_option_bracket. Future users might consider 1222 1226 # using 'bracket' instead of _repr_option_bracket. 1223 1227 1224 # ignore the optional 'key' since it only affects UniqueRepresentation1228 # ignore the optional 'key' since it only affects CachedRepresentation 1225 1229 kwds.pop('key', None) 1226 1230 self.print_options(**kwds) 1227 1231 … … 2328 2332 sage: T.print_options(tensor_symbol= ' @ ') # note the spaces 2329 2333 sage: T # indirect doctest 2330 2334 F @ G 2335 2336 To avoid a side\--effect on another doctest, we revert the change:: 2337 2338 sage: T.print_options(tensor_symbol= ' # ') 2331 2339 """ 2332 2340 from sage.categories.tensor import tensor 2333 2341 if hasattr(self, "_print_options"): … … 2412 2420 sage: f = F.monomial(1) + 2 * F.monomial(2) 2413 2421 sage: g = 2*G.monomial(3) + G.monomial(4) 2414 2422 sage: h = H.monomial(5) + H.monomial(6) 2415 2416 2423 sage: FG = tensor([F, G ]) 2417 2424 sage: phi_fg = FG.tensor_constructor((F, G)) 2418 2425 sage: phi_fg(f,g) -
sage/combinat/ncsf_qsym/ncsf.py
diff --git a/sage/combinat/ncsf_qsym/ncsf.py b/sage/combinat/ncsf_qsym/ncsf.py
a b 943 943 from sage.categories.all import tensor 944 944 return tensor([self.one(), x]) + tensor([x, self.one()]) 945 945 946 class Ribbon( CombinatorialFreeModule, BindableClass):946 class Ribbon(UniqueRepresentation, CombinatorialFreeModule, BindableClass): 947 947 r""" 948 948 The Hopf algebra of non-commutative symmetric functions in the Ribbon basis. 949 949 … … 1089 1089 1090 1090 R = ribbon = Ribbon 1091 1091 1092 class Complete( CombinatorialFreeModule, BindableClass):1092 class Complete(UniqueRepresentation, CombinatorialFreeModule, BindableClass): 1093 1093 """ 1094 1094 The Hopf algebra of non-commutative symmetric functions in the Complete basis. 1095 1095 … … 1256 1256 1257 1257 S = complete = Complete 1258 1258 1259 class Elementary( CombinatorialFreeModule, BindableClass):1259 class Elementary(UniqueRepresentation, CombinatorialFreeModule, BindableClass): 1260 1260 r""" 1261 1261 The Hopf algebra of non-commutative symmetric functions in the Elementary basis. 1262 1262 … … 1346 1346 1347 1347 L = elementary = Elementary 1348 1348 1349 class Psi( CombinatorialFreeModule, BindableClass):1349 class Psi(UniqueRepresentation, CombinatorialFreeModule, BindableClass): 1350 1350 r""" 1351 1351 The Hopf algebra of non-commutative symmetric functions in the Psi basis. 1352 1352 … … 1485 1485 return complete.sum_of_terms((J, minus_one**(len(J)-len(I))*coeff_lp(J,I)) 1486 1486 for J in I.finer()) 1487 1487 1488 class Phi( CombinatorialFreeModule, BindableClass):1488 class Phi(UniqueRepresentation, CombinatorialFreeModule, BindableClass): 1489 1489 r""" 1490 1490 The Hopf algebra of non-commutative symmetric functions in the Phi basis. 1491 1491 … … 1593 1593 return complete.sum_of_terms((J, minus_one**(len(J)-len(I)) * prod(I) / coeff_ell(J,I)) 1594 1594 for J in I.finer()) 1595 1595 1596 class Monomial( CombinatorialFreeModule, BindableClass):1596 class Monomial(UniqueRepresentation, CombinatorialFreeModule, BindableClass): 1597 1597 def __init__(self, NCSF): 1598 1598 r""" 1599 1599 Basis from 'Noncommutative Analogs of Monomial Symmetric … … 1700 1700 1701 1701 nM = monomial = Monomial 1702 1702 1703 class Immaculate( CombinatorialFreeModule, BindableClass):1703 class Immaculate(UniqueRepresentation, CombinatorialFreeModule, BindableClass): 1704 1704 def __init__(self, NCSF): 1705 1705 r""" 1706 1706 The immaculate basis of the non-commutative symmetric functions. This basis first -
sage/combinat/root_system/dynkin_diagram.py
diff --git a/sage/combinat/root_system/dynkin_diagram.py b/sage/combinat/root_system/dynkin_diagram.py
a b 171 171 """ 172 172 EXAMPLES:: 173 173 174 sage: hash(CartanType(['A',3]).dynkin_diagram()) # indirect doctest175 286820813001824631 # 64-bit176 -2127980169 # 32-bit174 sage: d = CartanType(['A',3]).dynkin_diagram() 175 sage: hash(d) == hash((d.cartan_type(), tuple(d.vertices()), tuple(d.edge_iterator(d.vertices())))) 176 True 177 177 """ 178 178 # Should assert for immutability! 179 179 -
sage/combinat/root_system/weyl_characters.py
diff --git a/sage/combinat/root_system/weyl_characters.py b/sage/combinat/root_system/weyl_characters.py
a b 18 18 from sage.misc.flatten import flatten 19 19 from sage.misc.lazy_attribute import lazy_attribute 20 20 from sage.misc.functional import is_even, is_odd 21 from sage.structure.unique_representation import UniqueRepresentation 21 22 from sage.modules.free_module_element import vector 22 23 from sage.rings.all import ZZ, QQ 23 24 24 class WeylCharacterRing( CombinatorialFreeModule):25 class WeylCharacterRing(UniqueRepresentation, CombinatorialFreeModule): 25 26 """ 26 27 A class for rings of Weyl characters. 27 28 … … 2516 2517 else: 2517 2518 return lambda x : tuple(M*vector(x)) 2518 2519 2519 class WeightRing( CombinatorialFreeModule):2520 class WeightRing(UniqueRepresentation,CombinatorialFreeModule): 2520 2521 """ 2521 2522 The WeightRing is the group algebra over a weight lattice. 2522 2523 -
sage/combinat/sf/sfa.py
diff --git a/sage/combinat/sf/sfa.py b/sage/combinat/sf/sfa.py
a b 203 203 from sage.combinat.partition import Partitions 204 204 import sage.libs.symmetrica.all as symmetrica # used in eval() 205 205 from sage.combinat.free_module import CombinatorialFreeModule 206 from sage.structure.unique_representation import UniqueRepresentation 206 207 from sage.matrix.constructor import matrix 207 208 from sage.misc.misc import repr_lincomb, prod, uniq 208 209 from functools import partial … … 762 763 """ 763 764 return self.coefficient([]) 764 765 765 class SymmetricFunctionAlgebra_generic( CombinatorialFreeModule):766 class SymmetricFunctionAlgebra_generic(UniqueRepresentation, CombinatorialFreeModule): 766 767 r""" 767 768 768 769 .. TODO:: most of the methods in this class are generic (manipulations of morphisms, ...) and should be generalized (or removed) -
sage/combinat/symmetric_group_algebra.py
diff --git a/sage/combinat/symmetric_group_algebra.py b/sage/combinat/symmetric_group_algebra.py
a b 15 15 import partition 16 16 from tableau import Tableau, StandardTableaux_size, StandardTableaux_shape, StandardTableaux 17 17 from sage.interfaces.all import gap 18 from sage.structure.unique_representation import UniqueRepresentation 18 19 from sage.rings.all import factorial, QQ, PolynomialRing 19 20 from sage.matrix.all import matrix 20 21 from sage.modules.all import vector … … 91 92 """ 92 93 return SymmetricGroupAlgebra_n(R,n) 93 94 94 class SymmetricGroupAlgebra_n( CombinatorialFreeModule):95 class SymmetricGroupAlgebra_n(UniqueRepresentation, CombinatorialFreeModule): 95 96 96 97 def __init__(self, R, n): 97 98 """ 98 99 TESTS:: 99 100 100 101 sage: QS3 = SymmetricGroupAlgebra(QQ, 3) 101 sage: QS3 ==loads(dumps(QS3))102 sage: QS3 is loads(dumps(QS3)) 102 103 True 103 104 """ 104 105 self.n = n … … 747 748 748 749 return HeckeAlgebraSymmetricGroup_t(R, n, q) 749 750 750 class HeckeAlgebraSymmetricGroup_generic( CombinatorialAlgebra):751 class HeckeAlgebraSymmetricGroup_generic(UniqueRepresentation, CombinatorialAlgebra): 751 752 def __init__(self, R, n, q=None): 752 753 """ 753 754 TESTS:: -
sage/ext/python_rich_object.pxi
diff --git a/sage/ext/python_rich_object.pxi b/sage/ext/python_rich_object.pxi
a b 31 31 newfunc tp_new 32 32 freefunc tp_free 33 33 destructor tp_dealloc 34 hashfunc tp_hash 35 richcmpfunc tp_richcompare 34 36 35 37 #sizeof(Object) 36 38 Py_ssize_t tp_basicsize -
sage/graphs/isgci.py
diff --git a/sage/graphs/isgci.py b/sage/graphs/isgci.py
a b 328 328 """ 329 329 330 330 from sage.structure.sage_object import SageObject 331 from sage.structure.unique_representation import UniqueRepresentation331 from sage.structure.unique_representation import CachedRepresentation, UniqueRepresentation 332 332 from sage.misc.unknown import Unknown 333 333 from sage.misc.misc import SAGE_SHARE 334 334 … … 341 341 342 342 _XML_FILE = "isgci_sage.xml" 343 343 344 class GraphClass(SageObject, UniqueRepresentation):344 class GraphClass(SageObject, CachedRepresentation): 345 345 r""" 346 346 An instance of this class represents a Graph Class, matching some entry in 347 347 the ISGCI database. -
sage/groups/perm_gps/permgroup_named.py
diff --git a/sage/groups/perm_gps/permgroup_named.py b/sage/groups/perm_gps/permgroup_named.py
a b 89 89 from sage.rings.arith import factor 90 90 from sage.groups.abelian_gps.abelian_group import AbelianGroup 91 91 from sage.misc.functional import is_even 92 from sage.misc.cachefunc import cached_method 92 from sage.misc.cachefunc import cached_method, weak_cached_function 93 from sage.misc.classcall_metaclass import typecall 93 94 from sage.misc.superseded import deprecated_function_alias 94 95 from sage.groups.perm_gps.permgroup import PermutationGroup_generic 95 96 from sage.groups.perm_gps.permgroup_element import PermutationGroupElement 96 from sage.structure.unique_representation import UniqueRepresentation97 from sage.structure.unique_representation import CachedRepresentation 97 98 from sage.structure.parent import Parent 98 99 from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets 99 100 from sage.sets.finite_enumerated_set import FiniteEnumeratedSet … … 103 104 from sage.sets.family import Family 104 105 from sage.sets.primes import Primes 105 106 106 class PermutationGroup_unique(UniqueRepresentation, PermutationGroup_generic): 107 @staticmethod 107 class PermutationGroup_unique(CachedRepresentation, PermutationGroup_generic): 108 """ 109 .. TODO:: 110 111 Fix the broken hash. 112 :: 113 114 sage: G = SymmetricGroup(6) 115 sage: G3 = G.subgroup([G((1,2,3,4,5,6)),G((1,2))]) 116 sage: hash(G) == hash(G3) # todo: Should be True! 117 False 118 """ 119 @weak_cached_function 108 120 def __classcall__(cls, *args, **kwds): 109 121 """ 110 122 This makes sure that domain is a FiniteEnumeratedSet before it gets passed … … 124 136 125 137 def __eq__(self, other): 126 138 """ 127 Overrides the default equality testing provided by128 UniqueRepresentation by forcing a call to :meth:.`__cmp__`.129 130 139 EXAMPLES:: 131 140 132 141 sage: G = SymmetricGroup(6) 133 142 sage: G3 = G.subgroup([G((1,2,3,4,5,6)),G((1,2))]) 134 143 sage: G == G3 135 144 True 145 146 .. WARNING:: 147 148 The hash currently is broken for this comparison. 136 149 """ 137 150 return self.__cmp__(other) == 0 138 151 … … 1631 1644 """ 1632 1645 return isinstance(G,TransitiveGroup) 1633 1646 1634 class TransitiveGroupsOfDegree( UniqueRepresentation, Parent):1647 class TransitiveGroupsOfDegree(CachedRepresentation, Parent): 1635 1648 """ 1636 1649 The set of all transitive groups of a given (small) degree up to isomorphisms. 1637 1650 … … 2028 2041 """ 2029 2042 return isinstance(G,PrimitiveGroup) 2030 2043 2031 class PrimitiveGroupsOfDegree( UniqueRepresentation, Parent):2044 class PrimitiveGroupsOfDegree(CachedRepresentation, Parent): 2032 2045 """ 2033 2046 The set of all primitive groups of a given degree up to isomorphisms. 2034 2047 … … 2666 2679 2667 2680 """ 2668 2681 return "The Suzuki group over %s"%self.base_ring() 2669 2670 2671 2672 2673 2674 2675 -
new file sage/misc/fast_methods.pxd
diff --git a/sage/misc/fast_methods.pxd b/sage/misc/fast_methods.pxd new file mode 100644
- + 1 cdef class FastHashable_class: 2 cdef long _hash -
new file sage/misc/fast_methods.pyx
diff --git a/sage/misc/fast_methods.pyx b/sage/misc/fast_methods.pyx new file mode 100644
- + 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:`FastHashable_class` with assignable hash, and a cython base 11 class :class:`WithRichCmpById` implementing unique instance behaviour. 12 13 AUTHOR: 14 15 - Simon King (2013-02) 16 17 """ 18 19 #****************************************************************************** 20 # Copyright (C) 2013 Simon A. King <simon.king at uni-jena.de> 21 # 22 # Distributed under the terms of the GNU General Public License (GPL) 23 # 24 # This code is distributed in the hope that it will be useful, 25 # but WITHOUT ANY WARRANTY; without even the implied warranty of 26 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 # General Public License for more details. 28 # 29 # The full text of the GPL is available at: 30 # 31 # http://www.gnu.org/licenses/ 32 #****************************************************************************** 33 34 include "../ext/python_rich_object.pxi" 35 include "../ext/python_bool.pxi" 36 include "../ext/python_ref.pxi" 37 38 cdef int SIZEOF_VOID_P_SHIFT = 8*sizeof(void *) - 4 39 40 cdef class WithRichCmpById: 41 """ 42 Provide hash and comparison based on identity. 43 44 .. NOTE:: 45 46 This class provides the unique representation behaviour of 47 :class:`~sage.structure.unique_representation.UniqueRepresentation`, 48 together with :class:`~sage.structure.unique_representation.CachedRepresentation`. 49 50 EXAMPLES: 51 52 Any instance of :class:`~sage.structure.unique_representation.UniqueRepresentation` 53 inherits from :class:`WithRichCmpById`. 54 :: 55 56 sage: class MyParent(Parent): 57 ... def __init__(self, x): 58 ... self.x = x 59 ... def __cmp__(self,other): 60 ... return cmp(self.x^2,other.x^2) 61 ... def __hash__(self): 62 ... return hash(self.x) 63 sage: class MyUniqueParent(UniqueRepresentation, MyParent): pass 64 sage: issubclass(MyUniqueParent, sage.misc.fast_methods.WithRichCmpById) 65 True 66 67 Inheriting from :class:`WithRichCmpById` provides unique representation 68 behaviour. In particular, the comparison inherited from ``MyParent`` 69 is overloaded:: 70 71 sage: a = MyUniqueParent(1) 72 sage: b = MyUniqueParent(2) 73 sage: c = MyUniqueParent(1) 74 sage: a is c 75 True 76 sage: d = MyUniqueParent(-1) 77 sage: a == d 78 False 79 80 Note, however, that Python distinguishes between "comparison by cmp" 81 and "comparison by binary relations":: 82 83 sage: cmp(a,d) 84 0 85 86 The comparison inherited from ``MyParent`` will be used in those cases 87 in which identity does not give sufficient information to find the relation:: 88 89 sage: a < b 90 True 91 sage: b > d 92 True 93 94 The hash inherited from ``MyParent`` is replaced by a hash that coincides 95 with :class:`object`'s hash:: 96 97 sage: hash(a) == hash(a.x) 98 False 99 sage: hash(a) == object.__hash__(a) 100 True 101 102 .. WARNING:: 103 104 It is possible to inherit from 105 :class:`~sage.structure.unique_representation.UniqueRepresentation` 106 and then overload comparison in a way that destroys the unique 107 representation property. We strongly recommend against it! You should 108 use :class:`~sage.structure.unique_representation.CachedRepresentation` 109 instead. 110 111 :: 112 113 sage: class MyNonUniqueParent(MyUniqueParent): 114 ... def __eq__(self, other): 115 ... return self.x^2 == other.x^2 116 sage: a = MyNonUniqueParent(1) 117 sage: d = MyNonUniqueParent(-1) 118 sage: a is MyNonUniqueParent(1) 119 True 120 sage: a == d 121 True 122 sage: a is d 123 False 124 125 """ 126 def __hash__(self): 127 """ 128 The hash provided by this class coincides with that of ``<type 'object'>``. 129 130 TESTS:: 131 132 sage: class MyParent(Parent): 133 ... def __init__(self, x): 134 ... self.x = x 135 ... def __cmp__(self,other): 136 ... return cmp(self.x^2,other.x^2) 137 ... def __hash__(self): 138 ... return hash(self.x) 139 sage: class MyUniqueParent(UniqueRepresentation, MyParent): pass 140 sage: issubclass(MyUniqueParent, sage.misc.fast_methods.WithRichCmpById) 141 True 142 sage: a = MyUniqueParent(1) 143 sage: hash(a) == hash(a.x) 144 False 145 sage: hash(a) == object.__hash__(a) 146 True 147 148 """ 149 # This is the default hash function in Python's object.c: 150 cdef long x 151 cdef size_t y = <size_t><void *>self 152 y = (y >> 4) | (y << SIZEOF_VOID_P_SHIFT) 153 x = <long>y 154 if x==-1: 155 x = -2 156 return x 157 158 def __richcmp__(self, other, int m): 159 """ 160 Rich comparison provided by this class is by identity. 161 162 TESTS:: 163 164 sage: class MyParent(Parent): 165 ... def __init__(self, x): 166 ... self.x = x 167 ... def __cmp__(self,other): 168 ... return cmp(self.x^2,other.x^2) 169 ... def __hash__(self): 170 ... return hash(self.x) 171 sage: class MyUniqueParent(UniqueRepresentation, MyParent): pass 172 sage: issubclass(MyUniqueParent, sage.misc.fast_methods.WithRichCmpById) 173 True 174 sage: a = MyUniqueParent(1) 175 sage: b = MyUniqueParent(-1) 176 177 Comparison with ``cmp`` is still using what is inherited 178 from ``MyParent``:: 179 180 sage: cmp(a,b) 181 0 182 183 However, rich comparison takes into account identity:: 184 185 sage: a == b 186 False 187 188 In cases in which rich comparison by identity gives no final answer, 189 the comparison inherited from ``MyParent`` is consulted again:: 190 191 sage: a <= b and b >= a 192 True 193 194 """ 195 cdef object out 196 if self is other: 197 if m==0: # < 198 return False 199 elif m==1: # <= 200 return True 201 elif m==2: # == 202 return True 203 elif m==3: # != 204 return False 205 elif m==4: # > 206 return False 207 else: # >= 208 return True 209 else: 210 if m==2: 211 return False 212 elif m==3: 213 return True 214 else: 215 return NotImplemented 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 -
sage/misc/unknown.py
diff --git a/sage/misc/unknown.py b/sage/misc/unknown.py
a b 153 153 else: 154 154 raise ValueError, "Unable to compare %s with %s"%(self, other) 155 155 156 def __eq__(self, other):157 """158 TESTS::159 160 sage: Unknown == Unknown161 True162 sage: Unknown == None163 False164 """165 return self is other166 167 def __ne__(self, other):168 """169 TESTS::170 171 sage: Unknown != Unknown172 False173 sage: Unknown != None174 True175 """176 return self is not other177 178 156 Unknown = UnknownClass() -
sage/structure/unique_representation.py
diff --git a/sage/structure/unique_representation.py b/sage/structure/unique_representation.py
a b 6 6 .. SEEALSO:: 7 7 8 8 :class:`sage.structure.factory.UniqueFactory` 9 10 AUTHORS: 11 12 - Nicolas M. Thiery (2008): Original version 13 - Simon A. King (2013-02): Separate cached and unique representation. 14 9 15 """ 10 16 #***************************************************************************** 11 17 # Copyright (C) 2008 Nicolas M. Thiery <nthiery at users.sf.net> 18 # Copyright (C) 2013 Simon A. King <simon.king at uni-jena.de> 12 19 # 13 20 # Distributed under the terms of the GNU General Public License (GPL) 14 21 # … … 24 31 25 32 from sage.misc.cachefunc import weak_cached_function 26 33 from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall 34 from sage.misc.fast_methods import WithRichCmpById 27 35 28 class UniqueRepresentation:36 class CachedRepresentation: 29 37 """ 30 Classes derived from UniqueRepresentation inherit a unique 31 representation behavior for their instances. 38 Classes derived from CachedRepresentation inherit a weak cache for their 39 instances. 40 41 .. NOTE:: 42 43 If this class is used as a base class, then instances are (weakly) 44 cached, according to the arguments used to create the instance. 45 Pickling is provided, of course by using the cache. 46 47 .. NOTE:: 48 49 Using this class, one can have arbitrary hash and comparison. 50 Hence, *unique* representation behaviour is *not* provided. 51 52 .. SEEALSO:: 53 54 :class:`UniqueRepresentation` 32 55 33 56 EXAMPLES: 34 57 35 The short story: to construct a class whose instances have a36 unique representation behavior one just has to do::58 Providing a class with a weak cache for the instances is easy: Just 59 inherit from :class:`CachedRepresentation`:: 37 60 38 sage: class MyClass(UniqueRepresentation): 61 sage: from sage.structure.unique_representation import CachedRepresentation 62 sage: class MyClass(CachedRepresentation): 39 63 ... # all the rest as usual 40 64 ... pass 41 65 42 Everything below is for the curious or for advanced usage.66 .. rubric:: What is cached representation? 43 67 44 .. rubric:: What is unique representation? 68 Instances of a class have a *cached representation behavior* when 69 several instances constructed with the same arguments share the 70 same memory representation. For example, calling twice 71 :: 45 72 46 Instances of a class have a *unique representation behavior* when 47 several instances constructed with the same arguments share the 48 same memory representation. For example, calling twice:: 73 sage: G = SymmetricGroup(6) 74 sage: H = SymmetricGroup(6) 49 75 50 sage: f = GF(7) 51 sage: g = GF(7) 52 53 to create the finite field of order 7 actually gives back the same 76 to create the symmetric group on six elements gives back the same 54 77 object:: 55 78 56 sage: f == g79 sage: G is H 57 80 True 58 sage: f is g 81 82 However, symmetric groups do not show the *unique* representation behaviour, 83 since they are equal to groups created in a totally different way:: 84 85 sage: G3 = G.subgroup([G((1,2,3,4,5,6)),G((1,2))]) 86 sage: G is G3 87 False 88 sage: type(G) == type(G3) 89 False 90 sage: G == G3 59 91 True 60 92 61 93 This is a standard design pattern. Besides saving memory, it 62 94 allows for sharing cached data (say representation theoretical 63 information about a group) as well as for further optimizations 64 (fast hashing, equality testing). This behaviour is typically 65 desirable for parents and categories. It can also be useful for 66 intensive computations where one wants to cache all the operations 67 on a small set of elements (say the multiplication table of a 68 small group), and access this cache as quickly as possible. 69 70 The :class:`UniqueRepresentation` and 71 :class:`~sage.structure.factory.UniqueFactory` classes 72 provide two alternative implementations of this design pattern. Both 73 implementations have their own merits. :class:`UniqueRepresentation` is 74 very easy to use: a class just needs to derive from it, or make sure some 75 of its super classes does. Also, it groups together the 76 class and the factory in a single gadget; in the example above, one would 77 want to do:: 78 79 sage: isinstance(f, GF) # todo: not implemented 80 True 81 82 but this does not work, because GF is only the factory. 83 84 On the other hand the :class:`UniqueRepresentation` class is more 85 intrusive, as it imposes a behavior (and a metaclass) to all the 86 subclasses. Its implementation is also more technical, which leads 87 to some subtleties. 88 89 EXAMPLES: 95 information about a group). 90 96 91 97 We start with a simple class whose constructor takes a single 92 98 value as argument (TODO: find a more meaningful example):: 93 99 94 sage: class MyClass( UniqueRepresentation):100 sage: class MyClass(CachedRepresentation): 95 101 ... def __init__(self, value): 96 102 ... self.value = value 97 ... 103 ... def __cmp__(self, other): 104 ... c = cmp(type(self),type(other)) 105 ... if c: return c 106 ... return cmp(self.value, other.value) 98 107 99 Two coexisting instances of MyClass created with the same 100 argument data are guaranteed to share the same identity. Since 101 trac ticket #12215, this is only the case if there is some 102 strong reference to the returned instance, since otherwise 103 it may be garbage collected:: 108 Two coexisting instances of ``MyClass`` created with the same argument data 109 are guaranteed to share the same identity. Since :trac:`12215`, this is 110 only the case if there is some strong reference to the returned instance, 111 since otherwise it may be garbage collected:: 104 112 105 113 sage: x = MyClass(1) 106 114 sage: y = MyClass(1) … … 120 128 sage: x.value, y.value 121 129 (1, 1) 122 130 123 Unless overridden by the derived class, equality testing is 124 implemented by comparing identities, which is as fast as it can get:: 125 126 sage: x == y 127 True 128 sage: z = MyClass(2) 129 sage: x == z, x is z 130 (False, False) 131 132 Similarly, the identity is used as hash function, which is also as 133 fast as it can get. However this means that the hash function may 134 change in between Sage sessions, or even within the same Sage 135 session (see below). Subclasses should overload :meth:`__hash__ <object.__hash__>` 136 if this could be a problem. 137 138 139 The arguments can consist of any combination of positional or 140 keyword arguments, as taken by a usual 141 :meth:`__init__ <object.__init__>` 131 The arguments can consist of any combination of positional or keyword 132 arguments, as taken by a usual :meth:`__init__ <object.__init__>` 142 133 function. However, all values passed in should be hashable:: 143 134 144 135 sage: MyClass(value = [1,2,3]) … … 153 144 how to achieve this; it takes as argument any iterable, and 154 145 canonicalizes it into a tuple (which is hashable!):: 155 146 156 sage: class MyClass2( UniqueRepresentation):147 sage: class MyClass2(CachedRepresentation): 157 148 ... @staticmethod 158 149 ... def __classcall__(cls, iterable): 159 150 ... t = tuple(iterable) … … 174 165 values for some of its parameters. Alas, the obvious 175 166 implementation does not work:: 176 167 177 sage: class MyClass3( UniqueRepresentation):168 sage: class MyClass3(CachedRepresentation): 178 169 ... def __init__(self, value = 3): 179 170 ... self.value = value 180 171 ... … … 194 185 sage: MyClass3(3) is MyClass3() 195 186 True 196 187 197 A bit of explanation is in order. First, the call 198 ``MyClass2([1,2,3])`` triggers a call to 199 ``MyClass2.__classcall__(MyClass2, [1,2,3])``. This is an extension of 200 the standard Python behavior, needed by :class:`UniqueRepresentation`, 201 and implemented by the 188 A bit of explanation is in order. First, the call ``MyClass2([1,2,3])`` 189 triggers a call to ``MyClass2.__classcall__(MyClass2, [1,2,3])``. This is 190 an extension of the standard Python behavior, needed by 191 :class:`CachedRepresentation`, and implemented by the 202 192 :class:`~sage.misc.classcall_metaclass.ClasscallMetaclass`. Then, 203 193 ``MyClass2.__classcall__`` does the desired transformations on the 204 arguments. Finally, it uses ``super`` to call the default 205 implementation of ``__classcall__`` provided by206 :class:`UniqueRepresentation`. This one in turn handles the caching207 and, if needed, constructs and initializes a new object in the208 class using :meth:`__new__<object.__new__>` and:meth:`__init__<object.__init__>` as usual.194 arguments. Finally, it uses ``super`` to call the default implementation 195 of ``__classcall__`` provided by :class:`CachedRepresentation`. This one 196 in turn handles the caching and, if needed, constructs and initializes a 197 new object in the class using :meth:`__new__<object.__new__>` and 198 :meth:`__init__<object.__init__>` as usual. 209 199 210 200 Constraints: 211 201 … … 213 203 214 204 - the preprocessing on the arguments should be 215 205 idempotent. Namely, If ``MyClass2.__classcall__`` calls 216 `` UniqueRepresentation.__classcall__(<some_arguments>)``, then217 it should accept <some_arguments>as its own input, and pass it218 down unmodified to :meth:` UniqueRepresentation.__classcall__`.206 ``CachedRepresentation.__classcall__(<some_arguments>)``, then 207 it should accept ``<some_arguments>`` as its own input, and pass it 208 down unmodified to :meth:`CachedRepresentation.__classcall__`. 219 209 - ``MyClass2.__classcall__`` should return the result of 220 :meth:` UniqueRepresentation.__classcall__` without modifying it.210 :meth:`CachedRepresentation.__classcall__` without modifying it. 221 211 222 Other than that ``MyClass2.__classcall__`` may play any tricks, 223 like acting as a Factory and returning objectfrom other classes.212 Other than that ``MyClass2.__classcall__`` may play any tricks, like 213 acting as a Factory and returning objects from other classes. 224 214 225 .. rubric:: Uniquerepresentation and mutability215 .. rubric:: Cached representation and mutability 226 216 227 :class:` UniqueRepresentation` is primarily intended for implementing217 :class:`CachedRepresentation` is primarily intended for implementing 228 218 objects which are (at least semantically) immutable. This is in 229 219 particular assumed by the default implementations of ``copy`` and 230 220 ``deepcopy``:: … … 235 225 sage: deepcopy(x) is x 236 226 True 237 227 238 Using :class:`UniqueRepresentation` on mutable objects may lead to 239 subtle behavior:: 228 However, in contrast to :class:`UniqueRepresentation`, using 229 :class:`CachedRepresentation` allows for a comparison that is not by 230 identity:: 240 231 241 232 sage: t = MyClass(3) 242 233 sage: z = MyClass(2) 243 234 sage: t.value = 2 244 235 245 Now x and z have the same data structure, but are not considered 246 as equal:: 236 Now x and z are non-identical, but equal:: 247 237 248 238 sage: t.value == z.value 249 239 True 250 240 sage: t == z 241 True 242 sage: t is z 251 243 False 252 244 253 .. rubric:: More on uniquerepresentation and identity245 .. rubric:: More on cached representation and identity 254 246 255 :class:` UniqueRepresentation` is implemented by meanof a cache. This256 cache uses weak references so that, when all other references to,257 say, ``MyClass(1)`` have been deleted, the instance is actually258 deleted from memory. A later call to ``MyClass(1)`` reconstructs the259 instance fromscratch, *most likely with a different id*.247 :class:`CachedRepresentation` is implemented by means of a cache. This 248 cache uses weak references. Hence, when all other references to, say, 249 ``MyClass(1)`` have been deleted, the instance is actually deleted from 250 memory. A later call to ``MyClass(1)`` reconstructs the instance from 251 scratch, *most likely with a different id*. 260 252 261 TODO: add an example illustrating this behavior253 .. TODO:: 262 254 255 add an example illustrating this behavior 263 256 264 .. rubric:: Unique representation and pickling265 257 266 The default Python pickling implementation (by reconstructing an 267 object from its class and dictionary, see "The pickle protocol" in 268 the Python Library Reference) does not preserves unique 269 representation, as Python has no chance to know whether and where 270 the same object already exists. 258 .. rubric:: Cached representation and pickling 271 259 272 :class:`UniqueRepresentation` tries to ensure appropriate pickling by 273 implementing a :meth:`__reduce__ <object.__reduce__>` method returning the arguments 274 passed to the constructor:: 260 The default Python pickling implementation (by reconstructing an object 261 from its class and dictionary, see "The pickle protocol" in the Python 262 Library Reference) does not preserves cached representation, as Python has 263 no chance to know whether and where the same object already exists. 264 265 :class:`CachedRepresentation` tries to ensure appropriate pickling by 266 implementing a :meth:`__reduce__ <object.__reduce__>` method returning the 267 arguments passed to the constructor:: 275 268 276 269 sage: import __main__ # Fake MyClass being defined in a python module 277 270 sage: __main__.MyClass = MyClass … … 279 272 sage: loads(dumps(x)) is x 280 273 True 281 274 282 :class:` UniqueRepresentation` uses the :meth:`__reduce__275 :class:`CachedRepresentation` uses the :meth:`__reduce__ 283 276 <object.__reduce__>` pickle protocol rather than :meth:`__getnewargs__ 284 277 <object.__getnewargs__>` because the later does not handle keyword 285 278 arguments:: … … 292 285 293 286 .. warning:: 294 287 295 the default implementation of :meth:`__reduce__ <object.__reduce__>`296 in :class:` UniqueRepresentation` requires to store the constructor's288 The default implementation of :meth:`__reduce__ <object.__reduce__>` 289 in :class:`CachedRepresentation` requires to store the constructor's 297 290 arguments in the instance dictionary upon construction:: 298 291 299 292 sage: x.__dict__ … … 318 311 sage: x.__dict__ 319 312 {'value': 1} 320 313 321 .. rubric:: Migrating classes to `` UniqueRepresentation`` and unpickling314 .. rubric:: Migrating classes to ``CachedRepresentation`` and unpickling 322 315 323 We check that, when migrating a class to :class:` UniqueRepresentation`,316 We check that, when migrating a class to :class:`CachedRepresentation`, 324 317 older pickle can still be reasonably unpickled. Let us create a 325 318 (new style) class, and pickle one of its instances:: 326 319 … … 337 330 sage: y.value 338 331 1 339 332 340 Now, we upgrade the class to derive from :class:`UniqueRepresentation`:: 333 Now, we upgrade the class to derive from :class:`UniqueRepresentation`, 334 which inherits from :class:`CachedRepresentation`:: 341 335 342 336 sage: class MyClass4(UniqueRepresentation, object): 343 337 ... def __init__(self, value): … … 392 386 sage: y.value # todo: not implemented 393 387 1 394 388 395 396 397 389 .. rubric:: Rationale for the current implementation 398 390 399 :class:` UniqueRepresentation` and derived classes use the391 :class:`CachedRepresentation` and derived classes use the 400 392 :class:`~sage.misc.classcall_metaclass.ClasscallMetaclass` 401 393 of the standard Python type. The following example explains why. 402 394 403 395 We define a variant of ``MyClass`` where the calls to 404 396 :meth:`__init__<object.__init__>` are traced:: 405 397 406 sage: class MyClass( UniqueRepresentation):398 sage: class MyClass(CachedRepresentation): 407 399 ... def __init__(self, value): 408 400 ... print "initializing object" 409 401 ... self.value = value … … 431 423 unprocessed arguments will be passed down to 432 424 :meth:`__init__<object.__init__>`. 433 425 434 .. rubric:: Mixing super types and super classes435 436 TESTS:437 438 For the record, this test did fail with previous implementation439 attempts::440 441 sage: class bla(UniqueRepresentation, SageObject):442 ... pass443 ...444 sage: b = bla()445 446 426 """ 447 448 427 __metaclass__ = ClasscallMetaclass 449 428 450 429 _included_private_doc_ = ["__classcall__"] … … 454 433 """ 455 434 Constructs a new object of this class or reuse an existing one. 456 435 457 See also :class:`UniqueRepresentation` for a discussion. 436 See also :class:`CachedRepresentation` and 437 :class:`UniqueRepresentation` for a discussion. 458 438 459 439 EXAMPLES:: 460 440 461 441 sage: x = UniqueRepresentation() 462 442 sage: y = UniqueRepresentation() 463 sage: x is y 443 sage: x is y # indirect doctest 464 444 True 445 465 446 """ 466 447 instance = typecall(cls, *args, **options) 467 448 assert isinstance( instance, cls ) 468 if instance.__class__.__reduce__ == UniqueRepresentation.__reduce__:449 if instance.__class__.__reduce__ == CachedRepresentation.__reduce__: 469 450 instance._reduction = (cls, args, options) 470 451 return instance 471 452 472 # Should be cythoned473 def __eq__(self, other):474 """475 Test if ``self`` and ``other` are equal by comparing their476 identity.477 478 See also :class:`UniqueRepresentation` for a discussion.479 480 EXAMPLES::481 482 sage: x = UniqueRepresentation()483 sage: y = UniqueRepresentation()484 sage: x == y485 True486 sage: x is y487 True488 sage: x == 3489 False490 491 TESTS::492 493 sage: class bla(UniqueRepresentation, SageObject):494 ... def __init__(self, i): pass495 sage: b1 = bla(1); b2 = bla(2)496 sage: b1 == b1497 True498 sage: b1 == b2499 False500 """501 return self is other502 503 # Should be cythoned504 def __ne__(self, other):505 """506 Test if ``self`` and ``other` are different by comparing their507 identity.508 509 See also :class:`UniqueRepresentation` for a discussion.510 511 EXAMPLES::512 513 sage: x = UniqueRepresentation()514 sage: y = UniqueRepresentation()515 sage: x != y516 False517 518 TESTS::519 520 sage: class bla(UniqueRepresentation, SageObject):521 ... def __init__(self, i): pass522 sage: b1 = bla(1); b2 = bla(2)523 sage: b1 != b1524 False525 sage: b1 != b2526 True527 """528 return self is not other529 530 # Should be cythoned531 def __hash__(self):532 """533 Returns the hash value of ``self``.534 535 See also :class:`UniqueRepresentation` for a discussion.536 537 EXAMPLES::538 539 sage: x = UniqueRepresentation()540 sage: y = UniqueRepresentation()541 sage: hash(x) # random542 74153040543 sage: type(hash(x))544 <type 'int'>545 sage: hash(x) == hash(y)546 True547 sage: class bla(UniqueRepresentation, SageObject): pass548 sage: x = bla(); hx = hash(x)549 sage: x.rename("toto")550 sage: hx == hash(x)551 True552 """553 return id(self)554 555 453 def __reduce__(self): 556 454 """ 557 455 Returns the argument that have been passed to :meth:`__new__<object.__new__>` 558 456 to construct this object, as per the pickle protocol. 559 457 560 See also :class:`UniqueRepresentation` for a discussion. 458 See also :class:`CachedRepresentation` and 459 :class:`UniqueRepresentation` for a discussion. 561 460 562 461 EXAMPLES:: 563 462 564 463 sage: x = UniqueRepresentation() 565 sage: x.__reduce__() 464 sage: x.__reduce__() # indirect doctest 566 465 (<function unreduce at ...>, (<class 'sage.structure.unique_representation.UniqueRepresentation'>, (), {})) 567 466 """ 568 467 return (unreduce, self._reduction) … … 576 475 EXAMPLES:: 577 476 578 477 sage: x = UniqueRepresentation() 579 sage: x is copy(x) 478 sage: x is copy(x) # indirect doctest 580 479 True 581 480 """ 582 481 return self … … 591 490 592 491 sage: from copy import deepcopy 593 492 sage: x = UniqueRepresentation() 594 sage: x is deepcopy(x) 493 sage: x is deepcopy(x) # indirect doctest 595 494 True 596 495 """ 597 496 return self … … 603 502 sage: sage.structure.unique_representation.unreduce(Integer, (1,), {}) 604 503 1 605 504 606 Todo: should reuse something preexisting ... 505 .. TODO:: 506 507 should reuse something preexisting ... 508 607 509 """ 608 510 return cls(*args, **keywords) 511 512 513 class UniqueRepresentation(CachedRepresentation, WithRichCmpById): 514 """ 515 Classes derived from UniqueRepresentation inherit a unique 516 representation behavior for their instances. 517 518 EXAMPLES: 519 520 The short story: to construct a class whose instances have a 521 unique representation behavior one just has to do:: 522 523 sage: class MyClass(UniqueRepresentation): 524 ... # all the rest as usual 525 ... pass 526 527 Everything below is for the curious or for advanced usage. 528 529 .. rubric:: What is unique representation? 530 531 Instances of a class have a *unique representation behavior* when 532 instances evaluate equal if and only if they are identical (i.e., share 533 the same memory representation), if and only if they were created using 534 equal arguments. For example, calling twice:: 535 536 sage: f = GF(7) 537 sage: g = GF(7) 538 539 to create the finite field of order 7 actually gives back the same 540 object:: 541 542 sage: f == g 543 True 544 sage: f is g 545 True 546 547 This is a standard design pattern. It allows for sharing cached data (say 548 representation theoretical information about a group) as well as for very 549 fast hashing and equality testing. This behaviour is typically desirable 550 for parents and categories. It can also be useful for intensive 551 computations where one wants to cache all the operations on a small set of 552 elements (say the multiplication table of a small group), and access this 553 cache as quickly as possible. 554 555 The :class:`UniqueRepresentation` and 556 :class:`~sage.structure.factory.UniqueFactory` classes provide two 557 alternative implementations of this design pattern. Both implementations 558 have their own merits. :class:`UniqueRepresentation` is very easy to use: 559 a class just needs to derive from it, or make sure some of its super 560 classes does. Also, it groups together the class and the factory in a 561 single gadget; in the example above, one would want to do:: 562 563 sage: isinstance(f, GF) # todo: not implemented 564 True 565 566 but this does not work, because ``GF`` is only the factory. 567 568 On the other hand the :class:`UniqueRepresentation` class is more 569 intrusive, as it imposes a behavior (and a metaclass) to all the 570 subclasses. In particular, the unique representation behaviour is imposed 571 on *all* subclasses (unless the ``__classcall__`` method is overloaded and 572 not called in the subclass, which is not recommended). Its implementation 573 is also more technical, which leads to some subtleties. 574 575 EXAMPLES: 576 577 We start with a simple class whose constructor takes a single 578 value as argument (TODO: find a more meaningful example):: 579 580 sage: class MyClass(UniqueRepresentation): 581 ... def __init__(self, value): 582 ... self.value = value 583 ... def __cmp__(self, other): 584 ... c = cmp(type(self),type(other)) 585 ... if c: return c 586 ... print "custom cmp" 587 ... return cmp(self.value, other.value) 588 ... 589 590 Two coexisting instances of MyClass created with the same argument data 591 are guaranteed to share the same identity. Since :trac:`12215`, this is 592 only the case if there is some strong reference to the returned instance, 593 since otherwise it may be garbage collected:: 594 595 sage: x = MyClass(1) 596 sage: y = MyClass(1) 597 sage: x is y # There is a strong reference 598 True 599 sage: z = MyClass(2) 600 sage: x is z 601 False 602 603 In particular, modifying any one of them modifies the other 604 (reference effect):: 605 606 sage: x.value = 3 607 sage: x.value, y.value 608 (3, 3) 609 sage: y.value = 1 610 sage: x.value, y.value 611 (1, 1) 612 613 Rich comparison by identity is used when possible (hence, for ``==``, for 614 ``!=``, and for identical arguments in the case of ``<``, ``<=``, ``>=`` 615 and ``>``), which is as fast as it can get. Only if identity is not enough 616 to decide the answer of a comparison, the custom comparison is called:: 617 618 sage: x == y 619 True 620 sage: z = MyClass(2) 621 sage: x == z, x is z 622 (False, False) 623 sage: x <= x 624 True 625 sage: x != z 626 True 627 sage: x <= z 628 custom cmp 629 True 630 sage: x > z 631 custom cmp 632 False 633 634 A hash function equivalent to :meth:`object.__hash__` is used, which is 635 compatible with comparison by identity. However this means that the hash 636 function may change in between Sage sessions, or even within the same Sage 637 session. 638 :: 639 640 sage: hash(x) == object.__hash__(x) 641 True 642 643 .. WARNING:: 644 645 It is possible to inherit from 646 :class:`~sage.structure.unique_representation.UniqueRepresentation` 647 and then overload comparison in a way that destroys the unique 648 representation property. We strongly recommend against it! You should 649 use :class:`~sage.structure.unique_representation.CachedRepresentation` 650 instead. 651 652 .. rubric:: Mixing super types and super classes 653 654 TESTS: 655 656 For the record, this test did fail with previous implementation 657 attempts:: 658 659 sage: class bla(UniqueRepresentation, SageObject): 660 ... pass 661 ... 662 sage: b = bla() 663 664 """ -
sage/tests/cython.pyx
diff --git a/sage/tests/cython.pyx b/sage/tests/cython.pyx
a b 11 11 # http://www.gnu.org/licenses/ 12 12 #***************************************************************************** 13 13 14 from sage. categories.category_singletoncimport FastHashable_class14 from sage.misc.fast_methods cimport FastHashable_class 15 15 cdef class ClassWithLargeHash(FastHashable_class): 16 16 """ 17 17 This class tests against a bug with :class:`FastHashable_class`