The functions FindMinimum, FindMaximum, and FindRoot have the HoldAll attribute and so have special semantics for evaluation of their arguments. First, the variables are determined from the second argument, then they are localized. Next, the function is evaluated symbolically, then processed into an efficient form for numerical evaluation. Finally, during the execution of the command, the function is repeatedly evaluated with different numerical values. Here is a list showing these steps with additional description.
|Determine variables||process the second argument; if the second argument is not of the correct form (a list of variables and starting values), it will be evaluated to get the correct form|
|Localize variables||in a manner similar to Block and Table, add rules to the variables so that any assignments given to them will not affect your Wolfram System session beyond the scope of the command and so that previous assignments do not affect the value (the variable will evaluate to itself at this stage)|
|Evaluate the function||with the locally undefined (symbolic) values of the variables, evaluate the first argument (function or equations). Note: this is a change which was instituted in Mathematica 5, so some adjustments may be necessary for code that ran in previous versions. If your function is such that symbolic evaluation will not keep the function as intended or will be prohibitively slow, you should define your function so that it only evaluates for numerical values of the variables. The simplest way to do this is by defining your function using PatternTest (), as in f[x_?NumberQ]:=definition.|
|Preprocess the function||analyze the function to help determine the algorithm to use (e.g., sum of squares -> Levenberg–Marquardt); optimize and compile the function for faster numerical evaluation if possible: for FindRoot this first involves going from equations to a function|
|Compute derivatives||compute any needed symbolic derivatives if possible; otherwise, do preprocessing needed to compute derivatives using finite differences|
|Evaluate numerically||repeatedly evaluate the function (and derivatives when required) with different numerical values|
FindFit does not have the HoldAll attribute, so its arguments are all evaluated before the commands begin. However, it uses all of the stages described above, except instead of evaluating the function, it constructs a function to minimize from the model function, variables, and provided data.
You will sometimes want to prevent symbolic evaluation, most often when your function is not an explicit formula, but a value derived through running through a program. An example of what happens and how to prevent the symbolic evaluation is shown.
The command fails because of the symbolic evaluation of the function. You can see what happens when you evaluate it inside of Block.
Of course, this is not at all what was intended for the function; it does not even depend on . What happened is that without a numerical value for , NDSolve fails, so ReplaceAll () fails because there are no rules. First just returns its first argument, which is . Since the function is meaningless unless has numerical values, it should be properly defined.
An advantage of having a simple function definition outside of FindRoot is that it can independently be tested to make sure that it is what you really intended.
From the plot, you can deduce two bracketing values for the root, so it is possible to take advantage of Brent's method to quickly and accurately solve the problem.
It may seem that symbolic evaluation just creates a bother since you have to define the function specifically to prevent it. However, without symbolic evaluation, it is hard for the Wolfram Language to take advantage of its unique combination of numerical and symbolic power. Symbolic evaluation means that the commands can consistently take advantage of benefits that come from symbolic analysis, such as algorithm determination, automatic computation of derivatives, automatic optimization and compilation, and structural analysis.