Ticket #14054: trac14054_fast_methods.patch

File trac14054_fast_methods.patch, 55.6 KB (added by SimonKing, 7 years ago)

Separate cache and uniqueness.

  • 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  
    4646   sage/misc/nested_class
    4747   sage/misc/nested_class_test
    4848   sage/misc/classcall_metaclass
     49   sage/misc/fast_methods
    4950   sage/misc/sage_unittest
    5051   sage/misc/randstate
    5152   sage/misc/cython
  • 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/algebras/iwahori_hecke_algebra.py

    diff --git a/sage/algebras/iwahori_hecke_algebra.py b/sage/algebras/iwahori_hecke_algebra.py
    a b  
    1414from sage.combinat.family import Family
    1515from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement
    1616from sage.misc.cachefunc import cached_method
     17from sage.structure.unique_representation import UniqueRepresentation
    1718
    18 class IwahoriHeckeAlgebraT(CombinatorialFreeModule):
     19class IwahoriHeckeAlgebraT(UniqueRepresentation, CombinatorialFreeModule):
    1920    r"""
    2021    INPUT:
    2122
  • 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/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  
    1313from sage.categories.all import AlgebrasWithBasis
    1414from sage.combinat.free_module import CombinatorialFreeModule
    1515from sage.combinat.words.words import Words
     16from sage.structure.unique_representation import UniqueRepresentation
    1617
    17 class FreeAlgebra(CombinatorialFreeModule):
     18class FreeAlgebra(UniqueRepresentation, CombinatorialFreeModule):
    1819    r"""
    1920    An example of an algebra with basis: the free algebra
    2021
  • 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.WithRichCmpById'>,
    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.WithRichCmpById'>
    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  
    99#  Distributed under the terms of the GNU General Public License (GPL)
    1010#                  http://www.gnu.org/licenses/
    1111#*****************************************************************************
    12 from sage.structure.unique_representation import UniqueRepresentation
     12from sage.structure.unique_representation import CachedRepresentation
    1313from sage.structure.element import Element
    1414from sage.structure.parent import Parent
    1515from sage.structure.sage_object import have_same_parent
     
    262262            sage: F1.zero() == 0
    263263            True
    264264            sage: F1.zero() == F2.zero()
    265             False
     265            True
    266266            sage: F1.an_element() == None
    267267            False
    268268
     
    870870    else:
    871871        return q
    872872
    873 class CombinatorialFreeModule(UniqueRepresentation, Module):
     873class CombinatorialFreeModule(CachedRepresentation, Module):
    874874    r"""
    875875    Class for free modules with a named basis
    876876
     
    10001000        sage: F1 is F
    10011001        True
    10021002
    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)::
    10051006
    10061007        sage: F1 = CombinatorialFreeModule(QQ, (1,2,3,4))
    10071008        sage: F1 is F
    10081009        True
    10091010        sage: F1 = CombinatorialFreeModule(QQ, [4,3,2,1])
    10101011        sage: F1 == F
    1011         False
     1012        True
    10121013        sage: F2 = CombinatorialFreeModule(QQ, [1,2,3,4], prefix='F')
    10131014        sage: F2 == F
    1014         False
     1015        True
    10151016
    10161017    Because of this, if you create a free module with certain
    10171018    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`::
    10191023
    10201024        sage: F2.print_options(prefix='x')
    10211025        sage: F2.prefix()
     
    10271031        'x'
    10281032        sage: F4 = CombinatorialFreeModule(QQ, [1,2,3,4], prefix='F', bracket=True)
    10291033        sage: F4 == F2   # F4 was NOT defined just like F2
    1030         False
     1034        True
    10311035        sage: F4.prefix()
    10321036        'F'
    10331037
     
    12211225        # self._repr_option_bracket.  Future users might consider
    12221226        # using 'bracket' instead of _repr_option_bracket.
    12231227
    1224         # ignore the optional 'key' since it only affects UniqueRepresentation
     1228        # ignore the optional 'key' since it only affects CachedRepresentation
    12251229        kwds.pop('key', None)
    12261230        self.print_options(**kwds)
    12271231
     
    23282332                sage: T.print_options(tensor_symbol= ' @ ')  # note the spaces
    23292333                sage: T # indirect doctest
    23302334                F @ G
     2335
     2336            To avoid a side\--effect on another doctest, we revert the change::
     2337
     2338                sage: T.print_options(tensor_symbol= ' # ')
    23312339            """
    23322340            from sage.categories.tensor import tensor
    23332341            if hasattr(self, "_print_options"):
     
    24122420                sage: f =   F.monomial(1) + 2 * F.monomial(2)
    24132421                sage: g = 2*G.monomial(3) +     G.monomial(4)
    24142422                sage: h =   H.monomial(5) +     H.monomial(6)
    2415 
    24162423                sage: FG  = tensor([F, G   ])
    24172424                sage: phi_fg = FG.tensor_constructor((F, G))
    24182425                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  
    943943                from sage.categories.all import tensor
    944944                return tensor([self.one(), x]) + tensor([x, self.one()])
    945945
    946     class Ribbon(CombinatorialFreeModule, BindableClass):
     946    class Ribbon(UniqueRepresentation, CombinatorialFreeModule, BindableClass):
    947947        r"""
    948948        The Hopf algebra of non-commutative symmetric functions in the Ribbon basis.
    949949
     
    10891089
    10901090    R = ribbon = Ribbon
    10911091
    1092     class Complete(CombinatorialFreeModule, BindableClass):
     1092    class Complete(UniqueRepresentation, CombinatorialFreeModule, BindableClass):
    10931093        """
    10941094        The Hopf algebra of non-commutative symmetric functions in the Complete basis.
    10951095
     
    12561256
    12571257    S = complete = Complete
    12581258
    1259     class Elementary(CombinatorialFreeModule, BindableClass):
     1259    class Elementary(UniqueRepresentation, CombinatorialFreeModule, BindableClass):
    12601260        r"""
    12611261        The Hopf algebra of non-commutative symmetric functions in the Elementary basis.
    12621262
     
    13461346
    13471347    L = elementary = Elementary
    13481348
    1349     class Psi(CombinatorialFreeModule, BindableClass):
     1349    class Psi(UniqueRepresentation, CombinatorialFreeModule, BindableClass):
    13501350        r"""
    13511351        The Hopf algebra of non-commutative symmetric functions in the Psi basis.
    13521352
     
    14851485            return complete.sum_of_terms((J, minus_one**(len(J)-len(I))*coeff_lp(J,I))
    14861486                                            for J in I.finer())
    14871487
    1488     class Phi(CombinatorialFreeModule, BindableClass):
     1488    class Phi(UniqueRepresentation, CombinatorialFreeModule, BindableClass):
    14891489        r"""
    14901490        The Hopf algebra of non-commutative symmetric functions in the Phi basis.
    14911491
     
    15931593            return complete.sum_of_terms((J, minus_one**(len(J)-len(I)) * prod(I) / coeff_ell(J,I))
    15941594                                         for J in I.finer())
    15951595
    1596     class Monomial(CombinatorialFreeModule, BindableClass):
     1596    class Monomial(UniqueRepresentation, CombinatorialFreeModule, BindableClass):
    15971597        def __init__(self, NCSF):
    15981598            r"""
    15991599            Basis from 'Noncommutative Analogs of Monomial Symmetric
     
    17001700
    17011701    nM = monomial = Monomial
    17021702
    1703     class Immaculate(CombinatorialFreeModule, BindableClass):
     1703    class Immaculate(UniqueRepresentation, CombinatorialFreeModule, BindableClass):
    17041704        def __init__(self, NCSF):
    17051705            r"""
    17061706            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  
    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/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  
    1818from sage.misc.flatten import flatten
    1919from sage.misc.lazy_attribute import lazy_attribute
    2020from sage.misc.functional import is_even, is_odd
     21from sage.structure.unique_representation import UniqueRepresentation
    2122from sage.modules.free_module_element import vector
    2223from sage.rings.all import ZZ, QQ
    2324
    24 class WeylCharacterRing(CombinatorialFreeModule):
     25class WeylCharacterRing(UniqueRepresentation, CombinatorialFreeModule):
    2526    """
    2627    A class for rings of Weyl characters.
    2728
     
    25162517    else:
    25172518        return lambda x : tuple(M*vector(x))
    25182519
    2519 class WeightRing(CombinatorialFreeModule):
     2520class WeightRing(UniqueRepresentation,CombinatorialFreeModule):
    25202521    """
    25212522    The WeightRing is the group algebra over a weight lattice.
    25222523
  • sage/combinat/sf/sfa.py

    diff --git a/sage/combinat/sf/sfa.py b/sage/combinat/sf/sfa.py
    a b  
    203203from sage.combinat.partition import Partitions
    204204import sage.libs.symmetrica.all as symmetrica  # used in eval()
    205205from sage.combinat.free_module import CombinatorialFreeModule
     206from sage.structure.unique_representation import UniqueRepresentation
    206207from sage.matrix.constructor import matrix
    207208from sage.misc.misc import repr_lincomb, prod, uniq
    208209from functools import partial
     
    762763            """
    763764            return self.coefficient([])
    764765
    765 class SymmetricFunctionAlgebra_generic(CombinatorialFreeModule):
     766class SymmetricFunctionAlgebra_generic(UniqueRepresentation, CombinatorialFreeModule):
    766767    r"""
    767768
    768769    .. 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  
    1515import partition
    1616from tableau import Tableau, StandardTableaux_size, StandardTableaux_shape, StandardTableaux
    1717from sage.interfaces.all import gap
     18from sage.structure.unique_representation import UniqueRepresentation
    1819from sage.rings.all import factorial, QQ, PolynomialRing
    1920from sage.matrix.all import matrix
    2021from sage.modules.all import vector
     
    9192    """
    9293    return SymmetricGroupAlgebra_n(R,n)
    9394
    94 class SymmetricGroupAlgebra_n(CombinatorialFreeModule):
     95class SymmetricGroupAlgebra_n(UniqueRepresentation, CombinatorialFreeModule):
    9596
    9697    def __init__(self, R, n):
    9798        """
    9899        TESTS::
    99100       
    100101            sage: QS3 = SymmetricGroupAlgebra(QQ, 3)
    101             sage: QS3 == loads(dumps(QS3))
     102            sage: QS3 is loads(dumps(QS3))
    102103            True
    103104        """
    104105        self.n = n
     
    747748
    748749    return HeckeAlgebraSymmetricGroup_t(R, n, q)
    749750
    750 class HeckeAlgebraSymmetricGroup_generic(CombinatorialAlgebra):
     751class HeckeAlgebraSymmetricGroup_generic(UniqueRepresentation, CombinatorialAlgebra):
    751752    def __init__(self, R, n, q=None):
    752753        """
    753754        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  
    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 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"""
     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:`FastHashable_class` with assignable hash, and a cython base
     11    class :class:`WithRichCmpById` implementing unique instance behaviour.
     12
     13AUTHOR:
     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
     34include "../ext/python_rich_object.pxi"
     35include "../ext/python_bool.pxi"
     36include "../ext/python_ref.pxi"
     37
     38cdef int SIZEOF_VOID_P_SHIFT = 8*sizeof(void *) - 4
     39
     40cdef 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
     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 WithRichCmpById
    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, 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  
    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`