Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Suppose the evaluation of a function f[x_, y_] := ... takes a very long time, but the output is a not-so-complicated polynomial in x and y, say x+y. The evaluation is long for many reason, but one of these is that a lot previous defined functions are called.

Now I continue and define a function

g[x_, y_] := Some Easy Operations on f[x,y]

Of course, when I evaluate g[x, y] symbolically or with numerical values, it calls f[x ,y], right? Hence the evaluation of g is long also. But if I define

g[x_, y_] := Some Easy Operations on x+y

then the evaluation is fast. However, the relation between f and g is less obvious in the definition of g.

My questions

  • Is what I mentioned above correct?
  • Where I can find a reference to get a basic idea/some principles about how to optimize code like this?
share|improve this question
    
Without any insight into the code, for example what f is, we can not help you. For example, maybe f can be defined with Set instead of SetDelayed. You can always h[x_,y_]=f[x,y] and then work on h with g. –  Kuba Aug 10 '13 at 8:32
    
@Kuba, when use h in g, then when I evaluate g, would f will be evaluated? –  user565739 Aug 10 '13 at 8:35
    
@andre: Sorry for my typo in the post, but what I mean is that g[x_, y_] := ...f[x,y], not g[x_, y_] =: .... But thank you for your reply, because I don't know the difference between := and =. Would you mind explain a bit or a source? –  user565739 Aug 10 '13 at 8:50
    
about = and := there is reference.wolfram.com/mathematica/tutorial/… –  andre Aug 10 '13 at 9:11
    
Thanks for the Accept! –  Mr.Wizard Sep 9 '13 at 13:13
add comment

2 Answers 2

up vote 7 down vote accepted

Memoization

Yes, your understanding appears to be correct. I think possibly you want memoization.

mem : f[x_, y_] := mem = (Pause[5](*arbitrary slowdown*); x + y)

I use the Pattern name mem to remind myself of the purpose of this construct, as there are other uses.

You would now write:

g[x_, y_] := f[x, y]^2

You will observe that the first call for a particular x,y is slow, but the second call is instantaneous:

g[2, 7] // AbsoluteTiming
g[2, 7] // AbsoluteTiming

{5.0000070, 81}

{0., 81}

The computed value of f[2, 7] is stored:

?f
Global`f

f[2,7]=9

mem:f[x_,y_]:=mem=(Pause[5];x+y)

Please see Leonid Shifrin's full coverage of the subject.

Simple evaluation

A simpler reading of this question is that you merely want to symbolically evaluate each definition that is made, assuming that is possible, rather than calling the chain of functions it depends on every time. This is what was suggested to you in the comments regarding Set (=) versus SetDelayed (:=). See: Understand the difference between Set and SetDelayed.

Set evaluates the right-hand-side before making the definition. To do this properly you should guard the symbols that are used from global assignments (using Block), unless of course you want those assignments used. Here is an example:

ClearAll[f]

Block[{a, x},
  f[a_, x_] =
    Factor[1+4 a+6 a^2+4 a^3+a^4+(4+12 a+12 a^2+4 a^3) x+(6+12 a+6 a^2) x^2+(4+4 a) x^3+x^4];
]

After making this definition you can check the definition of f:

Definition[f]
f[a_, x_] = (1 + a + x)^4

Injected definitions

Jens shows another style of definition using Function:

g = Function[{x, y}, (# + h[x])^3] &@f[x, y]

(* ==> Function[{x, y}, ((x + y) + h[x])^3] *)

Pure functions surely have their place but I want to point out that similar behavior can be had with pattern-based definitions as well. You can inject the value of f[x, y] into a pattern-based SetDelayed definition just as was done about with a Function based one above. It would look like:

f[x_, y_] := x + y;

f[x, y] // ( g[x_, y_] := (# + h[x])^3 ) &

Definition[g]
g[x_, y_] := ((x + y) + h[x])^3

Note that only Slot should be used for this injection; other options such as With should not be used due to the automatic parameter renaming that will occur.

Additionally this definition should be protected form global values of x and y, so this should be wrapped in Block. We would then have:

Block[{x, y},
 ( g[x_, y_] := (# + h[x])^3 ) &[
  f[x, y]
 ]
]
share|improve this answer
add comment

In the original question, the functions f and g are defined as pattern replacement rules of the type g[x_, y_]. There is an alternative way of defining functions which can be very handy - whether it's better in your case depends on the details, but it should be mentioned for completeness:

Using Function

By defining functions such as g[x_, y_], you essentially add a (delayed) replacement rule to the DownValues of the symbol g. Using Set instead of SetDelayed in such a definition means that the replacements are made using the expression as it evaluates at the time of the definition. This is what you want to happen with your "expensive" function f.

However, what if your definition of the function g also depends on another function in addition to f - say h. And what if the definition of h is allowed to change between invocations of f? Here is an example where I use the Set (=) approach to defining g[x_, y_], to illustrate what happens when g is changed:

Clear[f, g, h, x, y]

f[x_, y_] := x + y

h[x_] := 1

g[x_, y_] = (f[x, y] + h[x])^3

(* ==> (1 + x + y)^3 *)

g[x, y]

(* ==> (1 + x + y)^3 *)

h[x_] := 2

g[x, y]

(* ==> (1 + x + y)^3 *)

Since the definition of g has used the definition of h at the time where Set was called, I can't affect the outcome of g[x, y] by subsequently changing the definition of h, as done above.

But let's say we actually want a change in h to affect f, too. One way to mix the two effects (have f evaluated at definition time but let h be evaluated only at the time f is called), is as follows:

Clear[g]

g = Function[{x, y}, (# + h[x])^3] &@f[x, y]

(* ==> Function[{x, y}, ((x + y) + h[x])^3] *)

g[x, y]

(* ==> (2 + x + y)^3 *)

h[x_] := 3

g[x, y]

(*
==> (3 + x + y)^3

Now you see first of all that f does still contain the evaluated result of f[x, y] as desired (because that was the expensive function), but at the same time it does not use the definition of the other function h until f is actually called.

In contrast to pattern definitions, the Function expression is assigned to g as an OwnValue, which I sometimes find more convenient to work with (e.g., when forming functions of functions, compositions, inverses etc). The way the above works is by exploiting the HoldAll attribute of Function which prevents h from being evaluated. On the other hand, the f[x,y] appears outside the body of Function and is therefore evaluated. It is injected into the Function only afterwards, because it appears as the argument of another anonymous function that wraps the Function.

Instead of this anonymous function construction, one can achieve the same thing by using a replacement rule for a dummy variable (fTemp) - it plays the same role as the anonymous function slot # above:

Clear[g, fTemp]
*)

g = Function[{x, y}, (fTemp + h[x])^3] /. fTemp -> f[x, y]

(* ==> Function[{x, y}, ((x + y) + h[x])^3] *)

Added note

I am assuming that the use of Block to protect the variables like x and y is not necessary in my definitions because the original question explicitly states that symbolic manipulations were performed (to get the result f[x,y] = x + y), so of course the relevant symbols must not have values assigned to them. I added Clear at the beginning just to make sure that this assumption really holds.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.