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$Functioninstead:(f[x_] := f[x] = #) &[test[x]]$\endgroup$