#11115: Rewrite cached_method in Cython
---------------------------+------------------------------------------------
   Reporter:  SimonKing    |       Owner:  jason                
       Type:  enhancement  |      Status:  needs_review         
   Priority:  major        |   Milestone:  sage-4.7             
  Component:  misc         |    Keywords:  category cython cache
     Author:  Simon King   |    Upstream:  N/A                  
   Reviewer:               |      Merged:                       
Work_issues:               |  
---------------------------+------------------------------------------------

Comment(by SimonKing):

 I improved the performance of accessing the cache even further.

 It is quite common to have methods that do not take arguments but whose
 return value should be cached. Typical example is the set of generators of
 a multivariate polynomial ring. Since sage-4.7.alpha5, it is a cached
 method.

 Obviously, if a method takes no arguments, then caching the single value
 is much easier than storing the results in a dictionary for different
 arguments. I implemented this special case in a class
 `CachedMethodCallerNoArgs`. It is automatically used if `@cached_method`
 is a applied to a method without arguments. In particular, one does not
 need to do changes in the code.

 Here is the performance. Bot `I.groebner_basis` and `I.gens` are cached
 methods (you need to take sage-4.7.alpha5 for the example):
 {{{
 sage: P.<a,b,c,d> = QQ[]
 sage: I = P*[a,b]
 sage: I.gens()
 [a, b]
 sage: I.groebner_basis()
 [a, b]
 sage: type(I.gens)
 <type 'sage.misc.cachefunc.CachedMethodCallerNoArgs'>
 sage: type(I.groebner_basis)
 <type 'sage.misc.cachefunc.CachedMethodCaller'>
 sage: timeit('I.gens()',number=10^6)
 1000000 loops, best of 3: 170 ns per loop
 sage: timeit('I.groebner_basis()',number=10^6)
 1000000 loops, best of 3: 250 ns per loop
 }}}

 That is much faster than with an unpatched sage-4.7.alpha5:
 {{{
 sage: P.<a,b,c,d> = QQ[]
 sage: I = P*[a,b]
 sage: I.groebner_basis()
 [a, b]
 sage: I.gens()
 [a, b]
 sage: timeit('I.gens()',number=10^6)
 1000000 loops, best of 3: 699 ns per loop
 sage: timeit('I.groebner_basis()',number=10^6)
 1000000 loops, best of 3: 746 ns per loop
 }}}

 To give you an idea of how fast 170 ns or 250 ns are:
 {{{
 sage: class MyClass:
 ....:     def __init__(self):
 ....:         self._v = 10
 ....:         self.__v = 10
 ....:     def m0(self):
 ....:         return 10
 ....:     def m1(self):
 ....:         return self._v
 ....:     def m2(self):
 ....:         return self.__v
 ....:
 sage: O = MyClass()
 sage: timeit('O.m0()')
 625 loops, best of 3: 1.01 µs per loop
 sage: timeit('O.m1()')
 625 loops, best of 3: 622 ns per loop
 sage: timeit('O.m2()')
 625 loops, best of 3: 621 ns per loop
 }}}

 Note that the cache is pickled -- see examples in the doc strings.

 There is one further extension. There is a class
 `sage.misc.cachefunc.ClearCacheOnPickle`, whose purpose is quite nice: If
 you have a class that inherits from `clearCacheOnPickle` then the cached
 values will ''not'' be pickled.

 That is to say: Let X be an instance of ClearCacheOnPickle and assume that
 its pickling is implemented using the `__get_newargs__` and
 `__get_state__` mantra. Then, the cache of any cached method of
 `loads(dumps(X))` will be empty (but of course the cache of X is
 preserved).

 The idea existed, but it did not work for me. So, I re-implemented it
 essentially from scratch, using the original ideas. Also, I provided doc
 tests for `ClearCacheOnPickle`; there had been none before.

 On top of sage-4.7.alpha5, I have the patches from #10296, #9944, #9138
 and #9976, and then all doc tests pass with the patch from here. But there
 should only be one dependency, namely of #9976, which provides
 introspection to interactive Cython code.

 Depends on #9976

-- 
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/11115#comment:13>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sage-trac?hl=en.

Reply via email to