How to convert a rule to a memorization function?
All the methods below basically create for each rule k -> g[a, b, c,...]
a code of the form
mem : k[t_] := mem = g[a[t], b[t], c[t],...]
which is then executed. The usage is the same for all three:
ClearAll[a, b, c, d, mem];
toMemo[t][rules1]
They also work for multivariate definitions, such as toMemo[s, t][rules]
.
Method 1
toMemo[args___][rules_] :=
With[{keypat = Alternatives @@ Keys[rules],
a = Sequence @@ Function[x, x_, Listable][{args}]
},
(Insert[Hold[mem : #1[a], Set[mem]],
#2 /. w : keypat :> w[args],
{2, -1}] & @@@ rules) /. Hold -> SetDelayed;
];
Method 2
toMemo[args___][rules_] :=
With[{k = Keys@rules, v = Values@rules,
a = Sequence @@ Function[x, x_, Listable][{args}]},
ReleaseHold@MapThread[
Hold@(mem : #1[a] := mem = #2) &,
{k, v /. f : Alternatives @@ k :> f[args]}
];
];
Method 3
toMemo[args___][rules_] :=
With[{k = Keys@rules, a = Function[x, x_, Listable][{args}]},
Block[{Set, SetDelayed},
rules /. HoldPattern[f_ -> body_] :>
((mem : f @@ a := mem = #) &@
(body /. v : Alternatives @@ k :> v[args]))
] // Identity;
];
Does this do what you want?
{a[t] -> Sin[t], b[t] ->
(a[t]*Cos[t])/(2 + a[t]),
c[t] -> 1 + b[t]^2 +
a[t]*Sin[t], d[t] ->
(-b[t])*c[t] + c[t]^2 +
b[t]*Cos[t]} /. {(name_[arg_] -> val_) :>
With[{name = name}, (name[dummy_] :=
name[dummy] = With[{arg = dummy}, val])]}
After executing this, we can call
a[1]; b[1]; c[1]; d[1];
If we now check their DownValues
with e.g. ?a
or DownValues[a]
we find that results have been memoized.
Note that the order in which these functions are called matters for what is memoized. If we call e.g. b[2]
before we have called a[2]
then the DownValues
for b
will contain calls to a
for which no appropriate memoization has occured, so that will take away the benefit of memoization.