Запоминание с использованием вспомогательного символа
Техника запоминания, представленная в вопросе, может быть изменена таким образом, что определения g
и h
не нужно переустанавливать всякий раз, когда необходимо очистить кэш. Идея состоит в том, чтобы хранить запомненные значения на вспомогательном символе, а не непосредственно на g
и h
:
g[0,k_] = 0;
g[t_,0] = e;
g[t_,k_] := memo[g, t, k] /. _memo :> (memo[g, t, k] = g[t-1,k]*a+h[t-1,k-1]*b)
h[0,k_] = 0;
h[t_,0] = f;
h[t_,k_] := memo[h, t, k] /. _memo :> (memo[h, t, k] = h[t-1,k]*c+g[t-1,k-1]*d)
Определения по существу такие же, как и в оригинальных запомненных версиях g
и h
, за исключением того, что был введен новый символ memo
. При наличии этих определений кеш можно очистить, просто используя Clear@memo
- нет необходимости заново определять g
и h
заново. Более того, кеш можно локализовать, поместив memo
в Block
, таким образом:
Block[{memo, a = 7, b = 9, c = 13, d = 0.002, e = 2, f = 1}
, Table[g[t, k], {t, 0, 100}, {k, 0, 100}]
]
Кеш сбрасывается при выходе из блока.
Запоминание с использованием Советы
Оригинальные и пересмотренные методы запоминания требовали инвазивных изменений в функциях g
и h
. Иногда удобно вводить памятку по факту. Один из способов сделать это - использовать метод , советующий - своего рода функциональное программирование, аналог подкласса в ОО-программировании. конкретная реализация функции совета регулярно появляется на страницах StackOverflow. Тем не менее, эта техника также агрессивна. Давайте рассмотрим альтернативный метод добавления рекомендаций к g
и h
без изменения их глобальных определений.
Хитрость заключается в том, чтобы временно переопределить g
и h
в пределах Block
. Переопределения сначала проверяют кеш на результат и, в случае неудачи, вызывают исходные определения извне блока. Давайте вернемся к исходным определениям g
и h
, которые блаженно не знают о запоминании:
g[0,k_]:=0
g[t_,0]:=e
g[t_,k_]:=g[t-1,k]*a+h[t-1,k-1]*b
h[0,k_]:=0
h[t_,0]:=f
h[t_,k_]:=h[t-1,k]*c+g[t-1,k-1]*d
Базовая схема для этой техники выглядит следующим образом:
Module[{gg, hh}
, copyDownValues[g, gg]
; copyDownValues[h, hh]
; Block[{g, h}
, m:g[a___] := m = gg[a]
; m:h[a___] := m = hh[a]
; (* ... do something with g and h ... *)
]
]
Временные символы gg
и hh
введены для хранения исходных определений g
и h
. Затем g
и h
локально возвращаются к новым определениям кэширования, которые при необходимости делегируют исходным определениям. Вот определение copyDownValues
:
ClearAll@copyDownValues
copyDownValues[from_Symbol, to_Symbol] :=
DownValues[to] =
Replace[
DownValues[from]
, (Verbatim[HoldPattern][from[a___]] :> d_) :> (HoldPattern[to[a]] :> d)
, {1}
]
В стремлении сделать этот пост коротким (er), эта функция «копирования» касается только понижающих значений. Средство общего консультирования также должно учитывать повышающие значения, подзначения, атрибуты символов и т. Д.
Этот общий шаблон легко, если утомительно, автоматизировать. Это делает следующая макрос-функция memoize
, представленная с небольшим комментарием:
ClearAll@memoize
SetAttributes[memoize, HoldRest]
memoize[symbols:{_Symbol..}, body_] :=
Module[{pairs, copy, define, cdv, sd, s, m, a}
, pairs = Rule[#, Unique[#, Temporary]]& /@ symbols
; copy = pairs /. (f_ -> t_) :> cdv[f, t]
; define = pairs /. (f_ -> t_) :> (m: f[a___]) ~sd~ (m ~s~ t[a])
; With[{ temps = pairs[[All, 2]]
, setup1 = Sequence @@ copy
, setup2 = Sequence @@ define }
, Hold[Module[temps, setup1; Block[symbols, setup2; body]]] /.
{ cdv -> copyDownValues, s -> Set, sd -> SetDelayed }
] // ReleaseHold
]
После долгих раздумий мы теперь можем навязывать извне не кеширующие версии g
и h
:
memoize[{g, h}
, Block[{a = 7, b = 9, c = 13, d = .002, e = 2, f = 1}
, Table[g[t, k], {t, 0, 100}, {k, 0, 100}]
]
]
Собрав все это вместе, мы теперь можем создать адаптивный Manipulate
блок:
Manipulate[
memoize[{g, h}
, Table[g[t, k], {t, 0, tMax}, {k, 0, kMax}] //
ListPlot3D[#, InterpolationOrder -> 0, PlotRange -> All, Mesh -> None] &
]
, {{tMax, 10}, 5, 25}
, {{kMax, 10}, 5, 25}
, {{a, 7}, 0, 20}
, {{b, 9}, 0, 20}
, {{c, 13}, 0, 20}
, {{d, 0.002}, 0, 20}
, {{e, 2}, 0, 20}
, {{f, 1}, 0, 20}
, LocalizeVariables -> False
, TrackedSymbols -> All
]
![Manipulate screenshot](https://i.stack.imgur.com/5OH8a.png)
Опции LocalizeVariables
и TrackedSymbols
являются артефактами зависимостей, которые g
и h
имеют от глобальных символов от a
до f
.