#12941: Cache should be cleared on cloning
----------------------------------------+-----------------------------------
Reporter: hivert | Owner: hivert
Type: defect | Status: new
Priority: major | Milestone: sage-5.1
Component: combinatorics | Resolution:
Keywords: Clone, cache, days38 | Work issues:
Report Upstream: N/A | Reviewers:
Authors: Florent Hivert | Merged in:
Dependencies: | Stopgaps:
----------------------------------------+-----------------------------------
Comment (by SimonKing):
Some comments, even though I don't know the exact purpose of
!ClonableIntArray. I guess I'll divide my reply into two posts. Here is
the first, in which I explain why Florent's approach won't work.
Replying to [comment:3 hivert]:
> Should be fixed not to copy cached methods, with something as
> {{{
> dct = self.__dict__.copy()
> for s in self.__dict__:
> if isinstance(dct[s], (CachedFunction, CachedMethod)):
> del dct[s]
> res.__dict__ = dct
> }}}
That would not be enough to clear the cache for cached methods '''with
arguments'''.
Let's go through an example that should illustrate different aspects:
{{{
sage: class A:
....: def __init__(self,x):
....: self.x = x
....: @cached_method
....: def f(self,y):
....: return self.x+y
....: @cached_method
....: def g(self):
....: return self.x*2
....:
}}}
First, we copy an instance of class A before calling the cached method,
and mutate it:
{{{
sage: a = A(5)
sage: b = copy(a)
sage: b.x = 7
sage: a.f(7)
12
sage: a.g()
10
sage: b.f(7)
14
sage: b.g()
14
}}}
No surprise, everything is fine. Now, we copy the first instance of A
again, and mutate:
{{{
sage: c = copy(a)
sage: c.x = 7
sage: c.f(7)
12
sage: c.g()
10
}}}
No surprise, the cache is (wrongly) preserved.
Next, and that illustrates why Florent's suggestion is not enough to solve
the problem, we copy the instance, kill the cached methods, and then
mutate:
{{{
sage: d = copy(a)
sage: del d.f, d.g
sage: d.x = 7
sage: d.f(7)
12
sage: d.g()
14
}}}
Observation: The cached method without arguments is now fine, but the
cached method with arguments is still caching the wrong result. Indeed,
cached methods with and without arguments are different in how they store
their cache values:
{{{
sage: type(d.f)
<type 'sage.misc.cachefunc.CachedMethodCaller'>
sage: type(d.g)
<type 'sage.misc.cachefunc.CachedMethodCallerNoArgs'>
sage: d.f.cache
{((7,), ()): 12}
sage: d.g.cache
14
}}}
So, a cached method stores the values in a dictionary, while the cached
method without arguments just stores its single value. And now comes the
catch: The dictionary is stored as an argument of the object and is thus
copied! `d.f.cache` is just a shortcut for faster access:
{{{
sage: d.f.cache is d._cache__f
True
}}}
__Summary__
Deleting a cached method in the copy is enough for cached methods with no
arguments, but won't suffice for general cached methods.
--
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/12941#comment:9>
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.