UPDATE 2: much shorter version
Given a list of paired indices {i, j}={{1,2}, {3,4}, …}, I need to first evaluate a rather complicated function test[i,j,x]
(because it's too computationally costing) and then assign each copy to a function named after {i, j} with memoization. Specifically, I need an expression (as elegant as possible, though timing is more important) which effectively does the following things:
f12[x_]:=f12[x]=Evaluate[test[1,2,x]]
f34[x_]:=f34[x]=Evaluate[test[3,4,x]]
…
Note that in this example Evaluate
has no effect (due to memoization), but I want it to be done first!
UPDATE 1
Thank @SimonWoods for proposing a Function
approach and @m_goldberg for proposing a replacement rule approach. However both approaches are not quite satisfying in their own ways. For the Function
approach, I confirmed that in the simplest MWE (with no indices in f
) it does assign x^2
instead of test[x]
to f[x]
:
(f[x_] := f[x] = #) &[test[x]]
?f
But when I want to create {f12, f34, …}
I have no idea how to generalize this approach because the existence of the extra #
ruins the function definition
(ToExpression["f" <> ToString[#1] <> ToString[#2]][x_] := ToExpression["f" <> ToString[#1] <> ToString[#2]][x] = #) &[test[x]] @@@ {{1, 2}, {3, 4}}
?f12
The replacement rule approach does address this issue as shown in @m_goldberg's answer. However as I said the function test
also depends on {{1,2}, {3,4}, …}
. Specifically, one can think of this complicated function as either
test[i_, j_, x_]:=Module[{some stuff}, some complicated operations which use {i, j} and return an expression in x]
or
test12[x_]:=Module[{some stuff}, some complicated operations which return an expression in x]
test34[x_]:=Module[{some stuff}, some complicated operations which return another expression in x]
and so on. In other words, I would like to assign the evaluated result of test12[x]
(or test[1,2,x]
) to f12[x]
, that of test34[x]
(or test[3,4,x]
) to f34[x]
, so on so forth. (I should have made this point more transparent. Apology.) But the replacement rule approach seems to fail at this requirement: the code
((ToExpression["f" <> ToString[#1] <> ToString[#2]][x_] :=
ToExpression["f" <> ToString[#1] <> ToString[#2]][x] =
expr;) /. expr -> test[#1, #2, x] &) @@@ {{1, 2}, {3, 4}}
does not give f12[x_]:=ToExpression[f<>ToString[1]<>ToString[2]][x]=test[1,2,x]
; it gives expr
instead. So both approaches still do not meet my need yet.
My goal is to create a bunch of functions {f12, f34, …}
on the fly for later calculation. Those functions involve a pre-defined Module
(let me call it test
) which gives a rather complicated expression. For simplicity let us first consider the following example:
(ToExpression["f" <> ToString[#1] <> ToString[#2]][x_] :=
ToExpression["f" <> ToString[#1] <> ToString[#2]][x] = x^2;) & @@@ {{1, 2}, {3, 4}}
This example defines functions f12[x]
and f34[x]
to be x^2
with memoization which can be easily seen by using Downvalues
:
f12[#] & /@ Range[2]; DownValues[f12]
{HoldPattern[f12[1]] :> 1, HoldPattern[f12[2]] :> 4, HoldPattern[f12[x_]] :>
(ToExpression["f" <> ToString[1] <> ToString[2]][x] = x^2)}
The last element of DownValues[f12]
is of crucial importance as it tells us the expression of f12[x]
is x^2
.
Now let me use a different approach. I define a function using Module
test[x_] := Module[{a}, a = x; FullSimplify[Log[Exp[a^2]], Assumptions -> a > 0]]
which essentially gives me x^2
upon evaluation. Follow the same strategy let us define f12
and f34
:
(ToExpression["f" <> ToString[#1] <> ToString[#2]][x_] :=
ToExpression["f" <> ToString[#1] <> ToString[#2]][x] = test[x];) & @@@ {{1, 2}, {3, 4}}
and look at again the Downvalues
of f12
:
f12[#] & /@ Range[2]; DownValues[f12]
{HoldPattern[f12[1]] :> 1, HoldPattern[f12[2]] :> 4, HoldPattern[f12[x_]] :>
(ToExpression["f" <> ToString[1] <> ToString[2]][x] = test[x])}
Note that now the last element of DownValues[f12]
involves the function test
. However this is not what I want! The reason is that as I mentioned above in my calculation test[x]
is a rather complicated expression (which depends on the indices {{1,2}, {3,4}, …}
) simplified within the Module
, and I would like to assign the simplified expressions to {f12, f34, …}
instead of computing them in situ. I tried
(ToExpression["f" <> ToString[#1] <> ToString[#2]][x_] :=
ToExpression["f" <> ToString[#1] <> ToString[#2]][x] =
Evaluate[test[x]];) & @@@ {{1, 2}, {3, 4}}
But DownValues[f12]
simply gives me
{HoldPattern[f12[1]] :> 1, HoldPattern[f12[2]] :> 4, HoldPattern[f12[x_]] :>
(ToExpression["f" <> ToString[1] <> ToString[2]][x] = Evaluate[test[x]])}
which is not useful.
In short, I would like to see any manipulation with test[x]
that gives me the DownValues
to be HoldPattern[f12[x_]] :> (ToExpression["f" <> ToString[1] <> ToString[2]][x] = x^2
. In other words, I need test[x]
to be evaluated first and then assigned to {f12, f34, …}
with memoization. On this site I think (two of) the best articles talking about memoization are this one and this one, but I think neither solves my problem…
With[{t = test[x]}, f[x_] := f[x] = t]
$\endgroup$f[#] & /@ Range[5]
you'll get{x^2, x^2, x^2, x^2, x^2}
instead of{1, 4, 9, 16, 25}
. $\endgroup$Function
instead:(f[x_] := f[x] = #) &[test[x]]
$\endgroup$