Mathematica:如何清除符号的缓存,即取消设置无模式的 DownValues

发布于 2024-10-18 11:13:55 字数 503 浏览 3 评论 0原文

我是一个糟糕的缓存器:有时,当没有人在看时,我会缓存结果而不包含完整的上下文,如下所示:

f[x_]:=f[x]=x+a;
a=2; f[1];
DownValues[f]

Out[2]= {HoldPattern[f[1]]:>3,HoldPattern[f[x_]]:>(f[x]=x+a)}

这会导致可怕的微妙错误,更重要的是,当我更改时需要清除缓存上下文。清除缓存的一种方法是完全清除符号并重复定义,但这并不是真正的解决方案。

我真正想要的是一种清除与符号关联的所有无模式 DownValues 的方法。
为了清楚起见,我将把我目前的解决方案作为答案,但如果两次失败

  • 它只会清除带有全数字参数的 DownValues
  • 出于美观原因,我想避免使用 Block 来获取向下值。

关于如何改进 ClearCache 有什么想法吗?

I'm a bad cacher: Sometimes, when no one is watching, I'll cache results without including the full context like so:

f[x_]:=f[x]=x+a;
a=2; f[1];
DownValues[f]

Out[2]= {HoldPattern[f[1]]:>3,HoldPattern[f[x_]]:>(f[x]=x+a)}

This leads to horribly subtle bugs, and, more importantly, to the need for clearing the cache when I change the context. One way of clearing the cache is to completely Clear the symbol and repeat the definitions, but this is not really a solution.

What I would really like is a method for clearing all pattern-free DownValues associated with a symbol.
For clarity, I'll include my present solution as an answer, but if fails on two counts

  • It only clears DownValues with all-numeric arguments
  • For aesthetical reasons, I'd like to avoid using Block to grab the DownValues.

Any ideas on how to improve ClearCache?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我早已燃尽 2024-10-25 11:13:55

我过去做过类似的功能(但我不记得在哪里)。

下面的代码能满足您的所有需求吗?

ClearCache[f_] := DownValues[f] = DeleteCases[DownValues[f], 
                                              _?(FreeQ[First[#], Pattern] &)]

这也许应该扩展到 UpValuesSubValues。并且 fHead 仅限于 Symbol

I've made similar functions in the past (but I can't remember where).

Does the following code do all that you need?

ClearCache[f_] := DownValues[f] = DeleteCases[DownValues[f], 
                                              _?(FreeQ[First[#], Pattern] &)]

This maybe should be extended to UpValues and SubValues. And the Head of f restricted to Symbol.

韵柒 2024-10-25 11:13:55

只是为了补充其他优秀的解决方案:如果您有一个非常大的 DownValues 列表,并且对 ClearCache 有严格的效率要求,您可以通过清除所有定义来显着加快该过程然后只重建那些有模式的。下面是一个示例:

In[1]:= 
ClearCache[f_] := 
  DownValues[f] = DeleteCases[DownValues[f], _?(FreeQ[First[#], Pattern] &)];

In[2]:= Clear[f];
f[x_] := f[x] = x;

In[4]:= f /@ Range[1000000];

In[5]:= ClearCache[f]; // Timing

Out[5]= {7.765, Null}

In[6]:= 
ClearAll[createDefs];
SetAttributes[createDefs, HoldRest];
createDefs[f_, defs_: Automatic] :=
        (createDefs[f] := (Clear[f]; defs); createDefs[f]);

In[9]:= Clear[f];
createDefs[f, f[x_] := f[x] = x]

In[11]:= f /@ Range[1000000];

In[12]:= Length[DownValues[f]]

Out[12]= 1000001

In[13]:= createDefs[f]; // Timing

Out[13]= {1.079, Null}

In[14]:= DownValues[f]

Out[14]= {HoldPattern[f[x_]] :> (f[x] = x)}

请注意,您只需使用创建函数的基于模式的定义的代码调用 createDefs 一次。在所有其他时候,您都将其称为 createDefs[f],因为它会在第一次调用时记住重新创建定义所需的代码。

您也可能不想增加巨大的缓存,但这在简单的 f[x_]:=f[x]=rhs 方法中超出了您的控制范围。换句话说,缓存可能包含大量不必要的旧内容,但在这种方法中,您无法区分旧的(不再使用的)定义和新定义。我用一个名为 Cache 的包部分解决了这个问题,可以在此处找到该包以及说明其用途的笔记本。它使您可以更好地控制缓存的大小。它有其问题,但偶尔可能有用。

Just to complement the other excellent solution: if you have a very large list of DownValues and have strict efficiency requirements for ClearCache, you can significantly speed up the process by clearing all definitions and then reconstructing only those with patterns. Here is an example:

In[1]:= 
ClearCache[f_] := 
  DownValues[f] = DeleteCases[DownValues[f], _?(FreeQ[First[#], Pattern] &)];

In[2]:= Clear[f];
f[x_] := f[x] = x;

In[4]:= f /@ Range[1000000];

In[5]:= ClearCache[f]; // Timing

Out[5]= {7.765, Null}

In[6]:= 
ClearAll[createDefs];
SetAttributes[createDefs, HoldRest];
createDefs[f_, defs_: Automatic] :=
        (createDefs[f] := (Clear[f]; defs); createDefs[f]);

In[9]:= Clear[f];
createDefs[f, f[x_] := f[x] = x]

In[11]:= f /@ Range[1000000];

In[12]:= Length[DownValues[f]]

Out[12]= 1000001

In[13]:= createDefs[f]; // Timing

Out[13]= {1.079, Null}

In[14]:= DownValues[f]

Out[14]= {HoldPattern[f[x_]] :> (f[x] = x)}

Note that you only have to call the createDefs once with the code that creates the pattern-based definitions of the function. All other times, you call it as createDefs[f], because it memoizes the code needed to re-create the definitions, on the first call.

It is also possible that you don't want to grow huge caches, but this is out of your control in the simple f[x_]:=f[x]=rhs approach. In other words, the cache may contain lots of unnecessary old stuff, but in this approach you can not tell old (no longer used) definitions from the new ones. I partially addressed this problem with a package I called Cache, which can be found here together with the notebook illustrating its use. It gives you more control over the size of the cache. It has its problems, but may occasionally be useful.

海风掠过北极光 2024-10-25 11:13:55

一旦我实现了一个方案来限制记忆值的数量(并节省内存)。在该页面上搜索记忆。这在这里可能也很有用(特别是考虑到一些标记为与此问题重复的问题)。

代码

SetAttributes[memo, HoldAll]
SetAttributes[memoStore, HoldFirst]
SetAttributes[memoVals, HoldFirst]

memoVals[_] = {};

memoStore[f_, x_] := 
 With[{vals = memoVals[f]}, 
  If[Length[vals] > 200, 
   f /: memoStore[f, First[vals]] =.;
   memoVals[f] ^= Append[Rest[memoVals[f]], x], 
   memoVals[f] ^= Append[memoVals[f], x]];
  f /: memoStore[f, x] = f[x]]

memo[f_Symbol][x_?NumericQ] := memoStore[f, x]

memoClearCache[f_Symbol] := 
 (Scan[(f /: memoStore[f, #] =.) &, memoVals[f]]; 
  f /: memoVals[f] =. )

用法和说明

此版本适用于采用单个数字参数的函数。调用 memo[f][x] 而不是 f[x] 以使用记忆版本。缓存的值仍然与 f 相关联,因此当 f 被清除时,它们就会消失。默认情况下,缓存值的数量限制为 200。使用 memoClearCache[f] 清除所有记忆值。

Once I implemented a scheme to limit the number of memoized values (and conserve memory). Search for memoization on that page. This might be useful here as well (especially considering some of the questions marked as duplicate of this one).

The code

SetAttributes[memo, HoldAll]
SetAttributes[memoStore, HoldFirst]
SetAttributes[memoVals, HoldFirst]

memoVals[_] = {};

memoStore[f_, x_] := 
 With[{vals = memoVals[f]}, 
  If[Length[vals] > 200, 
   f /: memoStore[f, First[vals]] =.;
   memoVals[f] ^= Append[Rest[memoVals[f]], x], 
   memoVals[f] ^= Append[memoVals[f], x]];
  f /: memoStore[f, x] = f[x]]

memo[f_Symbol][x_?NumericQ] := memoStore[f, x]

memoClearCache[f_Symbol] := 
 (Scan[(f /: memoStore[f, #] =.) &, memoVals[f]]; 
  f /: memoVals[f] =. )

Usage and description

This version works with functions that take a single numerical argument. Call memo[f][x] instead of f[x] to use a memoized version. Cached values are still associated with f, so when f is cleared, they are gone. The number of cached values is limited to 200 by default. Use memoClearCache[f] to clear all memoized values.

你如我软肋 2024-10-25 11:13:55

这是我目前对问题的解决方案,但正如问题中提到的那样,它并不严格寻找无模式的 DownValues,也不是很优雅。
存储 fDownValues

In[6]:= dv = DownValues[f]

Out[6]= {HoldPattern[f[1]] :> 3, HoldPattern[f[x_]] :> (f[x] = x + a)}

查找要在 Block 内清除的 DownValues,以避免立即求值

In[7]:= dv2clear = Block[{f},
  Hold@Evaluate@Cases[dv,
      HoldPattern[f[args__ /; Apply[And, NumericQ /@ Flatten[{args}]]]], {3}]]

Out[7]= Hold[{f[1]}]

应用取消设置 到持有列表中的目标 DownValues ,然后释放

In[8]:= Map[Unset, dv2clear, {2}]
ReleaseHold@%

Out[8]= Hold[{(f[1]) =.}]

这工作正常

In[10]:= DownValues[f]

Out[10]= {HoldPattern[f[x_]] :> (f[x] = x + a)}

并且可以像这样包装:

ClearCache[f_] := Module[{dv, dv2clear},
  (* Cache downvalues for use inside block *)
  dv = DownValues[f];
  (* Find the downvalues to clear in Block to avoid immediate evaluation *)
  dv2clear = Block[{f},Hold@Evaluate@Cases[dv,HoldPattern[
        f[args__ /; Apply[And, NumericQ /@ Flatten[{args}]]]], {3}]];
  (* Apply Unset to the terms inside the held list and then release *)
  ReleaseHold@Map[Unset, dv2clear, {2}];]

This is my present solution to the problem, but as mentioned in the question is doesn't strictly look for pattern-free DownValues, nor is it very elegant.
Store the DownValues for f

In[6]:= dv = DownValues[f]

Out[6]= {HoldPattern[f[1]] :> 3, HoldPattern[f[x_]] :> (f[x] = x + a)}

Find the DownValues to clear inside a Block to avoid immediate evaluation

In[7]:= dv2clear = Block[{f},
  Hold@Evaluate@Cases[dv,
      HoldPattern[f[args__ /; Apply[And, NumericQ /@ Flatten[{args}]]]], {3}]]

Out[7]= Hold[{f[1]}]

Apply Unset to the targeted DownValues inside the held list and then release

In[8]:= Map[Unset, dv2clear, {2}]
ReleaseHold@%

Out[8]= Hold[{(f[1]) =.}]

This works fine

In[10]:= DownValues[f]

Out[10]= {HoldPattern[f[x_]] :> (f[x] = x + a)}

And can be wrapped up like so:

ClearCache[f_] := Module[{dv, dv2clear},
  (* Cache downvalues for use inside block *)
  dv = DownValues[f];
  (* Find the downvalues to clear in Block to avoid immediate evaluation *)
  dv2clear = Block[{f},Hold@Evaluate@Cases[dv,HoldPattern[
        f[args__ /; Apply[And, NumericQ /@ Flatten[{args}]]]], {3}]];
  (* Apply Unset to the terms inside the held list and then release *)
  ReleaseHold@Map[Unset, dv2clear, {2}];]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文