24
$\begingroup$

I recently learned that we can use Print as a monitoring tool. My favorite is Ted Ersek's example

h[f1[a1], f2[e][a2]] /. (a_ /; Print[a] :> 0)

which reveals the order in which ReplaceAll goes through parts of an expression. Clearly this is a very useful trick.

On page 41 of his book, David Wagner gave the example

FindRoot[Print[x]; Sin[x] - Cos[x], {x, .5}]

which prints the sequence of iterates generated by FindRoot along the way. That code no longer works on Mathematica version 8:

In[22]:= FindRoot[Print[x]; Sin[x] - Cos[x], {x, .5}]
During evaluation of In[22]:= x
Out[22]= {x -> 0.785398}

At first I thought this is related to the fact that we now have the EvaluationMonitor option, and FindRoot somehow weeds out superfluous subexpressions like Print. Now I know this is probably false because

Plot[Print[x]; Sin[x], {x, Pi/4, Pi/2}]

still lists all the points considered during its evaluation.

Why does FindRoot ignore Print?

$\endgroup$
1
  • 3
    $\begingroup$ I've learned recently that Plot, probably as well as FindRoot don't necessarily evaluate the whole first argument, as is, in every iteration. They sometimes partially evaluate first, and I am not sure in what cases. So you probably simply shouldn't put there what you want evaluated every time. Probably since EvaluationMonitor exists they have taken the liberty to put some optimizations in the expression preprocessing, where they felt like it. $\endgroup$
    – Rojo
    Jun 9, 2012 at 3:00

2 Answers 2

26
$\begingroup$

Try the Evaluated -> False option:

FindRoot[Print[x]; Sin[x] - Cos[x], {x, .5}, Evaluated -> False]

During evaluation of In[3]:= 0.5

During evaluation of In[3]:= 0.5

During evaluation of In[3]:= 0.5

During evaluation of In[3]:= 0.793408

During evaluation of In[3]:= 0.793408

During evaluation of In[3]:= 0.793408

During evaluation of In[3]:= 0.785398

During evaluation of In[3]:= 0.785398

During evaluation of In[3]:= 0.785398

During evaluation of In[3]:= 0.785398

During evaluation of In[3]:= 0.785398

During evaluation of In[3]:= 0.785398

Out[3]= {x -> 0.785398}

As to the Plot, try

Plot[Print[x]; Sin[x], {x, Pi/4, Pi/2}, Evaluated -> True];

During evaluation of In[5]:= x

As you see, the behavior is exactly the same as it is for FindRoot by default. The difference in default behavior can be explained by default values of the Evaluated option:

Options[#, Evaluated] & /@ {Plot, FindRoot}

{{Evaluated -> Automatic}, {Evaluated -> True}}

It seems that the Automatic value is equivalent to False in this case.

Another approach

As Albert Retey mentioned in the comment, the "standard" (and documented) way to monitor evaluations is to define objective function as black-box function by restricting its argument to numerical values only:

In[1]:= f[x_?NumericQ] := (Print[x]; Sin[x] - Cos[x])
FindRoot[f[x], {x, .5}]

During evaluation of In[1]:= 0.5

During evaluation of In[1]:= 0.5

During evaluation of In[1]:= 0.5

During evaluation of In[1]:= 0.793408

During evaluation of In[1]:= 0.793408

During evaluation of In[1]:= 0.793408

During evaluation of In[1]:= 0.785398

During evaluation of In[1]:= 0.785398

During evaluation of In[1]:= 0.785398

During evaluation of In[1]:= 0.785398

During evaluation of In[1]:= 0.785398

During evaluation of In[1]:= 0.785398

Out[2]= {x -> 0.785398}

Additional comparisons

Here I switch off autocompilation for not loading the corresponding package (it affects output of Trace):

In[1]:= ClearAll[f, x]; f[x_] := x - 1;
Trace[FindRoot[f[x], {x, .5}, Evaluated -> False, Compiled -> False], 
  TraceInternal -> True] // LeafCount
Trace[FindRoot[f[x], {x, .5}, Evaluated -> True, Compiled -> False], 
  TraceInternal -> True] // LeafCount

Out[2]= 181

Out[3]= 111

In[4]:= ClearAll[f, x]; f[x_?NumericQ] := x - 1;
Trace[FindRoot[f[x], {x, .5}, Evaluated -> False, Compiled -> False], 
  TraceInternal -> True] // LeafCount
Trace[FindRoot[f[x], {x, .5}, Evaluated -> True, Compiled -> False], 
  TraceInternal -> True] // LeafCount

Out[5]= 217

Out[6]= 261

One can see that in simple cases the option Evaluated -> True reduces number of evaluations but in more complicated cases (black-box function) it cannot help.

$\endgroup$
14
  • $\begingroup$ Evaluated is not listed as one of the options for FindRoot in the documentation. What does it do? $\endgroup$ Jun 9, 2012 at 6:58
  • 5
    $\begingroup$ It controls whether the first argument will be evaluated before the moment when the local variable (in this case x) will have concrete value assigned. See this Mathgroups thread for more information. $\endgroup$ Jun 9, 2012 at 7:03
  • 7
    $\begingroup$ It probably should be mentioned that the "standard" trick to provide a function which only evalutes for numeric arguments (f[x_?NumericQ] := (Print[x]; Sin[x] - Cos[x])) will also do the trick without the need of the undocumented option. $\endgroup$ Jun 9, 2012 at 9:31
  • $\begingroup$ It also works for Plot. Nice one! +1 $\endgroup$
    – Rojo
    Jun 9, 2012 at 14:06
  • 1
    $\begingroup$ @Michael This technique is demonstrated in the Documentation in few places, for example here. $\endgroup$ Jun 10, 2012 at 8:01
5
$\begingroup$

First, it's probably worth adding to @Rojo's comment that EvaluationMonitor was introduced in V5, so that the functionality of Wagner's code can be achieved with

FindRoot[Sin[x] - Cos[x], {x, .5}, EvaluationMonitor :> Print[x]]

Second, note that using Evaluated -> False or ?NumericQ prevents symbolic analysis of the function and prevents FindRoot from choosing Newton's method, as is done in Wagner's book. In his book, the output of Print is

x
0.5
0.793408
0.785398
0.785398

To get the essential part of Wagner's output with Evaluated -> False or a ?NumericQ function supply the Jacobian:

FindRoot[Print[x]; Sin[x] - Cos[x], {x, .5}, Evaluated -> False, 
 Jacobian -> D[{Sin[x] - Cos[x]}, {{x}}]]
(*
  0.5
  0.793408
  0.785398
  0.785398

  {x -> 0.785398}
*)

Note the initial x is missing, but otherwise the steps are the same.

Just because I like generalizing processes: Here's a generic wrapper, with a debugging hook debug that can be set to Print temporarily with Block.

ClearAll[dbFunc];
f[x_] := Sin[x] - Cos[x];
dbFunc[f_][x_?NumericQ] := (debug[x]; f[x]);
Derivative[1][dbFunc[f_]][x_] := f'[x]; (* need to Clear[Derivative] to undo this def *)
Block[{debug = Print},
 FindRoot[dbFunc[f][x], {x, .5}]
 ]
(*
  0.5
  0.793408
  0.785398
  0.785398

  {x -> 0.785398}
*)
$\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.