Wolfram mathematica Mathematica:如何清除符号的缓存,即未设置模式自由值

Wolfram mathematica Mathematica:如何清除符号的缓存,即未设置模式自由值,wolfram-mathematica,Wolfram Mathematica,我是一个糟糕的缓存器:有时,当没有人观看时,我会缓存结果,但不包括完整的上下文,如下所示: 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)} 这导致了极其微妙的bug,更重要的是,当我更改上下文时需要清除缓存。清除缓存的一种方法是完全清除符号并重复定义,但这并不是真正的解决方案 我真正想要的是一种清除与符号关联的所有无模式下

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

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)}
这导致了极其微妙的bug,更重要的是,当我更改上下文时需要清除缓存。清除缓存的一种方法是完全
清除
符号并重复定义,但这并不是真正的解决方案

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

  • 它只清除带有所有数值参数的DownValue
  • 出于美观的原因,我希望避免使用
    Block
    来获取下行值

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

这是我目前针对这个问题的解决方案,但正如问题中提到的,它不是严格地寻找无模式的
DownValues
,也不是很优雅。
f

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

Out[6]= {HoldPattern[f[1]] :> 3, HoldPattern[f[x_]] :> (f[x] = x + a)}
查找
DownValues
以清除
块中的内容
,避免立即计算

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

Out[7]= Hold[{f[1]}]
Unset
应用于保留列表中的目标
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}];]

我以前也做过类似的函数(但我不记得在哪里)

下面的代码是否满足了您的所有需要

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

这可能应该扩展到
UpValues
SubValues
。而
f
仅限于
符号

只是为了补充另一个优秀的解决方案:如果您有一个非常大的
下行值列表
,并且对
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的包部分地解决了这个问题,这个包可以和说明其用法的笔记本一起找到。它使您能够更好地控制缓存的大小。它有它的问题,但有时可能有用

一旦我实施了一个计划(并保存内存)。在该页上搜索备忘录。这在这里可能也很有用(特别是考虑到一些标记为重复的问题)

代码

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]
清除所有已记忆的值。

@belisarius:你没有投票权的评论让我怀疑我做了什么蠢事。。。一个简单的解决方案并不意味着我是个傻瓜,是吗?@Simon我只是忘了投票。我真丢脸!那图案真漂亮。哇!这看起来和我想做的一模一样。有一点技术上的问题可以让问题多讨论几分钟:你取消了向下值清除的资格,即使它在RHS上只有一个模式——对于ClearCache Nirvana,我们可能应该只看LHS。@Janus:幸运的是,这很容易修复-请参阅编辑。(顺便说一句,涅磐?你一定非常想要这个
ClearCache
功能!)谢谢西蒙!我会让它开几个小时——因为在我还没看到它之前,当一个问题就结束时,它总是让我恼火:)谢谢,莱昂尼德。这里也列出了这种方法,这很好。我偶尔会使用它(即在构建“ClearCache”之前),但我并不喜欢它如何干扰实现过程。对于我的特殊用途,我缓存的结果非常昂贵,以至于我可以在一眨眼之间清除一年的缓存:)