Ticket #14054: trac14054_fast_methods-5.8.patch

File trac14054_fast_methods-5.8.patch, 50.8 KB (added by SimonKing, 7 years ago)

Separate cache and uniqueness. Rel #6495 and #14040

  • doc/en/reference/misc/index.rst

    # HG changeset patch
    # User Simon King <simon.king@uni-jena.de>
    # Date 1361268866 -3600
    # Node ID cf895aa83cb358d94b774cb854fa9838dc2c1ff5
    # Parent  40a43716b9b84b27e24c6a0c1d85a28da6700a3a
    #14054: Separate CachedRepresentation from UniqueRepresentation.
    
    diff --git a/doc/en/reference/misc/index.rst b/doc/en/reference/misc/index.rst
    a b  
    4444   sage/misc/nested_class
    4545   sage/misc/nested_class_test
    4646   sage/misc/classcall_metaclass
     47   sage/misc/fast_methods
    4748   sage/misc/sage_unittest
    4849   sage/misc/randstate
    4950   sage/misc/cython
  • doc/en/thematic_tutorials/coercion_and_categories.rst

    diff --git a/doc/en/thematic_tutorials/coercion_and_categories.rst b/doc/en/thematic_tutorials/coercion_and_categories.rst
    a b  
    404404
    405405    sage: import inspect
    406406    sage: len([s for s in dir(MS1) if inspect.ismethod(getattr(MS1,s,None))])
    407     54
     407    51
    408408    sage: len([s for s in dir(MS2) if inspect.ismethod(getattr(MS2,s,None))])
    409     76
     409    73
    410410    sage: MS1.__class__ is MS2.__class__
    411411    True
    412412
  • module_list.py

    diff --git a/module_list.py b/module_list.py
    a b  
    11971197    Extension('sage.misc.classcall_metaclass',
    11981198              sources = ['sage/misc/classcall_metaclass.pyx']),
    11991199
     1200    Extension('sage.misc.fast_methods',
     1201              sources = ['sage/misc/fast_methods.pyx']),
     1202
    12001203    Extension('sage.misc.binary_tree',
    12011204              sources = ['sage/misc/binary_tree.pyx']),
    12021205   
  • 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 _hash
    3 
    41cdef class Category_contains_method_by_parent_class:
    52    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  
    8282            except AttributeError:
    8383                return False
    8484
    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):
     85class Category_singleton(Category):
    11286    """
    11387    A base class for implementing singleton category
    11488
     
    274248            sage: MySubStuff()
    275249            Category of my stuff
    276250        """
    277         cdef FastHashable_class obj
    278251        if cls.__mro__[1] is not Category_singleton:
    279252            # Actually this type error is invisible. But it makes sure that
    280253            # the __classcall__ for Category_singleton is not overridden
    281254            # when someone is calling it.
    282255            raise TypeError, "%s is not a direct subclass of %s"%(cls,Category_singleton)
    283256        obj = UniqueRepresentation.__classcall__(cls)
    284         obj._hash = <Py_ssize_t><void *>cls
    285257        return ConstantFunction(obj)
    286258
    287 #    @lazy_class_attribute
    288 #    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 doctest
    295 #            True
    296 #
    297 #        """
    298 #        return ConstantFunction(id(cls))
    299 
    300259    @lazy_class_attribute
    301260    def __contains__(cls):
    302261        """
  • sage/categories/primer.py

    diff --git a/sage/categories/primer.py b/sage/categories/primer.py
    a b  
    427427    [<class 'sage.categories.examples.finite_semigroups.LeftRegularBand_with_category'>,
    428428     <class 'sage.categories.examples.finite_semigroups.LeftRegularBand'>,
    429429     <class 'sage.structure.unique_representation.UniqueRepresentation'>,
     430     <class 'sage.structure.unique_representation.CachedRepresentation'>,
     431     <type 'sage.misc.fast_methods.WithEqualityById'>,
    430432     <type 'sage.structure.parent.Parent'>,
    431433     <type 'sage.structure.category_object.CategoryObject'>,
    432434     <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  
    8888        <class 'sage.categories.examples.sets_cat.PrimeNumbers_Inherits'>
    8989        <class 'sage.categories.examples.sets_cat.PrimeNumbers_Abstract'>
    9090        <class 'sage.structure.unique_representation.UniqueRepresentation'>
     91        <class 'sage.structure.unique_representation.CachedRepresentation'>
     92        <type 'sage.misc.fast_methods.WithEqualityById'>
    9193        <type 'sage.structure.parent.Parent'>
    9294        <type 'sage.structure.category_object.CategoryObject'>
    9395        <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  
    255255            False
    256256            sage: F1.an_element() == F1.an_element()
    257257            True
    258 
    259         Currently, if ``self`` and ``other`` do not have the same
    260         parent, coercions are attempted::
     258            sage: F1.an_element() == None
     259            False
     260
     261        .. TODO::
     262
     263            Currently, if ``self`` and ``other`` do not have the same parent,
     264            seemingly equal elements do not evaluate equal, since conversions
     265            between different modules have not been established.
     266
     267        ::
    261268
    262269            sage: F1.zero() == 0
    263270            True
     271            sage: F1(0)
     272            0
     273
     274        ::
     275
    264276            sage: F1.zero() == F2.zero()
    265277            False
    266             sage: F1.an_element() == None
    267             False
    268 
     278            sage: F1(F2.zero())
     279            Traceback (most recent call last):
     280            ...
     281            TypeError: do not know how to make x (= 0) an element of self (=Free module generated by {1, 2, 3} over Rational Field)
    269282            sage: F = AlgebrasWithBasis(QQ).example()
    270283            sage: F.one() == 1
    271284            True
     
    10001013        sage: F1 is F
    10011014        True
    10021015
    1003     The constructed free module depends on the order of the basis and
    1004     on the other parameters, like the prefix::
     1016    The identity of the constructed free module depends on the order of the
     1017    basis and on the other parameters, like the prefix. Note that :class:`CombinatorialFreeModule` is
     1018    a :class:`~sage.structure.unique_representation.UniqueRepresentation`. Hence,
     1019    two combinatorial free modules evaluate equal if and only if they are
     1020    identical::
    10051021
    10061022        sage: F1 = CombinatorialFreeModule(QQ, (1,2,3,4))
    10071023        sage: F1 is F
     
    10131029        sage: F2 == F
    10141030        False
    10151031
    1016     Because of this, if you create a free module with certain
    1017     parameters and then modify its prefix or other print options, this
    1018     affects all modules which were defined using the same parameters::
     1032    Because of this, if you create a free module with certain parameters and
     1033    then modify its prefix or other print options, this affects all modules
     1034    which were defined using the same parameters.
     1035    ::
    10191036
    10201037        sage: F2.print_options(prefix='x')
    10211038        sage: F2.prefix()
     
    10771094        sage: e[(1,2)] - 3 * e[(3,4)]
    10781095        (1, 2) - 3*(3, 4)
    10791096
     1097    TESTS:
     1098
     1099    Before :trac:`14054`, combinatorial free modules violated the unique
     1100    parent condition. That caused a problem. The tensor product construction
     1101    involves maps, but maps check that their domain and the parent of a
     1102    to-be-mapped element are identical (not just equal). However, the tensor
     1103    product was cached by a :class:`~sage.misc.cachefunc.cached_method`, which
     1104    involves comparison by equality (not identity). Hence, the last line of
     1105    the following example used to fail with an assertion error::
     1106
     1107        sage: F = CombinatorialFreeModule(ZZ, [1,2,3], prefix="F")
     1108        sage: G = CombinatorialFreeModule(ZZ, [1,2,3,4], prefix="G")
     1109        sage: f =   F.monomial(1) + 2 * F.monomial(2)
     1110        sage: g = 2*G.monomial(3) +     G.monomial(4)
     1111        sage: tensor([f, g])
     1112        2*F[1] # G[3] + F[1] # G[4] + 4*F[2] # G[3] + 2*F[2] # G[4]
     1113        sage: F = CombinatorialFreeModule(ZZ, [1,2,3], prefix='x')
     1114        sage: G = CombinatorialFreeModule(ZZ, [1,2,3,4], prefix='y')
     1115        sage: f =   F.monomial(1) + 2 * F.monomial(2)
     1116        sage: g = 2*G.monomial(3) +     G.monomial(4)
     1117        sage: tensor([f, g])
     1118        2*x[1] # y[3] + x[1] # y[4] + 4*x[2] # y[3] + 2*x[2] # y[4]
     1119
    10801120    """
    10811121
    10821122    @staticmethod
     
    12211261        # self._repr_option_bracket.  Future users might consider
    12221262        # using 'bracket' instead of _repr_option_bracket.
    12231263
    1224         # ignore the optional 'key' since it only affects UniqueRepresentation
     1264        # ignore the optional 'key' since it only affects CachedRepresentation
    12251265        kwds.pop('key', None)
    12261266        self.print_options(**kwds)
    12271267
     
    23282368                sage: T.print_options(tensor_symbol= ' @ ')  # note the spaces
    23292369                sage: T # indirect doctest
    23302370                F @ G
     2371
     2372            To avoid a side\--effect on another doctest, we revert the change::
     2373
     2374                sage: T.print_options(tensor_symbol= ' # ')
    23312375            """
    23322376            from sage.categories.tensor import tensor
    23332377            if hasattr(self, "_print_options"):
     
    24122456                sage: f =   F.monomial(1) + 2 * F.monomial(2)
    24132457                sage: g = 2*G.monomial(3) +     G.monomial(4)
    24142458                sage: h =   H.monomial(5) +     H.monomial(6)
    2415 
    24162459                sage: FG  = tensor([F, G   ])
    24172460                sage: phi_fg = FG.tensor_constructor((F, G))
    24182461                sage: phi_fg(f,g)
  • 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  
    171171        """
    172172        EXAMPLES::
    173173
    174             sage: hash(CartanType(['A',3]).dynkin_diagram()) # indirect doctest
    175             286820813001824631     # 64-bit
    176             -2127980169            # 32-bit
     174            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
    177177        """
    178178        # Should assert for immutability!
    179179
  • sage/combinat/symmetric_group_algebra.py

    diff --git a/sage/combinat/symmetric_group_algebra.py b/sage/combinat/symmetric_group_algebra.py
    a b  
    9898        TESTS::
    9999       
    100100            sage: QS3 = SymmetricGroupAlgebra(QQ, 3)
    101             sage: QS3 == loads(dumps(QS3))
     101            sage: QS3 is loads(dumps(QS3))
    102102            True
    103103        """
    104104        self.n = n
  • sage/ext/python_rich_object.pxi

    diff --git a/sage/ext/python_rich_object.pxi b/sage/ext/python_rich_object.pxi
    a b  
    3131        newfunc tp_new
    3232        freefunc tp_free
    3333        destructor tp_dealloc
     34        hashfunc tp_hash
     35        richcmpfunc tp_richcompare
    3436       
    3537        #sizeof(Object)
    3638        Py_ssize_t tp_basicsize
  • sage/graphs/isgci.py

    diff --git a/sage/graphs/isgci.py b/sage/graphs/isgci.py
    a b  
    328328"""
    329329
    330330from sage.structure.sage_object import SageObject
    331 from sage.structure.unique_representation import UniqueRepresentation
     331from sage.structure.unique_representation import CachedRepresentation, UniqueRepresentation
    332332from sage.misc.unknown import Unknown
    333333from sage.misc.misc import SAGE_SHARE
    334334
     
    341341
    342342_XML_FILE = "isgci_sage.xml"
    343343
    344 class GraphClass(SageObject, UniqueRepresentation):
     344class GraphClass(SageObject, CachedRepresentation):
    345345    r"""
    346346    An instance of this class represents a Graph Class, matching some entry in
    347347    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  
    8989from sage.rings.arith import factor
    9090from sage.groups.abelian_gps.abelian_group import AbelianGroup
    9191from sage.misc.functional import is_even
    92 from sage.misc.cachefunc import cached_method
     92from sage.misc.cachefunc import cached_method, weak_cached_function
     93from sage.misc.classcall_metaclass import typecall
    9394from sage.misc.superseded import deprecated_function_alias
    9495from sage.groups.perm_gps.permgroup import PermutationGroup_generic
    9596from sage.groups.perm_gps.permgroup_element import PermutationGroupElement
    96 from sage.structure.unique_representation import UniqueRepresentation
     97from sage.structure.unique_representation import CachedRepresentation
    9798from sage.structure.parent import Parent
    9899from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
    99100from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
     
    103104from sage.sets.family import Family
    104105from sage.sets.primes import Primes
    105106
    106 class PermutationGroup_unique(UniqueRepresentation, PermutationGroup_generic):
    107     @staticmethod
     107class 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
    108120    def __classcall__(cls, *args, **kwds):
    109121        """
    110122        This makes sure that domain is a FiniteEnumeratedSet before it gets passed
     
    124136 
    125137    def __eq__(self, other):
    126138        """
    127         Overrides the default equality testing provided by
    128         UniqueRepresentation by forcing a call to :meth:.`__cmp__`.
    129 
    130139        EXAMPLES::
    131140
    132141            sage: G = SymmetricGroup(6)
    133142            sage: G3 = G.subgroup([G((1,2,3,4,5,6)),G((1,2))])
    134143            sage: G == G3
    135144            True
     145
     146        .. WARNING::
     147
     148            The hash currently is broken for this comparison.
    136149        """
    137150        return self.__cmp__(other) == 0
    138151
     
    16311644        """
    16321645        return isinstance(G,TransitiveGroup)
    16331646
    1634 class TransitiveGroupsOfDegree(UniqueRepresentation, Parent):
     1647class TransitiveGroupsOfDegree(CachedRepresentation, Parent):
    16351648    """
    16361649    The set of all transitive groups of a given (small) degree up to isomorphisms.
    16371650
     
    20282041        """
    20292042        return isinstance(G,PrimitiveGroup)
    20302043
    2031 class PrimitiveGroupsOfDegree(UniqueRepresentation, Parent):
     2044class PrimitiveGroupsOfDegree(CachedRepresentation, Parent):
    20322045    """
    20332046    The set of all primitive groups of a given degree up to isomorphisms.
    20342047
     
    26662679
    26672680        """
    26682681        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
    - +  
     1cdef class FastHashable_class:
     2    cdef Py_ssize_t _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"""
     2Fast methods via Cython
     3
     4This module provides extension classes with useful methods of cython speed,
     5that 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
     14AUTHOR:
     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
     35include "../ext/python_rich_object.pxi"
     36include "../ext/python_bool.pxi"
     37include "../ext/python_ref.pxi"
     38
     39cdef int SIZEOF_VOID_P_SHIFT = 8*sizeof(void *) - 4
     40
     41cdef 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
     217cdef 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  
    153153        else:
    154154            raise ValueError, "Unable to compare %s with %s"%(self, other)
    155155
    156     def __eq__(self, other):
    157         """
    158         TESTS::
    159 
    160             sage: Unknown == Unknown
    161             True
    162             sage: Unknown == None
    163             False
    164         """
    165         return self is other
    166 
    167     def __ne__(self, other):
    168         """
    169         TESTS::
    170 
    171             sage: Unknown != Unknown
    172             False
    173             sage: Unknown != None
    174             True
    175         """
    176         return self is not other
    177 
    178156Unknown = UnknownClass()
  • sage/structure/unique_representation.py

    diff --git a/sage/structure/unique_representation.py b/sage/structure/unique_representation.py
    a b  
    66.. SEEALSO::
    77
    88   :class:`sage.structure.factory.UniqueFactory`
     9
     10AUTHORS:
     11
     12- Nicolas M. Thiery (2008): Original version
     13- Simon A. King (2013-02): Separate cached and unique representation.
     14
    915"""
    1016#*****************************************************************************
    1117#  Copyright (C) 2008 Nicolas M. Thiery <nthiery at users.sf.net>
     18#  Copyright (C) 2013 Simon A. King <simon.king at uni-jena.de>
    1219#
    1320#  Distributed under the terms of the GNU General Public License (GPL)
    1421#
     
    2431
    2532from sage.misc.cachefunc import weak_cached_function
    2633from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall
     34from sage.misc.fast_methods import WithEqualityById
    2735
    28 class UniqueRepresentation:
     36class CachedRepresentation:
    2937    """
    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`
    3255
    3356    EXAMPLES:
    3457
    35     The short story: to construct a class whose instances have a
    36     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`::
    3760
    38         sage: class MyClass(UniqueRepresentation):
     61        sage: from sage.structure.unique_representation import CachedRepresentation
     62        sage: class MyClass(CachedRepresentation):
    3963        ...       # all the rest as usual
    4064        ...       pass
    4165
    42     Everything below is for the curious or for advanced usage.
     66    .. rubric:: What is cached representation?
    4367
    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    ::
    4572
    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)
    4975
    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
    5477    object::
    5578
    56         sage: f == g
     79        sage: G is H
    5780        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
    5991        True
    6092
    6193    This is a standard design pattern. Besides saving memory, it
    6294    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).
    9096
    9197    We start with a simple class whose constructor takes a single
    9298    value as argument (TODO: find a more meaningful example)::
    9399
    94         sage: class MyClass(UniqueRepresentation):
     100        sage: class MyClass(CachedRepresentation):
    95101        ...       def __init__(self, value):
    96102        ...           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)
    98107
    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::
    104112
    105113        sage: x = MyClass(1)
    106114        sage: y = MyClass(1)
     
    120128        sage: x.value, y.value
    121129        (1, 1)
    122130
    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__>`
    142133    function. However, all values passed in should be hashable::
    143134
    144135        sage: MyClass(value = [1,2,3])
     
    153144    how to achieve this; it takes as argument any iterable, and
    154145    canonicalizes it into a tuple (which is hashable!)::
    155146
    156         sage: class MyClass2(UniqueRepresentation):
     147        sage: class MyClass2(CachedRepresentation):
    157148        ...       @staticmethod
    158149        ...       def __classcall__(cls, iterable):
    159150        ...           t = tuple(iterable)
     
    174165    values for some of its parameters. Alas, the obvious
    175166    implementation does not work::
    176167
    177         sage: class MyClass3(UniqueRepresentation):
     168        sage: class MyClass3(CachedRepresentation):
    178169        ...       def __init__(self, value = 3):
    179170        ...           self.value = value
    180171        ...
     
    194185        sage: MyClass3(3) is MyClass3()
    195186        True
    196187
    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
    202192    :class:`~sage.misc.classcall_metaclass.ClasscallMetaclass`. Then,
    203193    ``MyClass2.__classcall__`` does the desired transformations on the
    204     arguments. Finally, it uses ``super`` to call the default
    205     implementation of ``__classcall__`` provided by
    206     :class:`UniqueRepresentation`. This one in turn handles the caching
    207     and, if needed, constructs and initializes a new object in the
    208     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.
    209199
    210200    Constraints:
    211201
     
    213203
    214204     - the preprocessing on the arguments should be
    215205       idempotent. Namely, If ``MyClass2.__classcall__`` calls
    216        ``UniqueRepresentation.__classcall__(<some_arguments>)``, then
    217        it should accept <some_arguments> as its own input, and pass it
    218        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__`.
    219209     - ``MyClass2.__classcall__`` should return the result of
    220        :meth:`UniqueRepresentation.__classcall__` without modifying it.
     210       :meth:`CachedRepresentation.__classcall__` without modifying it.
    221211
    222     Other than that ``MyClass2.__classcall__`` may play any tricks,
    223     like acting as a Factory and returning object from other classes.
     212    Other than that ``MyClass2.__classcall__`` may play any tricks, like
     213    acting as a Factory and returning objects from other classes.
    224214
    225     .. rubric:: Unique representation and mutability
     215    .. rubric:: Cached representation and mutability
    226216
    227     :class:`UniqueRepresentation` is primarily intended for implementing
     217    :class:`CachedRepresentation` is primarily intended for implementing
    228218    objects which are (at least semantically) immutable. This is in
    229219    particular assumed by the default implementations of ``copy`` and
    230220    ``deepcopy``::
     
    235225        sage: deepcopy(x) is x
    236226        True
    237227
    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::
    240231
    241232        sage: t = MyClass(3)
    242233        sage: z = MyClass(2)
    243234        sage: t.value = 2
    244235
    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::
    247237
    248238        sage: t.value == z.value
    249239        True
    250240        sage: t == z
     241        True
     242        sage: t is z
    251243        False
    252244
    253     .. rubric:: More on unique representation and identity
     245    .. rubric:: More on cached representation and identity
    254246
    255     :class:`UniqueRepresentation` is implemented by mean of a cache. This
    256     cache uses weak references so that, when all other references to,
    257     say, ``MyClass(1)`` have been deleted, the instance is actually
    258     deleted from memory. A later call to ``MyClass(1)`` reconstructs the
    259     instance from scratch, *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*.
    260252
    261     TODO: add an example illustrating this behavior
     253    .. TODO::
    262254
     255        add an example illustrating this behavior
    263256
    264     .. rubric:: Unique representation and pickling
    265257
    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
    271259
    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::
    275268
    276269        sage: import __main__             # Fake MyClass being defined in a python module
    277270        sage: __main__.MyClass = MyClass
     
    279272        sage: loads(dumps(x)) is x
    280273        True
    281274
    282     :class:`UniqueRepresentation` uses the :meth:`__reduce__
     275    :class:`CachedRepresentation` uses the :meth:`__reduce__
    283276    <object.__reduce__>` pickle protocol rather than :meth:`__getnewargs__
    284277    <object.__getnewargs__>` because the later does not handle keyword
    285278    arguments::
     
    292285
    293286    .. warning::
    294287
    295         the default implementation of :meth:`__reduce__ <object.__reduce__>`
    296         in :class:`UniqueRepresentation` requires to store the constructor's
     288        The default implementation of :meth:`__reduce__ <object.__reduce__>`
     289        in :class:`CachedRepresentation` requires to store the constructor's
    297290        arguments in the instance dictionary upon construction::
    298291
    299292            sage: x.__dict__
     
    318311        sage: x.__dict__
    319312        {'value': 1}
    320313
    321     .. rubric:: Migrating classes to ``UniqueRepresentation`` and unpickling
     314    .. rubric:: Migrating classes to ``CachedRepresentation`` and unpickling
    322315
    323     We check that, when migrating a class to :class:`UniqueRepresentation`,
     316    We check that, when migrating a class to :class:`CachedRepresentation`,
    324317    older pickle can still be reasonably unpickled. Let us create a
    325318    (new style) class, and pickle one of its instances::
    326319
     
    337330        sage: y.value
    338331        1
    339332
    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`::
    341335
    342336        sage: class MyClass4(UniqueRepresentation, object):
    343337        ...       def __init__(self, value):
     
    392386        sage: y.value            # todo: not implemented
    393387        1
    394388
    395 
    396 
    397389    .. rubric:: Rationale for the current implementation
    398390
    399     :class:`UniqueRepresentation` and derived classes use the
     391    :class:`CachedRepresentation` and derived classes use the
    400392    :class:`~sage.misc.classcall_metaclass.ClasscallMetaclass`
    401393    of the standard Python type. The following example explains why.
    402394
    403395    We define a variant of ``MyClass`` where the calls to
    404396    :meth:`__init__<object.__init__>` are traced::
    405397
    406         sage: class MyClass(UniqueRepresentation):
     398        sage: class MyClass(CachedRepresentation):
    407399        ...       def __init__(self, value):
    408400        ...           print "initializing object"
    409401        ...           self.value = value
     
    431423    unprocessed arguments will be passed down to
    432424    :meth:`__init__<object.__init__>`.
    433425
    434     .. rubric:: Mixing super types and super classes
    435 
    436     TESTS:
    437 
    438     For the record, this test did fail with previous implementation
    439     attempts::
    440 
    441         sage: class bla(UniqueRepresentation, SageObject):
    442         ...       pass
    443         ...
    444         sage: b = bla()
    445 
    446426    """
    447 
    448427    __metaclass__ = ClasscallMetaclass
    449428
    450429    _included_private_doc_ = ["__classcall__"]
     
    454433        """
    455434        Constructs a new object of this class or reuse an existing one.
    456435
    457         See also :class:`UniqueRepresentation` for a discussion.
     436        See also :class:`CachedRepresentation` and
     437        :class:`UniqueRepresentation` for a discussion.
    458438
    459439        EXAMPLES::
    460440
    461441            sage: x = UniqueRepresentation()
    462442            sage: y = UniqueRepresentation()
    463             sage: x is y
     443            sage: x is y   # indirect doctest
    464444            True
     445
    465446        """
    466447        instance = typecall(cls, *args, **options)
    467448        assert isinstance( instance, cls )
    468         if instance.__class__.__reduce__ == UniqueRepresentation.__reduce__:
     449        if instance.__class__.__reduce__ == CachedRepresentation.__reduce__:
    469450            instance._reduction = (cls, args, options)
    470451        return instance
    471452
    472     # Should be cythoned
    473     def __eq__(self, other):
    474         """
    475         Test if ``self`` and ``other` are equal by comparing their
    476         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 == y
    485             True
    486             sage: x is y
    487             True
    488             sage: x == 3
    489             False
    490 
    491         TESTS::
    492 
    493             sage: class bla(UniqueRepresentation, SageObject):
    494             ...        def __init__(self, i): pass
    495             sage: b1 = bla(1); b2 = bla(2)
    496             sage: b1 == b1
    497             True
    498             sage: b1 == b2
    499             False
    500         """
    501         return self is other
    502 
    503     # Should be cythoned
    504     def __ne__(self, other):
    505         """
    506         Test if ``self`` and ``other` are different by comparing their
    507         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 != y
    516             False
    517 
    518         TESTS::
    519 
    520             sage: class bla(UniqueRepresentation, SageObject):
    521             ...        def __init__(self, i): pass
    522             sage: b1 = bla(1); b2 = bla(2)
    523             sage: b1 != b1
    524             False
    525             sage: b1 != b2
    526             True
    527         """
    528         return self is not other
    529 
    530     # Should be cythoned
    531     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) # random
    542             74153040
    543             sage: type(hash(x))
    544             <type 'int'>
    545             sage: hash(x) == hash(y)
    546             True
    547             sage: class bla(UniqueRepresentation, SageObject): pass
    548             sage: x = bla(); hx = hash(x)
    549             sage: x.rename("toto")
    550             sage: hx == hash(x)
    551             True
    552         """
    553         return id(self)
    554 
    555453    def __reduce__(self):
    556454        """
    557455        Returns the argument that have been passed to :meth:`__new__<object.__new__>`
    558456        to construct this object, as per the pickle protocol.
    559457
    560         See also :class:`UniqueRepresentation` for a discussion.
     458        See also :class:`CachedRepresentation` and
     459        :class:`UniqueRepresentation` for a discussion.
    561460
    562461        EXAMPLES::
    563462
    564463            sage: x = UniqueRepresentation()
    565             sage: x.__reduce__()
     464            sage: x.__reduce__()          # indirect doctest
    566465            (<function unreduce at ...>, (<class 'sage.structure.unique_representation.UniqueRepresentation'>, (), {}))
    567466        """
    568467        return (unreduce, self._reduction)
     
    576475        EXAMPLES::
    577476
    578477            sage: x = UniqueRepresentation()
    579             sage: x is copy(x)
     478            sage: x is copy(x)    # indirect doctest
    580479            True
    581480        """
    582481        return self
     
    591490
    592491            sage: from copy import deepcopy
    593492            sage: x = UniqueRepresentation()
    594             sage: x is deepcopy(x)
     493            sage: x is deepcopy(x)      # indirect doctest
    595494            True
    596495        """
    597496        return self
     
    603502        sage: sage.structure.unique_representation.unreduce(Integer, (1,), {})
    604503        1
    605504
    606     Todo: should reuse something preexisting ...
     505    .. TODO::
     506
     507        should reuse something preexisting ...
     508
    607509    """
    608510    return cls(*args, **keywords)
     511
     512
     513class UniqueRepresentation(CachedRepresentation, WithEqualityById):
     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  
    1111#                  http://www.gnu.org/licenses/
    1212#*****************************************************************************
    1313
    14 from sage.categories.category_singleton cimport FastHashable_class
     14from sage.misc.fast_methods cimport FastHashable_class
    1515cdef class ClassWithLargeHash(FastHashable_class):
    1616    """
    1717    This class tests against a bug with :class:`FastHashable_class`