補助記号を使用したメモ化
g
質問で示されているメモ化手法を変更して、キャッシュをクリアする必要があるたびにとの定義をh
再確立する必要がないようにすることができます。g
アイデアは、メモ化された値をandに直接保存するのではなく、補助記号に保存することです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
and と基本的に同じです。これらの定義が整っていれば、次のコマンドを使用するだけでキャッシュをクリアできます。再定義して新たに作成する必要はありません。さらに良いことに、キャッシュは次のように配置することでローカライズできます。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
た。後からメモ化を導入すると便利な場合もあります。これを行う 1 つの方法は、アドバイジングの手法を使用することです。これは、OO プログラミングのサブクラス化に類似した一種の関数型プログラミングです。関数アドバイスの特定の実装は、StackOverflow のページに定期的に表示されます。ただし、その手法は侵襲的でもあります。グローバル定義を変更せずにg
アドバイスを追加する別の手法を考えてみましょう。h
トリックは、一時的にg
とh
内で再定義することBlock
です。再定義は、最初に結果のキャッシュをチェックし、それが失敗すると、ブロックの外側から元の定義を呼び出します。g
andの元の定義に戻りましょう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}
]
この投稿を短くするために、この「コピー」機能はダウン値のみに関係しています。一般的なアドバイス機能では、アップ値、サブ値、シンボル属性なども考慮する必要があります。
この一般的なパターンは、面倒でも簡単に自動化できます。次のマクロ関数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
苦労の末、非キャッシュ バージョンのandに外部からメモ化を課すことができるようになりました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
]

LocalizeVariables
およびTrackedSymbols
オプションは、 および が を介してグローバル シンボルに持つ依存関係のg
成果物h
です。a
f