Skip to main content
6 of 10
Fixed error in rule list
Åsmund Hj
  • 398
  • 1
  • 9

'Manual' common subexpression elimination and use of LetL

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?

Åsmund Hj
  • 398
  • 1
  • 9