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}];]