tags:

views:

180

answers:

2

I have a differential operator that acts on two functions. To simplify the problem let's say that my operator is

A[F_,G_] := D[F,x] D[G,y]

I want to be able, if I know F, to define a differential operator AF such that AF[G] is equal to A[F,G]. The obvious way is

AF[G_] := A[F,G]

which works without any problem. But what I would really like is to arrange things so that when I call AF with different arguments G1, G2, ... the derivative D[F,x] is not re-computed every time but only once. Moreover, I would like the definition of AF to not depend on the particular form of A, since A is passed as an argument to my function.

I have read the help on Hold, HoldAll, Evaluate etc. but I cannot put these things together to get what I want. I don't even know if what I want is possible in Mathematica.

+1  A: 

With the problem you describe, I don't see a straightforward way of doing it. One thing you could do to recast it to make it dramatically easier would be to redefine A so its a function of the derivatives of F and G. If you have

A[{dFdx_,dFdy_}, {dGdx_,dGdy_}] := dFdx*dFdy

you'll be in a very good position to calculate the derivatives of F that you need and then define AF in a way that's generic with respect to A, like so:

With[{ dFdx = D[F,x], dFdy = D[F,y] },
  AF[G_] := A[{dFdx, dFdy}, {D[G, x], D[G, y]}]]

You can use With to substitute evaluated pieces into the unevaluated right-hand side of a SetDelayed form (a definition using ":=") as shown. However, if you can't make that change, things are going to get hairy, and you'll have to make some assumptions about what A is.

If A is a symbol with DownValues defined for it, and has a simple definition, then you can do the partial evaluation you want by using a Hold, doing rule substitutions, and then doing a ReleaseHold, like so:

ReleaseHold[
  Hold[AF[G_] := A[F, G]] /. DownValues[A] /. 
    HoldPattern[D[F, var_]] :> With[{eval = D[F, var]}, eval /; True]]

The With[...] bit in the second rule is a trick for forcing the evaluation of something matching a pattern inside a Hold called the "Trott-Strzebonski method", which is obscure but extremely useful for tasks like this. However, going this way really limits your interface, meaning that you can't, say, pass in a pure function for A, and with a more complicated definition this trick probably won't work either. If you can possibly manage to specify that your differential form will be a function of the actual derivatives, I strongly recommend doing so.

EDIT: I thought of a more general and robust way of doing this.

The trick then is to temporarily suppress the definition of D (the derivative operator) using Block, so the derivatives in the definition of A remain unevaluated, and then use rule-replacement to substitute in the values for the derivatives of F while wrapping everything up in a pure function to get the name substitution right, like so:

With[{fRules =
 {HoldPattern[D[F, x]] :> Evaluate[D[F, x]]}},
   Block[{D},
     With[{fn = Function[G, Evaluate[A[F, G] /. fRules]]},
       AF[G_] := fn[G]]]]
Pillsy
Thank you! This worked perfectly. I have made a few non-essential changes though to take into account the possibility of having more than one variables x,y, etc. So the code that I have used is AF = With[ {fRules = {HoldPattern[D[F, x_]] :> Evaluate[D[F, x]]}}, Block[{D}, Function[G, Evaluate[A[F, G] /. fRules]]]];
cefstat
A: 

Can you not just do:

A[F_] := With[{DF = D[F, x]}, Function[{G}, DF D[G, y]]]

That is similar to currying in a real functional programming language like F#, where you would write:

let a f =
  let df = d f x
  fun g -> df * d g y
Jon Harrop
If `A` is known and cast in the form of a function of the derivatives of `F` and `G` ahead of time, this works fine. But if it's not, you need to delay evaluation of the derivatives of `G` while forcing the evaluation of the derivatives of `F`, which requires the extra steps.
Pillsy