Mathematica: Как очистить кеш для символа, т.е. Unset без шаблонов DownValues

Я плохой cacher: Иногда, когда никто не смотрит, я буду кэшировать результаты, не включая полный контекст:

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)}

Это приводит к ужасно тонким ошибкам и, что более важно, необходимости очистки кеша при изменении контекста. Один из способов очистки кеша - полностью Clear символ и повторить определения, но это не совсем решение.

Мне бы очень понравился метод очистки всех без шаблонов DownValues, связанных с символом.
Для ясности, я буду включать мое настоящее решение в качестве ответа, но если сбой по двум пунктам

  • Он только очищает DownValues ​​с помощью числовых аргументов
  • По эстетическим причинам я хотел бы избежать использования Block, чтобы захватить DownValues.

Любые идеи о том, как улучшить ClearCache?

Ответ 1

Я делал подобные функции в прошлом (но я не могу вспомнить, где).

Выполняет ли следующий код все, что вам нужно?

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

Это может быть расширено до UpValues и SubValues. И Head of f ограничен Symbol.

Ответ 2

Просто чтобы дополнить другое превосходное решение: если у вас есть очень большой список 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, который можно найти здесь вместе с записью, иллюстрирующей ее использование. Это дает вам больше контроля над размером кеша. У этого есть свои проблемы, но может иногда быть полезным.

Ответ 3

Как только я выполнил схему ограничить количество сохраненных значений (и сохранить память). Найдите мемонирование на этой странице. Это может быть полезно и здесь (особенно учитывая некоторые вопросы, отмеченные как дубликаты этого).

Код

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] для использования memoized версии. Кэшированные значения по-прежнему связаны с f, поэтому, когда f очищается, они исчезли. По умолчанию количество кешированных значений ограничено 200. Используйте memoClearCache[f], чтобы очистить все сохраненные значения.

Ответ 4

Это мое настоящее решение проблемы, но, как упоминалось в вопросе, не строго ищет шаблон без DownValues, и он не очень изящный.
Сохраните DownValues для f

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

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

Найдите DownValues для очистки внутри a Block, чтобы избежать непосредственной оценки

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

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

Примените Unset к целевому DownValues внутри удерживаемого списка, а затем отпустите

In[8]:= Map[Unset, dv2clear, {2}]
[email protected]%

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},[email protected]@Cases[dv,HoldPattern[
        f[args__ /; Apply[And, NumericQ /@ Flatten[{args}]]]], {3}]];
  (* Apply Unset to the terms inside the held list and then release *)
  [email protected][Unset, dv2clear, {2}];]