# HG changeset patch
# User Simon King <simon.king@unijena.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


10  10   William Stein (20060114): Changed from Homspace to Homset. 
11  11  
12  12   Nicolas M. Thiery (200812): Updated for the new category framework 
 13  
 14   Simon King (201112): Use a weak cache for homsets 
13  15  """ 
14  16  
15  17  #***************************************************************************** 
… 
… 

36  38  from sage.misc.cachefunc import cached_function 
37  39  import types 
38  40  
39   _cache = {} 
 41  ################################### 
 42  # Use the weak "triple" dictionary 
 43  # introduced in trac ticket #715 
 44  
 45  import weakref 
 46  from sage.structure.coerce_dict import TripleDict 
 47  _cache = TripleDict(53) 
 48  
40  49  def Hom(X, Y, category=None): 
41  50  """ 
42  51  Create the space of homomorphisms from X to Y in the category ``category``. 
… 
… 

72  81  sage: Hom(FreeModule(QQ,1), FreeModule(ZZ,1)) 
73  82  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 
74  83  
 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  
75  98  To illustrate the choice of the category, we consider the 
76  99  following parents as running examples:: 
77  100  
… 
… 

155  178  # However it breaks somehow the coercion (see e.g. sage t sage.rings.real_mpfr) 
156  179  # To be investigated. 
157  180  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: 
160  184  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 sagecombinat/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 
167  191  
168  192  try: 
 193  # Apparently X._Hom_ is supposed to be cached 
169  194  return X._Hom_(Y, category) 
170  195  except (AttributeError, TypeError): 
171  196  pass 
… 
… 

182  207  else: 
183  208  raise TypeError, "Argument category (= %s) must be a category."%category 
184  209  # 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: 
187  213  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 
192  220  
193  221  # coercing would be incredibly annoying, since the domain and codomain 
194  222  # are totally different objects 
… 
… 

201  229  H = category.hom_category().parent_class(X, Y, category = category) 
202  230  
203  231  ##_cache[key] = weakref.ref(H) 
204   _cache[(X, Y, category)] = weakref.ref(H) 
 232  _cache[key] = weakref.ref(H) 
205  233  return H 
206  234  
207  235  def hom(X, Y, f): 
diff git a/sage/libs/singular/ring.pyx b/sage/libs/singular/ring.pyx
a

b


443  443  EXAMPLE:: 
444  444  
445  445  sage: import gc 
 446  sage: _ = gc.collect() 
446  447  sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular 
447  448  sage: from sage.libs.singular.groebner_strategy import GroebnerStrategy 
448  449  sage: from sage.libs.singular.ring import ring_refcount_dict 
diff git a/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/sage/rings/polynomial/multi_polynomial_libsingular.pyx
a

b


402  402  sage: import gc 
403  403  sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular 
404  404  sage: from sage.libs.singular.ring import ring_refcount_dict 
 405  sage: gc.collect() # random output 
405  406  sage: n = len(ring_refcount_dict) 
406  407  sage: R = MPolynomialRing_libsingular(GF(547), 2, ('x', 'y'), TermOrder('degrevlex', 2)) 
407  408  sage: len(ring_refcount_dict) == n + 1 