I am trying to address the calculation time of a fairly large expression. (It is a partial derivative from an accurate thermodynamic equation of state, GERG-2004.) There is a great deal of repetition and structure, so I have a good idea of what common subexpressions to identify and calculate separately.
I have done 'manual' subexpression elimination by developing a ruleset like the following. For example, the sum of all components and density occurs frequently. In addition, some partial derivatives occur in multiple expressions, so I want to calculate them separately as well. I have crafted the replacement rules so that they are valid symbols.
nvec = Table[Symbol["n" <> ToString[i]], {i, nc}]
rules = {nvec/Total[nvec] -> xv,
Total[nvec] -> sumn ,
sumn/v -> \[Rho],
Derivative[a_, b_][\[Alpha]00[[i_]]][\[Rho], t] :>
Symbol[StringJoin["$\[Alpha]00d", ToString[i], "x", ToString[a], ToString[b]]]
Derivative[l_List, i_][\[Delta]][xv, \[Rho]] :>
Symbol[StringJoin["$[Delta]d", StringJoin[ToString /@ l], "x", ToString[i]]]
}
I substitute using the following function
replaceone[expr_, rule_] := Block[{newtemps, unique},
unique = Union@Cases[expr, rule[[1]], Infinity];
newtemps = Thread[(unique /. rule) -> unique];
Sow[newtemps];
expr /. rule
]
{newekspr, temps} = Reap[Fold[replaceone, ekspr, rules]]
newekspr
is then the original function, with all replacements performed, and temps
is a list of actual replacements done.
How can I create a compilable function that takes the remaining variables (n1, n2, t and v) as parameters, and returns the value of the expression?
I tried using LetL
, but am unable to combine the list of replacements (in temps
) with the function arguments.
To provide a simple example, this works:
attempt1[b_] :=
LetL[{temp1 := b + 2, temp2 := 3*b, rv := temp1 + temp2}, rv]
attempt1[10]
(* 42 *)
but if I provide the first argument to LetL
as (or list of Rules, or anything...)
steps = Hold[{temp1 := b + 2, temp2 := 3*b, rv := temp1 + temp2}]
How can I then use LetL
?
attempt2[b_] := LetL[Evaluate[steps], rv]
attempt2[10]
(* LetL[Hold[{temp1 := b + 2, temp2 := 3 b, rv := temp1 + temp2}], rv] *)
that didn't release the hold, and the following doesn't work either.
attempt4[b_] := LetL[Evaluate[ReleaseHold[steps]], rv];
attempt4[10]
(* During evaluation of In[41]:= With::lvws: Variable Null in local variable specification {Null} requires a value. >> *)
(* With[{Null}, With[{Null}, With[{Null}, rv]]] *)
What is the best way, that also allows me to Compile
the function?