Ticket #13870: 13870.patch

File 13870.patch, 62.1 KB (added by Jeroen Demeyer, 10 years ago)
  • doc/en/reference/structure.rst

    # HG changeset patch
    # User Jeroen Demeyer <jdemeyer@cage.ugent.be>
    # Date 1356649242 -3600
    # Node ID 28c8c8135d91fd6f85a5465cd0096c4147d37a52
    # Parent  37912b9b0067aee1bce9cc5ac32eb51af8398ef8
    Undo #715 and #11521
    
    diff --git a/doc/en/reference/structure.rst b/doc/en/reference/structure.rst
    a b  
    99   sage/structure/parent_old
    1010   sage/structure/parent_base
    1111   sage/structure/parent_gens
    12    sage/structure/coerce_dict
    1312   sage/structure/formal_sum
    1413   sage/structure/factorization
    1514   sage/structure/element
  • sage/categories/action.pxd

    diff --git a/sage/categories/action.pxd b/sage/categories/action.pxd
    a b  
    55
    66cdef class Action(Functor):
    77    cdef G
    8     cdef US
     8    cdef S
    99    cdef bint _is_left
    1010    cdef op
    11     cdef underlying_set(self)
    1211    cpdef _call_(self, a, b)
    1312   
    1413   
  • sage/categories/action.pyx

    diff --git a/sage/categories/action.pyx b/sage/categories/action.pyx
    a b  
    11r"""
    2 Group, ring, etc. actions on objects.
     2Group, ring, etc. actions on objects. 
    33
    4 The terminology and notation used is suggestive of groups acting on sets,
    5 but this framework can be used for modules, algebras, etc.
     4The terminology and notation used is suggestive of groups
     5acting on sets, but this framework can be used for modules,
     6algebras, etc.
    67
    7 A group action $G \times S \rightarrow S$ is a functor from $G$ to Sets.
     8A group action $G \times S \rightarrow S$ is a functor from $G$ to Sets. 
    89
    9 .. WARNING::
    10 
    11     An :class:`Action` object only keeps a weak reference to the underlying set
    12     which is acted upon. This decision was made in :trac:`715` in order to
    13     allow garbage collection within the coercion framework (this is where
    14     actions are mainly used) and avoid memory leaks.
    15 
    16     ::
    17 
    18         sage: from sage.categories.action import Action
    19         sage: class P: pass
    20         sage: A = Action(P(),P())
    21         sage: import gc
    22         sage: _ = gc.collect()
    23         sage: A
    24         Traceback (most recent call last):
    25         ...
    26         RuntimeError: This action acted on a set that became garbage collected
    27 
    28     To avoid garbage collection of the underlying set, it is sufficient to
    29     create a strong reference to it before the action is created.
    30 
    31     ::
    32 
    33         sage: _ = gc.collect()
    34         sage: from sage.categories.action import Action
    35         sage: class P: pass
    36         sage: q = P()
    37         sage: A = Action(P(),q)
    38         sage: gc.collect()
    39         0
    40         sage: A
    41         Left action by <__main__.P instance at ...> on <__main__.P instance at ...>
    42 
    43 AUTHOR:
    44 
    45 - Robert Bradshaw: initial version
     10AUTHORS:
     11    -- Robert Bradshaw: initial version
    4612"""
    4713
    4814#*****************************************************************************
     
    6632
    6733import homset
    6834import sage.structure.element
    69 from weakref import ref
    7035
    7136include "../ext/stdsage.pxi"
    7237
     
    8348        from groupoid import Groupoid
    8449        Functor.__init__(self, Groupoid(G), category(S))
    8550        self.G = G
    86         self.US = ref(S)
     51        self.S = S
    8752        self._is_left = is_left
    8853        self.op = op
    8954       
     
    9661            if g in self.G:
    9762                return ActionEndomorphism(self, self.G(g))
    9863            elif g == self.G:
    99                 return self.underlying_set()
     64                return self.S
    10065            else:
    10166                raise TypeError, "%s not an element of %s"%(g, self.G)
    10267        elif len(args) == 2:
    10368            if self._is_left:
    104                 return self._call_(self.G(args[0]), self.underlying_set()(args[1]))
     69                return self._call_(self.G(args[0]), self.S(args[1]))
    10570            else:
    106                 return self._call_(self.underlying_set()(args[0]), self.G(args[1]))
     71                return self._call_(self.S(args[0]), self.G(args[1]))
    10772           
    10873    cpdef _call_(self, a, b):
    10974        raise NotImplementedError, "Action not implemented."
     
    12691       
    12792    def __repr__(self):
    12893        side = "Left" if self._is_left else "Right"
    129         return "%s %s by %r on %r"%(side, self._repr_name_(), self.G,
    130                                     self.underlying_set())
     94        return "%s %s by %r on %r"%(side, self._repr_name_(), self.G, self.S)
    13195       
    13296    def _repr_name_(self):
    13397        return "action"
    13498       
    13599    def actor(self):
    136100        return self.G
    137 
    138     cdef underlying_set(self):
    139         """
    140         The set on which the actor acts (it is not necessarily the codomain of
    141         the action).
    142 
    143         NOTE:
    144 
    145         Since this is a cdef'ed method, we can only provide an indirect doctest.
    146 
    147         EXAMPLES::
    148 
    149             sage: P = QQ['x']
    150             sage: R = (ZZ['x'])['y']
    151             sage: A = R.get_action(P,operator.mul,True)
    152             sage: A                 # indirect doctest
    153             Right scalar multiplication by Univariate Polynomial Ring in x over
    154             Rational Field on Univariate Polynomial Ring in y over Univariate
    155             Polynomial Ring in x over Integer Ring
    156 
    157         In this example, the underlying set is the ring ``R``. This is the same
    158         as the left domain, which is different from the codomain of the action::
    159 
    160             sage: A.codomain()
    161             Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field
    162             sage: A.codomain() == R
    163             False
    164             sage: A.left_domain() is R
    165             True
    166 
    167         By :trac:`715`, there is only a weak reference to the underlying set.
    168         Hence, the underlying set may be garbage collected, even when the
    169         action is still alive. This may result in a runtime error, as follows::
    170 
    171             sage: from sage.categories.action import Action
    172             sage: class P: pass
    173             sage: p = P()
    174             sage: q = P()
    175             sage: A = Action(p,q)
    176             sage: A
    177             Left action by <__main__.P instance at ...> on <__main__.P instance at ...>
    178             sage: del q
    179             sage: import gc
    180             sage: _ = gc.collect()
    181             sage: A
    182             Traceback (most recent call last):
    183             ...
    184             RuntimeError: This action acted on a set that became garbage collected
    185 
    186         """
    187         S = self.US()
    188         if S is None:
    189             raise RuntimeError, "This action acted on a set that became garbage collected"
    190         return S
    191 
     101   
    192102    def codomain(self):
    193        return self.underlying_set()
     103        return self.S
    194104       
    195105    def domain(self):
    196         return self.underlying_set()
     106        return self.S
    197107       
    198108    def left_domain(self):
    199109        if self._is_left:
     
    235145            # We must be in the case that parent(~a) == parent(a)
    236146            # so we can invert in call_c code below.
    237147            if (PY_TYPE_CHECK(G, Group) and G.is_multiplicative()) or G.is_field():
    238                 Action.__init__(self, G, action.underlying_set(), action._is_left)
     148                Action.__init__(self, G, action.S, action._is_left)
    239149                self._action = action
    240150                return
    241151            else:
    242152                K = G._pseudo_fraction_field()
    243                 Action.__init__(self, K, action.underlying_set(), action._is_left)
     153                Action.__init__(self, K, action.S, action._is_left)
    244154                self._action = action
    245155                return
    246156        except (AttributeError, NotImplementedError):
     
    280190              right_precomposition = homset.Hom(right_precomposition._codomain, right).natural_map() * right_precomposition
    281191            right = right_precomposition._domain
    282192        if action._is_left:
    283             Action.__init__(self, left, action.underlying_set(), 1)
     193            Action.__init__(self, left, action.S, 1)
    284194        else:
    285             Action.__init__(self, right, action.underlying_set(), 0)
     195            Action.__init__(self, right, action.S, 0)
    286196        self._action = action
    287197        self.left_precomposition = left_precomposition
    288198        self.right_precomposition = right_precomposition
     
    320230cdef class ActionEndomorphism(Morphism):
    321231   
    322232    def __init__(self, Action action, g):
    323         Morphism.__init__(self, homset.Hom(action.underlying_set(),
    324                                            action.underlying_set()))
     233        Morphism.__init__(self, homset.Hom(action.S, action.S))
    325234        self._action = action
    326235        self._g = g
    327236       
     
    332241            return self._action._call_(x, self._g)
    333242               
    334243    def _repr_(self):
    335         return "Action of %s on %s under %s."%(self._g,
    336                                                self._action.underlying_set(), self._action)
     244        return "Action of %s on %s under %s."%(self._g, self._action.S, self._action)
    337245       
    338246    def __mul__(left, right):
    339247        cdef ActionEndomorphism left_c, right_c
  • sage/categories/functor.pxd

    diff --git a/sage/categories/functor.pxd b/sage/categories/functor.pxd
    a b  
    11from sage.structure.sage_object cimport SageObject
    22
    33cdef class Functor(SageObject):
    4     cdef __weakref__
    54    cdef object __domain
    6     cdef object __codomain
     5    cdef object __codomain
     6 No newline at end of file
  • sage/categories/homset.py

    diff --git a/sage/categories/homset.py b/sage/categories/homset.py
    a b  
    1 r"""
     1"""
    22Homsets
    33
    4 The class :class:`Hom` is the base class used to represent sets of morphisms
    5 between objects of a given category.
    6 :class:`Hom` objects are usually "weakly" cached upon creation so that they
    7 don't have to be generated over and over but can be garbage collected together
    8 with the corresponding objects when these are are not stongly ref'ed anymore.
    9 
    10 EXAMPLES:
    11 
    12 In the following, the :class:`Hom` object is indeed cached::
    13 
    14     sage: K = GF(17)
    15     sage: H = Hom(ZZ, K)
    16     sage: H
    17     Set of Homomorphisms from Integer Ring to Finite Field of size 17
    18     sage: H is Hom(ZZ, K)
    19     True
    20 
    21 Nonetheless, garbage collection occurs when the original references are
    22 overwritten::
    23 
    24     sage: for p in prime_range(200):
    25     ...     K = GF(p)
    26     ...     H = Hom(ZZ, K)
    27     ...
    28     sage: import gc
    29     sage: _ = gc.collect()
    30     sage: from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn as FF
    31     sage: L = [x for x in gc.get_objects() if isinstance(x, FF)]
    32     sage: len(L)
    33     2
    34     sage: L
    35     [Finite Field of size 2, Finite Field of size 199]
    36 
    374AUTHORS:
    385
    396- David Kohel and William Stein
     
    4310- William Stein (2006-01-14): Changed from Homspace to Homset.
    4411
    4512- Nicolas M. Thiery (2008-12-): Updated for the new category framework
    46 
    47 - Simon King (2011-12): Use a weak cache for homsets
    4813"""
    4914
    5015#*****************************************************************************
     
    6227#                  http://www.gnu.org/licenses/
    6328#*****************************************************************************
    6429
     30import weakref
     31
    6532from sage.categories.category import Category
    6633import morphism
    6734from sage.structure.parent import Parent, Set_generic
     
    6936from sage.misc.cachefunc import cached_function
    7037import types
    7138
    72 ###################################
    73 # Use the weak "triple" dictionary
    74 # introduced in trac ticket #715
    75 
    76 from weakref import KeyedRef
    77 from sage.structure.coerce_dict import TripleDict
    78 _cache = TripleDict(53)
    79 
     39_cache = {}
    8040def Hom(X, Y, category=None):
    8141    """
    8242    Create the space of homomorphisms from X to Y in the category ``category``.
     
    11272        sage: Hom(FreeModule(QQ,1), FreeModule(ZZ,1))
    11373        Set of Morphisms from Vector space of dimension 1 over Rational Field to Ambient free module of rank 1 over the principal ideal domain Integer Ring in Category of vector spaces over Rational Field
    11474
    115     Here, we test against a memory leak that has been fixed at :trac:`11521` by
    116     using a weak cache::
    117 
    118         sage: for p in prime_range(10^5):
    119         ...    K = GF(p)
    120         ...    a = K(0)
    121         sage: import gc
    122         sage: gc.collect()       # random
    123         624
    124         sage: from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn as FF
    125         sage: L = [x for x in gc.get_objects() if isinstance(x, FF)]
    126         sage: len(L), L[0], L[len(L)-1]
    127         (2, Finite Field of size 2, Finite Field of size 99991)
    128 
    12975    To illustrate the choice of the category, we consider the
    13076    following parents as running examples::
    13177
     
    210156    # To be investigated.
    211157    global _cache
    212158    key = (X,Y,category)
    213     try:
     159    if _cache.has_key(key):
    214160        H = _cache[key]()
    215     except KeyError:
    216         H = None
    217     if H is not None:
    218         # Are domain or codomain breaking the unique parent condition?
    219         if H.domain() is X and H.codomain() is Y:
    220             return H
     161        # What is this test for? Why does the cache ever contain a 0 value?
     162        # This actually occurs: see e.g. sage -t  sage-combinat/sage/categories/modules_with_basis.py
     163        if H:
     164            # Are domain or codomain breaking the unique parent condition?
     165            if H.domain() is X and H.codomain() is Y:
     166                return H
    221167
    222168    try:
    223         # Apparently X._Hom_ is supposed to be cached
    224169        return X._Hom_(Y, category)
    225170    except (AttributeError, TypeError):
    226171        pass
     
    238183        raise TypeError, "Argument category (= %s) must be a category."%category
    239184    # Now, as the category may have changed, we try to find the hom set in the cache, again:
    240185    key = (X,Y,category)
    241     try:
     186    if _cache.has_key(key):
    242187        H = _cache[key]()
    243     except KeyError:
    244         H = None
    245     if H is not None:
    246         # Are domain or codomain breaking the unique parent condition?
    247         if H.domain() is X and H.codomain() is Y:
    248             return H
     188        if H:
     189            # Are domain or codomain breaking the unique parent condition?
     190            if H.domain() is X and H.codomain() is Y:
     191                return H
    249192
    250193    # coercing would be incredibly annoying, since the domain and codomain
    251194    # are totally different objects
     
    258201    H = category.hom_category().parent_class(X, Y, category = category)
    259202           
    260203    ##_cache[key] = weakref.ref(H)
    261     _cache[key] = KeyedRef(H, _cache.eraser, (id(X),id(Y),id(category)))
     204    _cache[(X, Y, category)] = weakref.ref(H)
    262205    return H
    263206
    264207def hom(X, Y, f):
  • sage/libs/singular/ring.pyx

    diff --git a/sage/libs/singular/ring.pyx b/sage/libs/singular/ring.pyx
    a b  
    463463    EXAMPLE::
    464464
    465465        sage: import gc
    466         sage: _ = gc.collect()
    467466        sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular
    468467        sage: from sage.libs.singular.groebner_strategy import GroebnerStrategy
    469468        sage: from sage.libs.singular.ring import ring_refcount_dict
     
    488487        sage: del P
    489488        sage: _ = gc.collect()
    490489        sage: ring_ptr in ring_refcount_dict
    491         True
     490        False
    492491    """
    493492    if existing_ring==NULL:
    494493        raise ValueError('singular_ring_reference(ring*) called with NULL pointer.')
  • sage/matrix/action.pyx

    diff --git a/sage/matrix/action.pyx b/sage/matrix/action.pyx
    a b  
    11"""
    2 These are the actions used by the coercion model for matrix and vector
    3 multiplications.
     2These are the actions used by the coercion model for matrix and vector multiplications.
    43
    5 .. WARNING::
    6 
    7     The class :class:`MatrixMulAction` and its descendants extends the class
    8     :class:`Action`. As a cosnequence objects from these classes only keep weak
    9     references to the underlying sets which are acted upon. This decision was
    10     made in :trac:`715` in order to allow garbage collection within the coercion
    11     framework, where actions are mainly used, and avoid memory leaks.
    12 
    13     To ensure that the underlying set of such an object does not get garbage
    14     collected, it is sufficient to explicitely create a strong reference to it
    15     before creating the action.
    16 
    17     ::
    18 
    19         sage: MSQ = MatrixSpace(QQ, 2)
    20         sage: MSZ = MatrixSpace(ZZ['x'], 2)
    21         sage: A = MSQ.get_action(MSZ)
    22         sage: A
    23         Left action by Full MatrixSpace of 2 by 2 dense matrices over Rational Field on Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring
    24         sage: import gc
    25         sage: _ = gc.collect()
    26         sage: A
    27         Left action by Full MatrixSpace of 2 by 2 dense matrices over Rational Field on Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring
    28 
    29 .. NOTE::
    30 
    31     The :func:`MatrixSpace` function caches the objects it creates. Therefore,
    32     the underlying set ``MSZ`` in the above example will not be garbage
    33     collected, even if it is not strongly ref'ed. Nonetheless, there is no
    34     guarantee that the set that is acted upon will always be cached in such a
    35     way, so that following the above example is good practice.
    36 
    37 AUTHOR:
    38 
    39 - Robert Bradshaw (2007-09): Initial version.
     4AUTHORS:
     5    -- Robert Bradshaw (2007-09): Initial version.
    406"""
    417
    428#*****************************************************************************
     
    7238       
    7339    def domain(self):
    7440        """
    75         EXAMPLES:
    76 
    77         By :trac:`715`, there only is a weak reference on the underlying set,
    78         so that it can be garbage collected if only the action itself is
    79         explicitly referred to. Hence, we first assign the involved matrix
    80         spaces to a variable::
    81 
    82             sage: MSQ = MatrixSpace(QQ, 2)
    83             sage: MSZ = MatrixSpace(ZZ['x'], 2)
    84             sage: A = MSQ.get_action(MSZ); A
     41        EXAMPLES:
     42            sage: A = MatrixSpace(QQ, 2).get_action(MatrixSpace(ZZ['x'], 2)); A
    8543            Left action by Full MatrixSpace of 2 by 2 dense matrices over Rational Field on Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring
    8644            sage: A.actor()
    8745            Full MatrixSpace of 2 by 2 dense matrices over Rational Field
     
    8947            Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Integer Ring
    9048            sage: A.codomain()
    9149            Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field
    92 
    93         .. NOTE::
    94 
    95             The :func:`MatrixSpace` function caches the object it creates.
    96             Therefore, the underlying set ``MSZ`` in the above example will not
    97             be garbage collected, even if it is not strongly ref'ed.
    98             Nonetheless, there is no guarantee that the set that is acted upon
    99             will always be cached in such a way, so that following the above
    100             example is good practice.
    101 
    10250        """
    103         return self.underlying_set()
     51        return self.S
    10452
    10553
    10654cdef class MatrixMatrixAction(MatrixMulAction):
    10755    def __init__(self, G, S):
    10856        """
    109         EXAMPLES:
    110 
    111         By :trac:`715`, there only is a weak reference on the underlying set,
    112         so that it can be garbage collected if only the action itself is
    113         explicitly referred to. Hence, we first assign the involved matrix
    114         spaces to a variable::
    115 
     57        EXAMPLES:
    11658            sage: R.<x> = ZZ[]
    117             sage: MSR = MatrixSpace(R, 3, 3)
    118             sage: MSQ = MatrixSpace(QQ, 3, 2)
    11959            sage: from sage.matrix.action import MatrixMatrixAction
    120             sage: A = MatrixMatrixAction(MSR, MSQ); A
     60            sage: A = MatrixMatrixAction(MatrixSpace(R, 3, 3), MatrixSpace(QQ, 3, 2)); A
    12161            Left action by Full MatrixSpace of 3 by 3 dense matrices over Univariate Polynomial Ring in x over Integer Ring on Full MatrixSpace of 3 by 2 dense matrices over Rational Field
    12262            sage: A.codomain()
    12363            Full MatrixSpace of 3 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field
     
    12565            [  0   x]
    12666            [2*x 3*x]
    12767            [4*x 5*x]
    128 
    129         .. NOTE::
    130 
    131             The :func:`MatrixSpace` function caches the object it creates.
    132             Therefore, the underlying set ``MSZ`` in the above example will not
    133             be garbage collected, even if it is not strongly ref'ed.
    134             Nonetheless, there is no guarantee that the set that is acted upon
    135             will always be cached in such a way, so that following the above
    136             example is good practice.
    137 
    13868        """
    13969        if not is_MatrixSpace(S):
    14070            raise TypeError, "Not a matrix space: %s" % S
     
    14272       
    14373    def _create_codomain(self, base):
    14474        """
    145         EXAMPLES:
    146 
    147         By :trac:`715`, there only is a weak reference on the underlying set,
    148         so that it can be garbage collected if only the action itself is
    149         explicitly referred to. Hence, we first assign the involved matrix
    150         spaces to a variable::
    151 
     75        EXAMPLES:
    15276            sage: from sage.matrix.action import MatrixMatrixAction
    15377            sage: R.<x> = ZZ[]
    154             sage: MSR = MatrixSpace(R, 3, 3)
    155             sage: MSQ = MatrixSpace(QQ, 3, 2)
    156             sage: A = MatrixMatrixAction(MSR, MSQ); A
     78            sage: A = MatrixMatrixAction(MatrixSpace(R, 3, 3), MatrixSpace(QQ, 3, 2)); A
    15779            Left action by Full MatrixSpace of 3 by 3 dense matrices over Univariate Polynomial Ring in x over Integer Ring on Full MatrixSpace of 3 by 2 dense matrices over Rational Field
    15880            sage: A.codomain()
    15981            Full MatrixSpace of 3 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field
    160 
    161         .. NOTE::
    162 
    163             The :func:`MatrixSpace` function caches the object it creates.
    164             Therefore, the underlying set ``MSZ`` in the above example will not
    165             be garbage collected, even if it is not strongly ref'ed.
    166             Nonetheless, there is no guarantee that the set that is acted upon
    167             will always be cached in such a way, so that following the above
    168             example is good practice.
    169 
    17082        """
    171         if self.G.ncols() != self.underlying_set().nrows():
    172             raise TypeError, "incompatible dimensions %s, %s" % (self.G.ncols(),  self.underlying_set().nrows())
    173         return MatrixSpace(base, self.G.nrows(), self.underlying_set().ncols(),
    174                            sparse = self.G.is_sparse() and self.underlying_set().is_sparse())
     83        if self.G.ncols() != self.S.nrows():
     84            raise TypeError, "incompatible dimensions %s, %s" % (self.G.ncols(),  self.S.nrows())
     85        return MatrixSpace(base, self.G.nrows(), self.S.ncols(), sparse = self.G.is_sparse() and self.S.is_sparse())
    17586       
    17687    cpdef _call_(self, g, s):
    17788        """
    17889        EXAMPLES:
    179 
    180         Respects compatible subdivisions::
    181 
     90        Respects compatible subdivisions:
    18291            sage: M = matrix(5, 5, prime_range(100))
    18392            sage: M.subdivide(2,3); M
    18493            [ 2  3  5| 7 11]
     
    203112            [ 8168|11143]
    204113            [11056|15077]
    205114
    206         Note that this is just like block matrix multiplication::
    207 
     115        Note that this is just like block matrix multiplication:
    208116            sage: M.subdivision(0,0) * N.subdivision(0,0) + M.subdivision(0,1) * N.subdivision(1,0)
    209117            [1048]
    210118            [3056]
    211119           
    212120        If the subdivisions aren't compatible, ignore them.
    213         ::
    214 
    215121            sage: N.subdivide(1,1); N
    216122            [ 0| 1]
    217123            [--+--]
     
    250156cdef class MatrixVectorAction(MatrixMulAction):
    251157    def __init__(self, G, S):
    252158        """
    253         EXAMPLES::
    254 
     159        EXAMPLES:
    255160            sage: from sage.matrix.action import MatrixVectorAction
    256161            sage: A = MatrixVectorAction(MatrixSpace(QQ, 3, 3), VectorSpace(CDF, 4)); A
    257162            Traceback (most recent call last):
     
    264169       
    265170    def _create_codomain(self, base):
    266171        """
    267         EXAMPLES::
    268 
     172        EXAMPLES:
    269173            sage: from sage.matrix.action import MatrixVectorAction
    270174            sage: A = MatrixVectorAction(MatrixSpace(QQ, 5, 3), VectorSpace(CDF, 3)); A
    271175            Left action by Full MatrixSpace of 5 by 3 dense matrices over Rational Field on Vector space of dimension 3 over Complex Double Field
    272176            sage: A.codomain()
    273177            Vector space of dimension 5 over Complex Double Field
    274178        """
    275         if self.G.ncols() != self.underlying_set().degree():
    276             raise TypeError, "incompatible dimensions %s, %s" % (self.G.ncols(),
    277                                                                  self.underlying_set().degree())
     179        if self.G.ncols() != self.S.degree():
     180            raise TypeError, "incompatible dimensions %s, %s" % (self.G.ncols(),  self.S.degree())
    278181        return FreeModule(base, self.G.nrows(), sparse = self.G.is_sparse())
    279182       
    280183    cpdef _call_(self, g, s):
     
    295198cdef class VectorMatrixAction(MatrixMulAction):
    296199    def __init__(self, G, S):
    297200        """
    298         EXAMPLES::
    299 
     201        EXAMPLES:
    300202            sage: from sage.matrix.action import VectorMatrixAction
    301203            sage: A = VectorMatrixAction(MatrixSpace(QQ, 5, 3), VectorSpace(CDF, 3)); A
    302204            Traceback (most recent call last):
     
    309211       
    310212    def _create_codomain(self, base):
    311213        """
    312         EXAMPLES::
    313 
     214        EXAMPLES:
    314215            sage: from sage.matrix.action import VectorMatrixAction
    315216            sage: A = VectorMatrixAction(MatrixSpace(QQ, 3, 5), VectorSpace(CDF, 3)); A
    316217            Right action by Full MatrixSpace of 3 by 5 dense matrices over Rational Field on Vector space of dimension 3 over Complex Double Field
    317218            sage: A.codomain()
    318219            Vector space of dimension 5 over Complex Double Field
    319220        """
    320         if self.G.nrows() != self.underlying_set().degree():
    321             raise TypeError, "incompatible dimensions %s, %s" % (self.G.nrows(),
    322                                                                  self.underlying_set().degree())
     221        if self.G.nrows() != self.S.degree():
     222            raise TypeError, "incompatible dimensions %s, %s" % (self.G.nrows(), self.S.degree())
    323223        return FreeModule(base, self.G.ncols(), sparse = self.G.is_sparse())
    324224       
    325225    cpdef _call_(self, s, g):
  • sage/modular/modsym/ambient.py

    diff --git a/sage/modular/modsym/ambient.py b/sage/modular/modsym/ambient.py
    a b  
    13441344       
    13451345        EXAMPLES::
    13461346       
    1347             sage: M = ModularSymbols(20, 2)
    1348             sage: B = M.boundary_space(); B
     1347            sage: ModularSymbols(20,2).boundary_space()
    13491348            Space of Boundary Modular Symbols for Congruence Subgroup Gamma0(20) of weight 2 and over Rational Field
    1350             sage: M.cusps()
    1351             [Infinity, 0, -1/4, 1/5, -1/2, 1/10]
    1352             sage: M.dimension()
     1349            sage: ModularSymbols(20,2).dimension()
    13531350            7
    1354             sage: B.dimension()
     1351            sage: ModularSymbols(20,2).boundary_space().dimension()
    13551352            6
    13561353        """
    13571354        raise NotImplementedError
  • sage/rings/polynomial/multi_polynomial_libsingular.pyx

    diff --git a/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/sage/rings/polynomial/multi_polynomial_libsingular.pyx
    a b  
    244244import sage.libs.pari.gen
    245245import polynomial_element
    246246
    247 permstore=[]
    248247cdef class MPolynomialRing_libsingular(MPolynomialRing_generic):
    249248
    250249    def __cinit__(self):
     
    366365        from sage.rings.polynomial.polynomial_element import PolynomialBaseringInjection
    367366        base_inject = PolynomialBaseringInjection(base_ring, self)
    368367        self.register_coercion(base_inject)
    369         #permanently store a reference to this ring until deallocation works reliably
    370         permstore.append(self)
    371368
    372369    def __dealloc__(self):
    373370        r"""
     
    407404            sage: import gc
    408405            sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular
    409406            sage: from sage.libs.singular.ring import ring_refcount_dict
    410             sage: gc.collect()  # random output
    411407            sage: n = len(ring_refcount_dict)
    412408            sage: R = MPolynomialRing_libsingular(GF(547), 2, ('x', 'y'), TermOrder('degrevlex', 2))
    413409            sage: len(ring_refcount_dict) == n + 1
     
    422418            sage: del q
    423419            sage: gc.collect() # random output
    424420            sage: len(ring_refcount_dict) == n   
    425             False
     421            True
    426422        """
    427423        return self
    428424
  • sage/rings/polynomial/polynomial_ring_constructor.py

    diff --git a/sage/rings/polynomial/polynomial_ring_constructor.py b/sage/rings/polynomial/polynomial_ring_constructor.py
    a b  
    5353from sage.categories.commutative_rings import CommutativeRings
    5454_CommutativeRings = CommutativeRings()
    5555
    56 import weakref
    57 _cache = weakref.WeakValueDictionary()
     56_cache = {}
    5857
    5958def PolynomialRing(base_ring, arg1=None, arg2=None,
    6059                   sparse=False, order='degrevlex',
  • sage/rings/polynomial/polynomial_zz_pex.pyx

    diff --git a/sage/rings/polynomial/polynomial_zz_pex.pyx b/sage/rings/polynomial/polynomial_zz_pex.pyx
    a b  
    2828    if parent is None:
    2929        return NULL
    3030    cdef ntl_ZZ_pEContext_class c
    31     try:
    32         c = parent._modulus
    33     except AttributeError:
    34         return NULL
     31    c = parent._modulus
    3532    return &(c.x)
    3633
    3734# first we include the definitions
  • sage/structure/coerce.pxd

    diff --git a/sage/structure/coerce.pxd b/sage/structure/coerce.pxd
    a b  
    44from parent cimport Parent
    55from sage.categories.action cimport Action
    66
    7 from coerce_dict cimport TripleDict
     7from coerce_dict cimport TripleDict, TripleDictIter
    88
    99cdef class CoercionModel_cache_maps(CoercionModel):
    1010    # This MUST be a mapping to tuples, where each
  • sage/structure/coerce.pyx

    diff --git a/sage/structure/coerce.pyx b/sage/structure/coerce.pyx
    a b  
    12071207        try:
    12081208            return self._action_maps.get(R, S, op)
    12091209        except KeyError:
    1210             pass
    1211         action = self.discover_action(R, S, op)
    1212         action = self.verify_action(action, R, S, op)
    1213         self._action_maps.set(R, S, op, action)
    1214         return action
     1210            action = self.discover_action(R, S, op)
     1211            action = self.verify_action(action, R, S, op)
     1212            self._action_maps.set(R, S, op, action)
     1213            return action
    12151214           
    12161215    cpdef verify_action(self, action, R, S, op, bint fix=True):
    12171216        r"""
  • sage/structure/coerce_actions.pyx

    diff --git a/sage/structure/coerce_actions.pyx b/sage/structure/coerce_actions.pyx
    a b  
    100100            Multivariate Polynomial Ring in x, y, z over Rational Field
    101101        """
    102102        if self._codomain is None:
    103             self._codomain = parent_c(self.act(an_element(self.G),
    104                                                an_element(self.underlying_set())))
     103            self._codomain = parent_c(self.act(an_element(self.G), an_element(self.S)))
    105104        return self._codomain
    106105
    107106
     
    333332        """
    334333        if self.extended_base is not None:
    335334            return self.extended_base
    336         return self.underlying_set()
     335        return self.S
    337336       
    338337    def domain(self):
    339338        """
     
    346345            sage: A.domain()
    347346            Multivariate Polynomial Ring in x, y, z over Integer Ring
    348347        """
    349         return self.underlying_set()
     348        return self.S
    350349
    351350
    352351
  • sage/structure/coerce_dict.pxd

    diff --git a/sage/structure/coerce_dict.pxd b/sage/structure/coerce_dict.pxd
    a b  
    11cdef class TripleDict:
    22    cdef Py_ssize_t _size
    33    cdef buckets
    4     cdef dict _refcache
    54    cdef double threshold
    6     cdef public TripleDictEraser eraser
    7     cdef get(self, object k1, object k2, object k3)
    8     cdef set(self, object k1, object k2, object k3, value)
     5    cdef get(self, k1, k2, k3)
     6    cdef set(self, k1, k2, k3, value)
    97   
    10 cdef class TripleDictEraser:
    11     cdef TripleDict D
     8cdef class TripleDictIter:
     9    cdef TripleDict pairs
     10    cdef buckets, bucket_iter
  • sage/structure/coerce_dict.pyx

    diff --git a/sage/structure/coerce_dict.pyx b/sage/structure/coerce_dict.pyx
    a b  
    11#*****************************************************************************
    22#       Copyright (C) 2007 Robert Bradshaw <robertwb@math.washington.edu>
    3 #                     2012 Simon King <simon.king@uni-jena.de>
    43#
    54#  Distributed under the terms of the GNU General Public License (GPL)
    65#
    76#                  http://www.gnu.org/licenses/
    87#*****************************************************************************
    9 """
    10 Containers for storing coercion data
    118
    12 This module provides :class:`TripleDict`. It is a structure similar to
    13 ``WeakKeyDictionary`` in Python's weakref module, and is optimized for lookup
    14 speed. Keys consist of a triple (k1,k2,k3) and are looked up by identity
    15 rather than equality. The keys are stored by weakrefs if possible. If any
    16 one of the components k1, k2, k3 gets garbage collected, then the entry is
    17 removed from the :class:`TripleDict`.
    189
    19 Key components that do not allow for weakrefs are stored via a normal
    20 refcounted reference. That means that any entry stored using a triple
    21 (k1,k2,k3) so that none of the k1,k2,k3 allows a weak reference behaves
    22 as an entry in a normal dictionary: Its existence in :class:`TripleDict`
    23 prevents it from being garbage collected.
    24 
    25 That container currently is used to store coercion and conversion maps
    26 between two parents (:trac:`715`) and to store homsets of pairs of objects
    27 of a category (:trac:`11521`). In both cases, it is essential that the parent
    28 structures remain garbage collectable, it is essential that the data access
    29 is faster than with a usual ``WeakKeyDictionary``, and we enforce the "unique
    30 parent condition" in Sage (parent structures should be identical if they are
    31 equal).
    32 """
    3310include "../ext/python_list.pxi"
    3411
    35 from weakref import KeyedRef
    36 
    37 ############################################
    38 # The following code is responsible for
    39 # removing dead references from the cache
    40 ############################################
    41 
    42 cdef class TripleDictEraser:
    43     """
    44     Erases items from a :class:`TripleDict` when a weak reference becomes
    45     invalid.
    46 
    47     This is of internal use only. Instances of this class will be passed as a
    48     callback function when creating a weak reference.
    49 
    50     EXAMPLES::
    51 
    52         sage: from sage.structure.coerce_dict import TripleDict
    53         sage: class A: pass
    54         sage: a = A()
    55         sage: T = TripleDict(11)
    56         sage: T[a,ZZ,None] = 1
    57         sage: T[ZZ,a,1] = 2
    58         sage: T[a,a,ZZ] = 3
    59         sage: len(T)
    60         3
    61         sage: del a
    62         sage: import gc
    63         sage: n = gc.collect()
    64         sage: len(T)
    65         0
    66 
    67     AUTHOR:
    68 
    69     - Simon King (2012-01)
    70     """
    71 
    72     def __init__(self, D):
    73         """
    74         INPUT:
    75 
    76         A :class:`TripleDict`.
    77 
    78         EXAMPLES::
    79 
    80             sage: from sage.structure.coerce_dict import TripleDict, TripleDictEraser
    81             sage: D = TripleDict(11)
    82             sage: TripleDictEraser(D)
    83             <sage.structure.coerce_dict.TripleDictEraser object at ...>
    84 
    85         """
    86         self.D = D
    87 
    88     def __call__(self, r):
    89         """
    90         INPUT:
    91 
    92         A weak reference with key.
    93 
    94         When this is called with a weak reference ``r``, then each item
    95         containing ``r`` is removed from the associated :class:`TripleDict`.
    96         Normally, this only happens when a weak reference becomes invalid.
    97 
    98         EXAMPLES::
    99 
    100             sage: from sage.structure.coerce_dict import TripleDict
    101             sage: class A: pass
    102             sage: a = A()
    103             sage: T = TripleDict(11)
    104             sage: T[a,ZZ,None] = 1
    105             sage: T[ZZ,a,1] = 2
    106             sage: T[a,a,ZZ] = 3
    107             sage: len(T)
    108             3
    109             sage: del a
    110             sage: import gc
    111             sage: n = gc.collect()
    112             sage: len(T)    # indirect doctest
    113             0
    114         """
    115         # r is a (weak) reference (typically to a parent), and it knows the
    116         # stored key of the unique triple r() had been part of.
    117         # We remove that unique triple from self.D
    118         cdef size_t k1,k2,k3
    119         k1,k2,k3 = r.key
    120         cdef size_t h = (k1 + 13*k2 ^ 503*k3)
    121         cdef list bucket = <object>PyList_GET_ITEM(self.D.buckets, h % PyList_GET_SIZE(self.D.buckets))
    122         cdef int i
    123         for i from 0 <= i < PyList_GET_SIZE(bucket) by 4:
    124             if <size_t><object>PyList_GET_ITEM(bucket, i)==k1 and \
    125                <size_t><object>PyList_GET_ITEM(bucket, i+1)==k2 and \
    126                <size_t><object>PyList_GET_ITEM(bucket, i+2)==k3:
    127                 del bucket[i:i+4]
    128                 self.D._size -= 1
    129                 break
    130         try:
    131             self.D._refcache.__delitem__((k1,k2,k3))
    132         except KeyError:
    133             pass
    13412
    13513cdef class TripleDict:
    13614    """
    137     This is a hashtable specifically designed for (read) speed in
    138     the coercion model.
    139 
    140     It differs from a python dict in the following important ways:
    141 
     15    This is a hashtable specifically designed for (read) speed in 
     16    the coercion model. 
     17   
     18    It differs from a python dict in the following important ways: 
     19   
    14220       - All keys must be sequence of exactly three elements. All sequence
    143          types (tuple, list, etc.) map to the same item.
     21         types (tuple, list, etc.) map to the same item. 
    14422       - Comparison is done using the 'is' rather than '==' operator.
    145 
    146     There are special cdef set/get methods for faster access.
    147     It is bare-bones in the sense that not all dictionary methods are
    148     implemented.
    149 
    150     It is implemented as a list of lists (hereafter called buckets). The bucket
    151     is chosen according to a very simple hash based on the object pointer,
    152     and each bucket is of the form [id(k1), id(k2), id(k3), value, id(k1),
    153     id(k2), id(k3), value, ...], on which a linear search is performed.
    154 
     23       
     24    There are special cdef set/get methods for faster access. 
     25    It is bare-bones in the sense that not all dictionary methods are 
     26    implemented. 
     27   
     28    It is implemented as a list of lists (hereafter called buckets). The bucket 
     29    is chosen according to a very simple hash based on the object pointer.
     30    and each bucket is of the form [k1, k2, k3, value, k1, k2, k3, value, ...]
     31    on which a linear search is performed.
     32   
    15533    To spread objects evenly, the size should ideally be a prime, and certainly
    156     not divisible by 2.
    157 
    158     EXAMPLES::
    159 
     34    not divisible by 2.
     35   
     36   
     37    EXAMPLES:
     38   
    16039        sage: from sage.structure.coerce_dict import TripleDict
    16140        sage: L = TripleDict(31)
    16241        sage: a = 'a'; b = 'b'; c = 'c'
     
    20382        Traceback (most recent call last):
    20483        ...
    20584        KeyError: 'a'
    206 
    207     The following illustrates why even sizes are bad (setting the threshold
    208     zero, so that no beneficial resizing happens)::
    209 
    210         sage: L = TripleDict(4, L, threshold=0)
     85       
     86    The following illustrates why even sizes are bad.
     87        sage: L = TripleDict(4, L)
    21188        sage: L.stats()
    21289        (0, 250.25, 1001)
    21390        sage: L.bucket_lens()
    21491        [1001, 0, 0, 0]
    21592
    216     Note that this kind of dictionary is also used for caching actions
    217     and coerce maps. In previous versions of Sage, the cache was by
    218     strong references and resulted in a memory leak in the following
    219     example. However, this leak was fixed by trac ticket :trac:`715`,
    220     using weak references::
    22193
    222         sage: K = GF(1<<55,'t')
    223         sage: for i in range(50):
    224         ...     a = K.random_element()
    225         ...     E = EllipticCurve(j=a)
    226         ...     P = E.random_point()
    227         ...     Q = 2*P
    228         sage: import gc
    229         sage: n = gc.collect()
    230         sage: from sage.schemes.elliptic_curves.ell_finite_field import EllipticCurve_finite_field
    231         sage: LE = [x for x in gc.get_objects() if isinstance(x, EllipticCurve_finite_field)]
    232         sage: len(LE)    # indirect doctest
    233         1
    234 
    235     ..NOTE::
    236 
    237         The index `h` corresponding to the key [k1, k2, k3] is computed as a
    238         value of unsigned type size_t as follows:
    239 
    240         ..MATH::
    241 
    242             h = id(k1) + 13*id(k2) \oplus 503 id(k3)
    243 
    244         Indeed, although the PyList_GetItem function and corresponding
    245         PyList_GET_ITEM macro take a value of signed type Py_ssize_t as input
    246         for the index, they do not accept negative inputs as the higher level
    247         Python functions. Moreover, the above formula can overflow so that `h`
    248         might be considered as negative. Even though this value is taken
    249         modulo the size of the buckets' list before accessing the corresponding
    250         item, the Cython "%" operator behaves for values of type size_t and
    251         Py_ssize_t like the C "%" operator, rather than like the Python "%"
    252         operator as it does for values of type int. That is, it returns a
    253         result of the same sign as its input. Therefore, if `h` was defined as
    254         a signed value, we might access the list at a negative index and raise
    255         a segfault (and this has been observed on 32 bits systems, see
    256         :trac:`715` for details).
    257 
    258     AUTHORS:
    259 
    260     - Robert Bradshaw, 2007-08
    261 
    262     - Simon King, 2012-01
     94    AUTHOR:
     95       -- Robert Bradshaw, 2007-08
    26396    """
    264 
    265     def __init__(self, size, data=None, threshold=0.7):
     97   
     98    def __init__(self, size, data=None, threshold=0):
    26699        """
    267         Create a special dict using triples for keys.
    268 
    269         EXAMPLES::
    270 
     100        Create a special dict using triples for keys.
     101       
     102        EXAMPLES:
    271103            sage: from sage.structure.coerce_dict import TripleDict
    272104            sage: L = TripleDict(31)
    273105            sage: a = 'a'; b = 'b'; c = 'c'
     
    279111        self.threshold = threshold
    280112        self.buckets = [[] for i from 0 <= i <  size]
    281113        self._size = 0
    282         self.eraser = TripleDictEraser(self)
    283         self._refcache = {}
    284114        if data is not None:
    285             for (k1,k2,k3), v in data.iteritems():
    286                 self.set(k1,k2,k3, v)
    287 
     115            for k, v in data.iteritems():
     116                self[k] = v
     117               
    288118    def __len__(self):
    289119        """
    290120        The number of items in self.
    291 
    292         EXAMPLES::
    293 
     121       
     122        EXAMPLES:
    294123            sage: from sage.structure.coerce_dict import TripleDict
    295124            sage: L = TripleDict(37)
    296125            sage: a = 'a'; b = 'b'; c = 'c'
     
    302131            3
    303132        """
    304133        return self._size
    305 
     134       
    306135    def stats(self):
    307136        """
    308         The distribution of items in buckets.
    309 
    310         OUTPUT:
    311 
    312         - (min, avg, max)
    313 
    314         EXAMPLES::
    315 
     137        The distribution of items in buckets.
     138       
     139        OUTPUT:
     140            (min, avg, max)
     141       
     142        EXAMPLES:
    316143            sage: from sage.structure.coerce_dict import TripleDict
    317144            sage: L = TripleDict(37)
    318145            sage: for i in range(100): L[i,i,i] = None
     
    323150            sage: for i in range(100): L[i,i,i] = None
    324151            sage: L.stats() # random
    325152            (0, 0.03325573661456601, 1)
    326 
    327         In order to have a test that isn't random, we use parameters
    328         that should not be used in real applications::
    329 
    330             sage: L = TripleDict(1, threshold=0)
     153           
     154            sage: L = TripleDict(1)
    331155            sage: for i in range(100): L[i,i,i] = None
    332156            sage: L.stats()
    333157            (100, 100.0, 100)
     
    342166            else:
    343167                min = 0
    344168        return min, 1.0*size/len(self.buckets), max
    345 
     169       
    346170    def bucket_lens(self):
    347171        """
    348         The distribution of items in buckets.
    349 
    350         OUTPUT:
    351 
    352         A list of how many items are in each bucket.
    353 
    354         EXAMPLES::
    355 
     172        The distribution of items in buckets.
     173       
     174        OUTPUT:
     175            A list of how many items are in each bucket.
     176       
     177        EXAMPLES:
    356178            sage: from sage.structure.coerce_dict import TripleDict
    357             sage: L = TripleDict(37, threshold=0)
     179            sage: L = TripleDict(37)
    358180            sage: for i in range(100): L[i,i,i] = None
    359181            sage: L.bucket_lens() # random
    360182            [3, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4]
    361183            sage: sum(L.bucket_lens())
    362184            100
    363 
    364         In order to have a test that isn't random, we use parameters
    365         that should not be used in real applications::
    366 
    367             sage: L = TripleDict(1, threshold=0)
     185           
     186            sage: L = TripleDict(1)
    368187            sage: for i in range(100): L[i,i,i] = None
    369188            sage: L.bucket_lens()
    370189            [100]
    371190        """
    372191        return [len(self.buckets[i])/4 for i from 0 <= i < len(self.buckets)]
    373 
     192       
    374193    def _get_buckets(self):
    375194        """
    376         The actual buckets of self, for debugging.
    377 
    378         EXAMPLES::
    379 
     195        The actual buckets of self, for debugging.
     196       
     197        EXAMPLE:
    380198            sage: from sage.structure.coerce_dict import TripleDict
    381199            sage: L = TripleDict(3)
    382200            sage: L[0,0,0] = None
     
    384202            [[0, 0, 0, None], [], []]
    385203        """
    386204        return self.buckets
    387 
     205       
    388206    def __getitem__(self, k):
    389207        """
    390         EXAMPLES::
    391 
     208        EXAMPLES:
    392209            sage: from sage.structure.coerce_dict import TripleDict
    393210            sage: L = TripleDict(31)
    394211            sage: a = 'a'; b = 'b'; c = 'c'
     
    396213            sage: L[a,b,c]
    397214            1
    398215        """
    399         cdef object k1,k2,k3
    400216        try:
    401217            k1, k2, k3 = k
    402218        except (TypeError,ValueError):
    403219            raise KeyError, k
    404220        return self.get(k1, k2, k3)
    405 
    406     cdef get(self, object k1, object k2, object k3):
    407         cdef size_t h1,h2,h3
    408         h1 = <size_t><void *>k1
    409         h2 = <size_t><void *>k2
    410         h3 = <size_t><void *>k3
    411         cdef object r1,r2,r3
    412         try:
    413             r1,r2,r3 = self._refcache[h1,h2,h3]
    414         except KeyError:
    415             raise KeyError, (k1,k2,k3)
    416         if (isinstance(r1,KeyedRef) and r1() is None) or \
    417            (isinstance(r2,KeyedRef) and r2() is None) or \
    418            (isinstance(r3,KeyedRef) and r3() is None):
    419             raise KeyError, (k1,k2,k3)
    420         cdef size_t h = (h1 + 13*h2 ^ 503*h3)
     221           
     222    cdef get(self, k1, k2, k3):
     223        cdef Py_ssize_t h = (<Py_ssize_t><void *>k1 + 13*<Py_ssize_t><void *>k2 ^ 503*<Py_ssize_t><void *>k3)
     224        if h < 0: h = -h
    421225        cdef Py_ssize_t i
    422         cdef list all_buckets = self.buckets
    423         cdef list bucket = <object>PyList_GET_ITEM(all_buckets, h % PyList_GET_SIZE(all_buckets))
    424         cdef object tmp
     226        bucket = <object>PyList_GET_ITEM(self.buckets, h % PyList_GET_SIZE(self.buckets))
    425227        for i from 0 <= i < PyList_GET_SIZE(bucket) by 4:
    426             tmp = <object>PyList_GET_ITEM(bucket, i)
    427             if <size_t>tmp == <size_t><void *>k1:
    428                 tmp = <object>PyList_GET_ITEM(bucket, i+1)
    429                 if <size_t>tmp == <size_t><void *>k2:
    430                     tmp = <object>PyList_GET_ITEM(bucket, i+2)
    431                     if <size_t>tmp == <size_t><void *>k3:
    432                         return <object>PyList_GET_ITEM(bucket, i+3)
     228            if PyList_GET_ITEM(bucket, i) == <PyObject*>k1 and \
     229               PyList_GET_ITEM(bucket, i+1) == <PyObject*>k2 and \
     230               PyList_GET_ITEM(bucket, i+2) == <PyObject*>k3:
     231                return <object>PyList_GET_ITEM(bucket, i+3)
    433232        raise KeyError, (k1, k2, k3)
    434 
     233       
    435234    def __setitem__(self, k, value):
    436235        """
    437         EXAMPLES::
    438 
     236        EXAMPLES:
    439237            sage: from sage.structure.coerce_dict import TripleDict
    440238            sage: L = TripleDict(31)
    441239            sage: a = 'a'; b = 'b'; c = 'c'
     
    443241            sage: L[a,b,c]
    444242            -1
    445243        """
    446         cdef object k1,k2,k3
    447244        try:
    448245            k1, k2, k3 = k
    449246        except (TypeError,ValueError):
    450247            raise KeyError, k
    451248        self.set(k1, k2, k3, value)
    452 
    453     cdef set(self, object k1, object k2, object k3, value):
     249           
     250    cdef set(self, k1, k2, k3, value):
    454251        if self.threshold and self._size > len(self.buckets) * self.threshold:
    455252            self.resize()
    456         cdef size_t h1 = <size_t><void *>k1
    457         cdef size_t h2 = <size_t><void *>k2
    458         cdef size_t h3 = <size_t><void *>k3
    459         cdef size_t h = (h1 + 13*h2 ^ 503*h3)
     253        cdef Py_ssize_t h = (<Py_ssize_t><void *>k1 + 13*<Py_ssize_t><void *>k2 ^ 503*<Py_ssize_t><void *>k3)
     254        if h < 0: h = -h
    460255        cdef Py_ssize_t i
    461         cdef list bucket = <object>PyList_GET_ITEM(self.buckets, h % PyList_GET_SIZE(self.buckets))
    462         cdef object tmp
     256        bucket = <object>PyList_GET_ITEM(self.buckets, h % PyList_GET_SIZE(self.buckets))
    463257        for i from 0 <= i < PyList_GET_SIZE(bucket) by 4:
    464             tmp = <object>PyList_GET_ITEM(bucket, i)
    465             if <size_t>tmp == h1:
    466                 tmp = <object>PyList_GET_ITEM(bucket, i+1)
    467                 if <size_t>tmp == h2:
    468                     tmp = <object>PyList_GET_ITEM(bucket, i+2)
    469                     if <size_t>tmp == h3:
    470                         # Test whether the old references are still active
    471                         r1,r2,r3 = <tuple>(self._refcache[h1,h2,h3])
    472                         if (isinstance(r1,KeyedRef) and r1() is None) or \
    473                            (isinstance(r2,KeyedRef) and r2() is None) or \
    474                            (isinstance(r3,KeyedRef) and r3() is None):
    475                             del bucket [i:i+4]
    476                             self._size -= 1
    477                             break
    478                         bucket[i+3] = value
    479                         return
    480         PyList_Append(bucket, h1)
    481         PyList_Append(bucket, h2)
    482         PyList_Append(bucket, h3)
    483         PyList_Append(bucket, value)
    484         try:
    485             ref1 = KeyedRef(k1,self.eraser,(h1, h2, h3))
    486         except TypeError:
    487             ref1 = k1
    488         if k2 is not k1:
    489             try:
    490                 ref2 = KeyedRef(k2,self.eraser,(h1, h2, h3))
    491             except TypeError:
    492                 ref2 = k2
    493         else:
    494             ref2 = None
    495         if k3 is not k2 or k3 is not k1:
    496             try:
    497                 ref3 = KeyedRef(k3,self.eraser,(h1, h2, h3))
    498             except TypeError:
    499                 ref3 = k3
    500         else:
    501             ref3 = None
    502         self._refcache[h1,h2,h3] = (ref1,ref2,ref3)
     258            if PyList_GET_ITEM(bucket, i) == <PyObject*>k1 and \
     259               PyList_GET_ITEM(bucket, i+1) == <PyObject*>k2 and \
     260               PyList_GET_ITEM(bucket, i+2) == <PyObject*>k3:
     261                bucket[i+3] = value
     262                return
     263        bucket += [k1, k2, k3, value]
    503264        self._size += 1
    504 
     265           
    505266    def __delitem__(self, k):
    506267        """
    507         EXAMPLES::
    508 
     268        EXAMPLES:
    509269            sage: from sage.structure.coerce_dict import TripleDict
    510270            sage: L = TripleDict(31)
    511271            sage: a = 'a'; b = 'b'; c = 'c'
     
    514274            sage: len(L)
    515275            0
    516276        """
    517         cdef object k1,k2,k3
    518277        try:
    519278            k1, k2, k3 = k
    520279        except (TypeError,ValueError):
    521280            raise KeyError, k
    522         try:
    523             r1,r2,r3 = self._refcache[<size_t><void *>k1,<size_t><void *>k2,<size_t><void *>k3]
    524         except KeyError:
    525             raise KeyError, k
    526         if (isinstance(r1,KeyedRef) and r1() is None) or \
    527            (isinstance(r2,KeyedRef) and r2() is None) or \
    528            (isinstance(r3,KeyedRef) and r3() is None):
    529             raise KeyError, k
    530         try:
    531             del self._refcache[<size_t><void *>k1,<size_t><void *>k2,<size_t><void *>k3]
    532         except KeyError:
    533             # This is to cope with a potential racing condition - if garbage
    534             # collection and weakref callback happens right between the
    535             # "if (isinstance(r1,..." and the "del", then the previously
    536             # existing entry might already be gone.
    537             raise KeyError, k
    538         cdef size_t h = (<size_t><void *>k1 + 13*<size_t><void *>k2 ^ 503*<size_t><void *>k3)
     281        cdef Py_ssize_t h = (<Py_ssize_t><void *>k1 + 13*<Py_ssize_t><void *>k2 ^ 503*<Py_ssize_t><void *>k3)
     282        if h < 0: h = -h
    539283        cdef Py_ssize_t i
    540         cdef list bucket = <object>PyList_GET_ITEM(self.buckets, h % PyList_GET_SIZE(self.buckets))
     284        bucket = <object>PyList_GET_ITEM(self.buckets, h % PyList_GET_SIZE(self.buckets))
    541285        for i from 0 <= i < PyList_GET_SIZE(bucket) by 4:
    542             if <size_t><object>PyList_GET_ITEM(bucket, i) == <size_t><void *>k1 and \
    543                <size_t><object>PyList_GET_ITEM(bucket, i+1) == <size_t><void *>k2 and \
    544                <size_t><object>PyList_GET_ITEM(bucket, i+2) == <size_t><void *>k3:
     286            if PyList_GET_ITEM(bucket, i) == <PyObject*>k1 and \
     287               PyList_GET_ITEM(bucket, i+1) == <PyObject*>k2 and \
     288               PyList_GET_ITEM(bucket, i+2) == <PyObject*>k3:
    545289                del bucket[i:i+4]
    546290                self._size -= 1
    547291                return
    548292        raise KeyError, k
    549 
     293       
    550294    def resize(self, int buckets=0):
    551295        """
    552         Changes the number of buckets of self, while preserving the contents.
    553 
    554         If the number of buckets is 0 or not given, it resizes self to the
    555         smallest prime that is at least twice as large as self.
    556 
    557         EXAMPLES::
    558 
     296        Changes the number of buckets of self, while preserving the contents.
     297       
     298        If the number of buckets is 0 or not given, it resizes self to the
     299        smallest prime that is at least twice as large as self.
     300       
     301        EXAMPLES:
    559302            sage: from sage.structure.coerce_dict import TripleDict
    560303            sage: L = TripleDict(8)
    561304            sage: for i in range(100): L[i,i,i] = None
     
    569312        """
    570313        if buckets == 0:
    571314            buckets = next_odd_prime(2*len(self.buckets))
    572         cdef list old_buckets = self.buckets
    573         cdef list bucket
    574         cdef Py_ssize_t i
    575         cdef size_t h
    576         self.buckets = [[] for i from 0 <= i <  buckets]
    577         cdef size_t k1,k2,k3
    578         cdef object v
    579         for bucket in old_buckets:
    580             for i from 0 <= i < PyList_GET_SIZE(bucket) by 4:
    581                 k1 = <size_t><object>PyList_GET_ITEM(bucket, i)
    582                 k2 = <size_t><object>PyList_GET_ITEM(bucket, i+1)
    583                 k3 = <size_t><object>PyList_GET_ITEM(bucket, i+2)
    584                 v  = <object>PyList_GET_ITEM(bucket, i+3)
    585                 h = (k1 + 13*k2 ^ 503*k3)
    586                 self.buckets[h % buckets] += [k1,k2,k3,v]
    587 
     315        cdef TripleDict new = TripleDict(buckets, self)
     316        self.buckets = new.buckets
     317           
    588318    def iteritems(self):
    589319        """
    590         EXAMPLES::
    591 
     320        EXAMPLES:
    592321            sage: from sage.structure.coerce_dict import TripleDict
    593322            sage: L = TripleDict(31)
    594323            sage: L[1,2,3] = None
    595324            sage: list(L.iteritems())
    596325            [((1, 2, 3), None)]
    597326        """
    598         cdef list bucket
    599         cdef size_t i, h1,h2,h3
    600         # We test whether the references are still valid.
    601         # However, we must not delete them, since we are
    602         # iterating.
    603         for bucket in self.buckets:
    604             for i from 0<=i<len(bucket) by 4:
    605                 h1,h2,h3 = bucket[i:i+3]
    606                 try:
    607                     r1,r2,r3 = self._refcache[h1,h2,h3]
    608                 except KeyError:
    609                     # That can only happen under a race condition.
    610                     # Anyway, it means the item is not there.
    611                     continue
    612                 if isinstance(r1, KeyedRef):
    613                     r1 = r1()
    614                     if r1 is None:
    615                         continue
    616                 if isinstance(r2, KeyedRef):
    617                     r2 = r2()
    618                     if r2 is None:
    619                         continue
    620                 if isinstance(r3, KeyedRef):
    621                     r3 = r3()
    622                     if r3 is None:
    623                         continue
    624                 yield (r1,r2,r3), <object>PyList_GET_ITEM(bucket,i+3)
    625 
     327        return TripleDictIter(self)
     328       
    626329    def __reduce__(self):
    627330        """
    628         Note that we don't expect equality as this class concerns itself with
    629         object identity rather than object equality.
     331        Note that we don't expect equality as this class concerns itself with 
     332        object identity rather than object equality. 
    630333
    631         EXAMPLES::
    632 
     334        EXAMPLES:
    633335            sage: from sage.structure.coerce_dict import TripleDict
    634336            sage: L = TripleDict(31)
    635337            sage: L[1,2,3] = True
     
    639341            [((1, 2, 3), True)]
    640342        """
    641343        return TripleDict, (len(self.buckets), dict(self.iteritems()), self.threshold)
     344       
     345
     346cdef class TripleDictIter:
     347    def __init__(self, pairs):
     348        """
     349        EXAMPLES:
     350            sage: from sage.structure.coerce_dict import TripleDict, TripleDictIter
     351            sage: L = TripleDict(31)
     352            sage: L[1,2,3] = None
     353            sage: L.iteritems().next()
     354            ((1, 2, 3), None)
     355        """
     356        self.pairs = pairs
     357        self.buckets = iter(self.pairs.buckets)
     358    def __iter__(self):
     359        """
     360        EXAMPLES:
     361            sage: from sage.structure.coerce_dict import TripleDict, TripleDictIter
     362            sage: L = TripleDict(31)
     363            sage: L[1,2,3] = None
     364            sage: iter(L.iteritems()).next()
     365            ((1, 2, 3), None)
     366        """
     367        return self
     368    def __next__(self):
     369        """
     370        EXAMPLES:
     371            sage: from sage.structure.coerce_dict import TripleDict, TripleDictIter
     372            sage: L = TripleDict(31)
     373            sage: L[1,2,3] = None
     374            sage: L[3,2,1] = None
     375            sage: sorted(L.iteritems())
     376            [((1, 2, 3), None), ((3, 2, 1), None)]
     377        """
     378        while self.bucket_iter is None:
     379            self.bucket_iter = self.buckets.next()
     380        self.bucket_iter = iter(self.bucket_iter)
     381        try:
     382            k1 = self.bucket_iter.next()
     383            k2 = self.bucket_iter.next()
     384            k3 = self.bucket_iter.next()
     385            value = self.bucket_iter.next()
     386            return ((k1, k2, k3), value)
     387        except StopIteration:
     388            self.bucket_iter = None
     389            return self.next()
     390
     391
    642392
    643393cdef long next_odd_prime(long n):
    644394    if n % 2 == 0:
  • sage/structure/parent.pxd

    diff --git a/sage/structure/parent.pxd b/sage/structure/parent.pxd
    a b  
    77###############################################################################
    88
    99cimport sage.structure.category_object
    10 from sage.structure.coerce_dict cimport TripleDict
    1110
    1211cdef class Parent(category_object.CategoryObject):
    1312
     
    7473    # and Parents for which self._rmul_ and/or self._lmul_
    7574    # do the correct thing.
    7675    # Initialized at ring creation.
    77     cdef list _action_list
     76    cdef _action_list
    7877    # Hashtable of everything we've (possibly recursively) discovered so far.
    79     cdef TripleDict _action_hash
     78    cdef _action_hash
    8079
    8180    # List consisting of Morphisms (from anything to self)
    8281    # and Parents for which the __call__ method of self
  • sage/structure/parent.pyx

    diff --git a/sage/structure/parent.pyx b/sage/structure/parent.pyx
    a b  
    546546            self._coerce_from_list = []
    547547            self._coerce_from_hash = {}
    548548            self._action_list = []
    549             self._action_hash = TripleDict(23)
     549            self._action_hash = {}
    550550            self._convert_from_list = []
    551551            self._convert_from_hash = {}
    552552            self._embedding = None
     
    664664        EXAMPLES::
    665665       
    666666            sage: sorted(QQ._introspect_coerce().items())
    667             [('_action_hash', <sage.structure.coerce_dict.TripleDict object at ...>),
     667            [('_action_hash', {...}),
    668668             ('_action_list', []),
    669669             ('_coerce_from_hash', {...}),
    670670             ('_coerce_from_list', []),
     
    16061606        if isinstance(action, Action):
    16071607            if action.actor() is self:
    16081608                self._action_list.append(action)
    1609                 self._action_hash.set(action.domain(), action.operation(), action.is_left(), action)
     1609                self._action_hash[action.domain(), action.operation(), action.is_left()] = action
    16101610            elif action.domain() is self:
    16111611                self._action_list.append(action)
    1612                 self._action_hash.set(action.actor(), action.operation(), not action.is_left(), action)
     1612                self._action_hash[action.actor(), action.operation(), not action.is_left()] = action
    16131613            else:
    16141614                raise ValueError("Action must involve self")
    16151615        else:
     
    22192219        try:
    22202220            if self._action_hash is None: # this is because parent.__init__() does not always get called
    22212221                self.init_coerce()
    2222             return self._action_hash.get(S, op, self_on_left)
     2222            return self._action_hash[S, op, self_on_left]
    22232223        except KeyError:
    22242224            pass
    22252225
     
    22342234            # We do NOT add to the list, as this would lead to errors as in
    22352235            # the example above.
    22362236
    2237         self._action_hash.set(S, op, self_on_left, action)
     2237        self._action_hash[S, op, self_on_left] = action
    22382238        return action
    22392239       
    22402240
  • sage/structure/parent_old.pyx

    diff --git a/sage/structure/parent_old.pyx b/sage/structure/parent_old.pyx
    a b  
    3030import operator
    3131from parent import Set_PythonType, Set_PythonType_class
    3232from coerce import py_scalar_parent
    33 from sage.structure.coerce_dict import TripleDict
    3433
    3534include '../ext/python_object.pxi'
    3635include '../ext/python_bool.pxi'
     
    6766        self._coerce_from_list = list(coerce_from)
    6867        self._coerce_from_hash = {}
    6968        self._action_list = list(actions)
    70         self._action_hash = TripleDict(23)
     69        self._action_hash = {}
    7170       
    7271        cdef parent.Parent other
    7372        for mor in embeddings: