Skip to main content
replaced http://mathematica.stackexchange.com/ with https://mathematica.stackexchange.com/
Source Link

I have working code, but am looking for ways to make it more elegant.

I have a fairly large expression with plenty of repetition and structure. A shortened toy example is

expr = (a/(a + b))^4.5  + (b/(a + b))^3.5 + 
  (a/(a + b))^1.5 + Cosh[a + b]  + 
  Log[a/(a + b)] + Log[b/(a + b)]

I have prepared a set of rules that simplifies the expression, for example like this:

rules = {
  a + b -> sum, 
  a/sum -> g,
  b/sum -> h}

In my actual code I use pattern matching, and also create unique symbols for all the matches, see below for an example.

 Derivative[l_List, i_][δ][xv, ρ] :> 
  Symbol[StringJoin["$δd", StringJoin[ToString /@ l], "x", ToString[i]]]

The simplified expression, and the actual set of replacements is provided by 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, expr, rules]]
temps = Association[temps]

I can then prepare a function for efficient evaluation of the expression, like this, with a nested Block.

exprfun[av_, bv_] :=
 Block[{a = av, b = bv},
  Block[Evaluate[Keys[temps]], KeyValueMap[Set, temps];
   newekspr]]    

I can Compile this function, although I suspect that the result is that the entire expression is expanded and simplified again.

Compile[{a, b}, Evaluate[exprfun[a, b]]]

Is this the best way of doing this?

Can I write a higher order function that takes my original expression, and a rules set, simplifies it and provides a optimised, and possibly compiled function?

What is the benefit of a nested With, and LetLLetL, that I have seen elsewhere, compared with this approach?

I have working code, but am looking for ways to make it more elegant.

I have a fairly large expression with plenty of repetition and structure. A shortened toy example is

expr = (a/(a + b))^4.5  + (b/(a + b))^3.5 + 
  (a/(a + b))^1.5 + Cosh[a + b]  + 
  Log[a/(a + b)] + Log[b/(a + b)]

I have prepared a set of rules that simplifies the expression, for example like this:

rules = {
  a + b -> sum, 
  a/sum -> g,
  b/sum -> h}

In my actual code I use pattern matching, and also create unique symbols for all the matches, see below for an example.

 Derivative[l_List, i_][δ][xv, ρ] :> 
  Symbol[StringJoin["$δd", StringJoin[ToString /@ l], "x", ToString[i]]]

The simplified expression, and the actual set of replacements is provided by 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, expr, rules]]
temps = Association[temps]

I can then prepare a function for efficient evaluation of the expression, like this, with a nested Block.

exprfun[av_, bv_] :=
 Block[{a = av, b = bv},
  Block[Evaluate[Keys[temps]], KeyValueMap[Set, temps];
   newekspr]]    

I can Compile this function, although I suspect that the result is that the entire expression is expanded and simplified again.

Compile[{a, b}, Evaluate[exprfun[a, b]]]

Is this the best way of doing this?

Can I write a higher order function that takes my original expression, and a rules set, simplifies it and provides a optimised, and possibly compiled function?

What is the benefit of a nested With, and LetL, that I have seen elsewhere, compared with this approach?

I have working code, but am looking for ways to make it more elegant.

I have a fairly large expression with plenty of repetition and structure. A shortened toy example is

expr = (a/(a + b))^4.5  + (b/(a + b))^3.5 + 
  (a/(a + b))^1.5 + Cosh[a + b]  + 
  Log[a/(a + b)] + Log[b/(a + b)]

I have prepared a set of rules that simplifies the expression, for example like this:

rules = {
  a + b -> sum, 
  a/sum -> g,
  b/sum -> h}

In my actual code I use pattern matching, and also create unique symbols for all the matches, see below for an example.

 Derivative[l_List, i_][δ][xv, ρ] :> 
  Symbol[StringJoin["$δd", StringJoin[ToString /@ l], "x", ToString[i]]]

The simplified expression, and the actual set of replacements is provided by 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, expr, rules]]
temps = Association[temps]

I can then prepare a function for efficient evaluation of the expression, like this, with a nested Block.

exprfun[av_, bv_] :=
 Block[{a = av, b = bv},
  Block[Evaluate[Keys[temps]], KeyValueMap[Set, temps];
   newekspr]]    

I can Compile this function, although I suspect that the result is that the entire expression is expanded and simplified again.

Compile[{a, b}, Evaluate[exprfun[a, b]]]

Is this the best way of doing this?

Can I write a higher order function that takes my original expression, and a rules set, simplifies it and provides a optimised, and possibly compiled function?

What is the benefit of a nested With, and LetL, that I have seen elsewhere, compared with this approach?

Notice removed Draw attention by CommunityBot
Bounty Ended with no winning answer by CommunityBot
Tweeted twitter.com/StackMma/status/711381894345203712
Rewrote question.
Source Link
Åsmund Hj
  • 398
  • 1
  • 9

'Manual' Best approach for '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 subexpressionsworking code, but am looking for ways to identify and calculate separatelymake it more elegant.

I have done 'manual' subexpression elimination by developing a ruleset like the following. For example, the sumfairly large expression with plenty of all componentsrepetition 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 symbolsstructure. A shortened toy example is

nc=2;
nvecexpr = Table[Symbol["n"(a/(a <>+ ToString[i]],b))^4.5 {i, nc}]
+ (b/(a + b))^3.5 + 
rules = {nvec(a/Total[nvec](a ->+ xv,b))^1.5 
 + Total[nvec]Cosh[a ->+ sumn,b]  + 
 sumn Log[a/v(a ->+ ρ,
b)] Derivative[a_,+ b_][α00[[i_]]][ρ,Log[b/(a t]+ :>b)]

I have prepared a set of rules that simplifies the expression, for example like this:

rules = {
  a Symbol[StringJoin["$α00d",+ ToString[i],b "x",-> ToString[a]sum, ToString[b]]]
  a/sum -> g,
  b/sum -> h}

In my actual code I use pattern matching, and also create unique symbols for all the matches, see below for an example.

 Derivative[l_List, i_][δ][xv, ρ] :> 
  Symbol[StringJoin["$δd", StringJoin[ToString /@ l], "x", ToString[i]]]
}

I substitute usingThe simplified expression, and the actual set of replacements is provided by 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, eksprexpr, rules]]
temps = Association[temps]

newekspr is then the original function, with all replacements performed, and temps is a list of actual replacements done.

How can I createcan then prepare a compilable function that takes the remaining variables (n1, n2, t and v) as parameters, and returns the valuefor efficient evaluation of the expression?

I tried using LetL, but am unable to combine the list of replacements (in temps)like this, with the function arguments.

To provide a simple example, this works:nested Block.

attempt1[b_]exprfun[av_, bv_] := 
 LetL[Block[{temp1a := av, b += 2bv}, 
 temp2 :=Block[Evaluate[Keys[temps]], 3*bKeyValueMap[Set, rvtemps];
 := temp1 +newekspr]] temp2}, rv]
attempt1[10]

(* 42 *)

but if I provide the first argument tocan LetLCompile as (or list of Rulesthis function, or anything..although I suspect that the result is that the entire expression is expanded and simplified again.)

steps = Hold[Compile[{temp1 :=a, b + 2}, temp2 := 3*bEvaluate[exprfun[a, rv := temp1 + temp2}]b]]]

How can I then use LetLIs this the best way of doing this?

attempt2[b_] := LetL[Evaluate[steps], rv]
attempt2[10]

(* LetL[Hold[{temp1 := b + 2, temp2 := 3 b, rv := temp1 + temp2}], rv] *)

Can I write a higher order function that didn't release the holdtakes my original expression, and the following doesn't work either.a rules set, simplifies it and provides a optimised, and possibly compiled function?

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 waybenefit of a nested With, that also allows me toand Compile the functionLetL, that I have seen elsewhere, compared with this approach?

'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.

nc=2;
nvec = Table[Symbol["n" <> ToString[i]], {i, nc}]

rules = {nvec/Total[nvec] -> xv, 
  Total[nvec] -> sumn, 
 sumn/v -> ρ,
 Derivative[a_, b_][α00[[i_]]][ρ, t] :>  
   Symbol[StringJoin["$α00d", ToString[i], "x", ToString[a], ToString[b]]],

 Derivative[l_List, i_][δ][xv, ρ] :> 
  Symbol[StringJoin["$δ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?

Best approach for 'manual' common subexpression elimination

I have working code, but am looking for ways to make it more elegant.

I have a fairly large expression with plenty of repetition and structure. A shortened toy example is

expr = (a/(a + b))^4.5  + (b/(a + b))^3.5 + 
  (a/(a + b))^1.5 + Cosh[a + b]  + 
  Log[a/(a + b)] + Log[b/(a + b)]

I have prepared a set of rules that simplifies the expression, for example like this:

rules = {
  a + b -> sum, 
  a/sum -> g,
  b/sum -> h}

In my actual code I use pattern matching, and also create unique symbols for all the matches, see below for an example.

 Derivative[l_List, i_][δ][xv, ρ] :> 
  Symbol[StringJoin["$δd", StringJoin[ToString /@ l], "x", ToString[i]]]

The simplified expression, and the actual set of replacements is provided by 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, expr, rules]]
temps = Association[temps]

I can then prepare a function for efficient evaluation of the expression, like this, with a nested Block.

exprfun[av_, bv_] :=
 Block[{a = av, b = bv}, 
  Block[Evaluate[Keys[temps]], KeyValueMap[Set, temps];
   newekspr]]    

I can Compile this function, although I suspect that the result is that the entire expression is expanded and simplified again.

Compile[{a, b}, Evaluate[exprfun[a, b]]]

Is this the best way of doing this?

Can I write a higher order function that takes my original expression, and a rules set, simplifies it and provides a optimised, and possibly compiled function?

What is the benefit of a nested With, and LetL, that I have seen elsewhere, compared with this approach?

added 11 characters in body
Source Link
Åsmund Hj
  • 398
  • 1
  • 9
nc=2;
nvec = Table[Symbol["n" <> ToString[i]], {i, nc}]

rules = {nvec/Total[nvec] -> xv, 
 Total[nvec] -> sumn, 
 sumn/v -> ρ,
 Derivative[a_, b_][α00[[i_]]][ρ, t] :>  
   Symbol[StringJoin["$α00d", ToString[i], "x", ToString[a], ToString[b]]],

 Derivative[l_List, i_][δ][xv, ρ] :> 
  Symbol[StringJoin["$δd", StringJoin[ToString /@ l], "x", ToString[i]]]
}
nvec = Table[Symbol["n" <> ToString[i]], {i, nc}]

rules = {nvec/Total[nvec] -> xv, 
 Total[nvec] -> sumn, 
 sumn/v -> ρ,
 Derivative[a_, b_][α00[[i_]]][ρ, t] :>  
   Symbol[StringJoin["$α00d", ToString[i], "x", ToString[a], ToString[b]]],

 Derivative[l_List, i_][δ][xv, ρ] :> 
  Symbol[StringJoin["$δd", StringJoin[ToString /@ l], "x", ToString[i]]]
}
nc=2;
nvec = Table[Symbol["n" <> ToString[i]], {i, nc}]

rules = {nvec/Total[nvec] -> xv, 
 Total[nvec] -> sumn, 
 sumn/v -> ρ,
 Derivative[a_, b_][α00[[i_]]][ρ, t] :>  
   Symbol[StringJoin["$α00d", ToString[i], "x", ToString[a], ToString[b]]],

 Derivative[l_List, i_][δ][xv, ρ] :> 
  Symbol[StringJoin["$δd", StringJoin[ToString /@ l], "x", ToString[i]]]
}
improved format and corrected two typos in `rules`
Source Link
bbgodfrey
  • 62.1k
  • 18
  • 92
  • 160
Loading
Fixed error in rule list
Source Link
Åsmund Hj
  • 398
  • 1
  • 9
Loading
Improved introduction and describe context for problem.
Source Link
Åsmund Hj
  • 398
  • 1
  • 9
Loading
Improved introduction and describe context for problem.
Source Link
Åsmund Hj
  • 398
  • 1
  • 9
Loading
added 2 characters in body
Source Link
Åsmund Hj
  • 398
  • 1
  • 9
Loading
Notice added Draw attention by Åsmund Hj
Bounty Started worth 50 reputation by Åsmund Hj
added 52 characters in body
Source Link
Loading
Source Link
Åsmund Hj
  • 398
  • 1
  • 9
Loading