Symbolic Evaluation
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 | This will be done by processing 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 Mathematica session beyond the scope of the Find 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. |
Steps in processing the function for the "Find" commands.
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.
This attempts to solve a simple boundary value problem numerically using shooting.
| Out[1]= |  |
|
The command fails because of the symbolic evaluation of the function. You can see what happens when you evaluate it inside of
Block.
This evaluates the function given to FindRoot with a local (undefined) value of xp.
| Out[2]= |  |
|
Of course, this is not at all what was intended for the function; it does not even depend on
xp. What happened is that without a numerical value for
xp,
NDSolve fails, so
ReplaceAll (/.) fails because there are no rules.
First just returns its first argument, which is
x[1]. Since the function is meaningless unless
xp has numerical values, it should be defined as such.
This defines a function that returns the value x[1] as a function of a numerical value for the x'[t] at t=-1. |
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.
This makes a plot of fx1.
| Out[4]= |  |
|
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.
This solves the shooting problem.
| Out[5]= |  |
|
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
Mathematica 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.