Ticket #11521: trac11521_triple_homset.patch

File trac11521_triple_homset.patch, 5.3 KB (added by SimonKing, 8 years ago)

Use the weak TripleDict from #715 for the cache of homsets

  • sage/categories/homset.py

    # HG changeset patch
    # User Simon King <simon.king@uni-jena.de>
    # Date 1325197817 -3600
    # Node ID d4d91dfafc78415a41a64c36a8430c05366dbf40
    # Parent  04e068d2e37c1a04acf446a7f05412f25951a3b2
    #11521: Use the weak TripleDict from #715 for the cache of homsets.
    
    diff --git a/sage/categories/homset.py b/sage/categories/homset.py
    a b  
    1010- William Stein (2006-01-14): Changed from Homspace to Homset.
    1111
    1212- Nicolas M. Thiery (2008-12-): Updated for the new category framework
     13
     14- Simon King (2011-12): Use a weak cache for homsets
    1315"""
    1416
    1517#*****************************************************************************
     
    3638from sage.misc.cachefunc import cached_function
    3739import types
    3840
    39 _cache = {}
     41###################################
     42# Use the weak "triple" dictionary
     43# introduced in trac ticket #715
     44
     45import weakref
     46from sage.structure.coerce_dict import TripleDict
     47_cache = TripleDict(53)
     48
    4049def Hom(X, Y, category=None):
    4150    """
    4251    Create the space of homomorphisms from X to Y in the category ``category``.
     
    7281        sage: Hom(FreeModule(QQ,1), FreeModule(ZZ,1))
    7382        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
    7483
     84    Here, we test against a memory leak that has been fixed at #11521 by using
     85    a weak cache::
     86
     87        sage: for p in prime_range(10^5):
     88        ...    K = GF(p)
     89        ...    a = K(0)
     90        sage: import gc
     91        sage: gc.collect()       # random
     92        624
     93        sage: from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn as FF
     94        sage: L = [x for x in gc.get_objects() if isinstance(x, FF)]
     95        sage: len(L), L[0], L[len(L)-1]
     96        (2, Finite Field of size 2, Finite Field of size 99991)
     97
    7598    To illustrate the choice of the category, we consider the
    7699    following parents as running examples::
    77100
     
    155178    # However it breaks somehow the coercion (see e.g. sage -t sage.rings.real_mpfr)
    156179    # To be investigated.
    157180    global _cache
    158     key = (X,Y,category)
    159     if _cache.has_key(key):
     181    cat_ref = weakref.ref(category) if category is not None else None
     182    key = (X,Y,cat_ref)
     183    try:
    160184        H = _cache[key]()
    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
     185    except KeyError:
     186        H = None
     187    if H:
     188        # Are domain or codomain breaking the unique parent condition?
     189        if H.domain() is X and H.codomain() is Y:
     190            return H
    167191
    168192    try:
     193        # Apparently X._Hom_ is supposed to be cached
    169194        return X._Hom_(Y, category)
    170195    except (AttributeError, TypeError):
    171196        pass
     
    182207    else:
    183208        raise TypeError, "Argument category (= %s) must be a category."%category
    184209    # Now, as the category may have changed, we try to find the hom set in the cache, again:
    185     key = (X,Y,category)
    186     if _cache.has_key(key):
     210    cat_ref = weakref.ref(category) if category is not None else None
     211    key = (X,Y,cat_ref)
     212    try:
    187213        H = _cache[key]()
    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
     214    except KeyError:
     215        H = None
     216    if H:
     217        # Are domain or codomain breaking the unique parent condition?
     218        if H.domain() is X and H.codomain() is Y:
     219            return H
    192220
    193221    # coercing would be incredibly annoying, since the domain and codomain
    194222    # are totally different objects
     
    201229    H = category.hom_category().parent_class(X, Y, category = category)
    202230           
    203231    ##_cache[key] = weakref.ref(H)
    204     _cache[(X, Y, category)] = weakref.ref(H)
     232    _cache[key] = weakref.ref(H)
    205233    return H
    206234
    207235def 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  
    443443    EXAMPLE::
    444444
    445445        sage: import gc
     446        sage: _ = gc.collect()
    446447        sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular
    447448        sage: from sage.libs.singular.groebner_strategy import GroebnerStrategy
    448449        sage: from sage.libs.singular.ring import ring_refcount_dict
  • 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  
    402402            sage: import gc
    403403            sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular
    404404            sage: from sage.libs.singular.ring import ring_refcount_dict
     405            sage: gc.collect()  # random output
    405406            sage: n = len(ring_refcount_dict)
    406407            sage: R = MPolynomialRing_libsingular(GF(547), 2, ('x', 'y'), TermOrder('degrevlex', 2))
    407408            sage: len(ring_refcount_dict) == n + 1