7
$\begingroup$

What is the order of computations here?

 g[x_]:=x^2;
 f[x_]:=Sqrt[g[x]];
 Map[f, Range[100]]

Does this code first gets $f(x)=x$ and then gives its values or for every $n$ it calculates $n^2$ and then its square root?

In the latter case, how can I first get $f(x)=x$?

$\endgroup$
1
  • $\begingroup$ Refine[Sqrt[x^2], x \[Element] Reals] (*Abs[x]*) $\endgroup$
    – k_v
    Jan 28, 2015 at 17:10

5 Answers 5

0
$\begingroup$
  1. If I understand your meaning there is no "function computation" in Mathematica, except in some internal routines. The code is not compiled and it is not optimized in the manner you inquire about. Instead the operations are performed in a far more direct and literal fashion. Due to the potential complexity of Mathematica functions it frequently would not make sense to attempt to pre-evaluate them in this way. When and if you want this kind of "function computation" you have to implement in manually. WReach already gave you an example of this. Here is of my own: Custom operators; custom pattern matching with pure functions.

  2. Since f does not evaluate to anything but itself it is literally mapped onto the list before any further evaluation takes place. See Scan vs. Map vs. Apply for my own description of this.

  3. While not as efficient as "function computation" would be in this case it is worth noting that since both your operations are natively Listable it is more efficient to avoid Map and apply them directly, e.g. f @ Range[100]. See case #5 in Alternatives to procedural loops and iterating over lists in Mathematica.

$\endgroup$
13
$\begingroup$

We can use some of Mathematica's built-in tracing facilities to help us answer this question.

Let's start by ensuring that the symbols we are about to use carry no extraneous definitions:

ClearAll[f, g, x]

Now, we'll establish the definitions from the question:

g[x_] := x^2
f[x_] := Sqrt[g[x]]

We can turn on selective tracing of some functions to see what is going on:

On[f, g, Sqrt]

Now, let's evaluate f for several values (here only 3 instead of 100 to keep the output manageable):

Map[f, Range[3]]

trace output

This shows us that f and g are being evaluated from first principles for each value in the range.

Should we wish to evaluate f[x] only once, applying the resultant expression to each value, then we must do something like this:

Map[Function[{x}, Evaluate@f[x]],  Range[3]]

trace output

The expression defines an anonymous function of x, whose body is the result of evaluating f[x]. It is very important that x has no value at this point -- that is why we cleared it at the beginning. Having done that, we can now see that f and g were only evaluated for x instead of for every range value.

Incidentally, observe that f[x] ultimately evaluates to Sqrt[x^2] rather than x since Mathematica does not assume that x can only be a positive real number.

The syntax used in the preceding example can be abbreviated if we use so-called "slot" notation (#):

Map[Evaluate@f[#] &,  Range[3]]

trace output

Again, we can see that f and g are not evaluated for each range element. The slot reference #1 has taken the place of the named variable x from the previous example.

Once we have completed our analysis, and are tired of seeing all those trace messages, we can turn off tracing like this:

Off[]
$\endgroup$
5
$\begingroup$

Note that you are using :=, also known by its FullForm name SetDelayed, to define your functions. According to the Documentation Center page for :=:

lhs := rhs assigns rhs to be the delayed value of lhs. rhs is maintained in an unevaluated form. When lhs appears, it is replaced by rhs, evaluated afresh each time.

This means that Sqrt[g[x]] is maintained in an unevaluated form, meaning that the latter case of your first question is how the calculation works internally; in other words, it does not conclude $f(x)=x$. More importantly, it doesn't even look at Sqrt[g[x]], except to store it as a definition.

As an additional example, consider the following:

h[x_] := Pause[1];

The definition proceeds instantly, which indicates that Mathematica doesn't even touch the definition. However, executing h[x] takes one second.

For your second question, in general it is not possible to conclude $\sqrt{x^2}=x$, unless $x$ is real and nonnegative. You can force it to use such an assumption as follows:

Refine[f[x], x > 0]
(*x*)
$\endgroup$
6
  • $\begingroup$ Thank you for your answer, the first part of my question is clear for me. Now, what should I do if I want first to calculate $g$ and then apply it to $1,\ldots,100$? The only way I know so far is to divide computations into two sessions: the first session is for calculation of $g$ and the second one if for its application. $\endgroup$
    – 8k14
    Jan 28, 2015 at 18:57
  • $\begingroup$ @8k14: What does "calculate $g$" mean? $g(x)=x^2$, so there is no simplification that can be done. Does g /@ Range[100] not do what you want? $\endgroup$ Jan 28, 2015 at 19:33
  • $\begingroup$ Sorry, I meant the calculation of $f$. $\endgroup$
    – 8k14
    Jan 28, 2015 at 19:55
  • $\begingroup$ It seems that the model code I put in my question is not good. Actually $f$ is a simple function, say a polynomial, with high computational complexity. I need to evaluate $f$ at many points that's why I want to calculate it before its application. $\endgroup$
    – 8k14
    Jan 28, 2015 at 20:03
  • $\begingroup$ @8k14: I'm still not totally sure what you're trying to do, but my best guess is that you want to simplify $f(x)$ first, and then substitute in various values of $x$. In that case, you could do f[x_] := Evaluate[(*Insert code*)] in the case that $f$ is simple enough that automatic simplification occurs, or alternately f[x_] := Evaluate[Simplify[(*Insert code*)]] in the case that more firepower is needed. By adding an Evaluate wrapper, the code inside is forcibly evaluated first, and then the resulting expression is used. $\endgroup$ Jan 28, 2015 at 20:19
3
$\begingroup$

Like k_v also proposed Refine can be used.

ClearAll[f, g, h];
g[x_] := x^2;
f[x_] := Sqrt[g[x]];
h[x_] = Block[{x}, Refine[f[x], x > 0]];
Trace@Map[h, Range[100]]

h[x]===x returns True

$\endgroup$
3
$\begingroup$

You can answer your question by using the built-in function Trace.

g[x_] := x^2
f[x_] := Sqrt[g[x]]
Trace[Map[f, Range[3]]]
{
 {Range[3], {1, 2, 3}},
 f /@ {1, 2, 3},  {f[1], f[2], f[3]},
 {f[1], Sqrt[g[1]], {g[1], 1^2, 1}, Sqrt[1], 1},
 {f[2], Sqrt[g[2]], {g[2], 2^2, 4}, Sqrt[4], 2},
 {f[3], Sqrt[g[3]], {g[3], 3^2, 9}, Sqrt[9], 3},
 {1, 2, 3}
}

From the output of Trace you can see that things happen as follows:

  1. Range[3] is replaced by {1, 2, 3}
  2. Map[f, {1, 2, 3}] is evaluated giving {f[1], f[2], f[3]}
  3. f[1] is replaced by Sqrt[g[1]]
  4. g[1] is replaced by 1^1 which is replaced by 1
  5. Sqrt[g[1]] is replaced by Sqrt[1], which is replaced by 1
  6. Now the f[2] and the f[3] argument of {f[1], f[2], f[3]} are processed in the same manner as f[1].
  7. The evaluator has now transformed Map[f, Range[3]] into {1, 2, 3}. No further transformation is possible, so evaluation ends, returning {1, 2, 3}.
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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