Mathematica: как очистить кэш для символа, т. Е. Сбросить безналичные значения DownValues - PullRequest
21 голосов
/ 23 февраля 2011

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

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 символ и повторение определений, но это не совсем решение.

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

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

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

Ответы [ 4 ]

23 голосов
/ 23 февраля 2011

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

Может ли следующий код делать все, что вам нужно?

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

Возможно, это должнобыть расширен до UpValues и SubValuesHead из f ограничено Symbol.

8 голосов
/ 23 февраля 2011

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

6 голосов
/ 14 января 2012

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

Код

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], чтобы очистить все запомненные значения.

3 голосов
/ 23 февраля 2011

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

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

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

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

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}];]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...