符号计算

函数 FindMinimumFindMaximumFindRoot 具有 HoldAll 属性,因此对它们参数的计算具有特殊的语义. 首先,变量由第二个参数确定,然后被局部化. 其次,函数先进行符号化计算,然后处理成用以进行数值计算的有效形式. 最后,在命令的执行过程中,该函数使用不同的数值值反复计算. 下表列出了上述步骤以及进一步的说明.

决定变量处理第二个参数;如果第二个参数不是正确的形式(变量和初始值的列表),将对其进行计算,以得到正确的形式
局部化变量用与 BlockTable 类似的方法,对变量增加规则使得对它们的任何赋值将不会影响 命令范围以外的 Wolfram 语言进程,也使得以往的赋值不影响该值(变量会在这个阶段对计算为自身)
计算函数使用变量的局部未定义的(符号)值,计算第一个参数(函数或者方程). 注:这是在 Wolfram 语言 5 中引入的一个变动,所以可能需要对运行在以前的版本上的代码进行一些调整. 如果您的函数在符号计算时不能保持您想要的函数形式或者慢得无法接受,那么您在定义函数时应该使它只对变量的数值值进行计算. 对此最简单的办法是使用 PatternTest (),如f[x_?NumberQ]:=definition 中那样.
预处理函数对函数进行分析,以帮助确定应该使用的算法(例如,平方和 -> LevenbergMarquardt);如果可能的话,对函数进行优化和编译以使数值计算更快:对于FindRoot 这首先包括从方程到函数的过程
计算导数如果可能的话,计算所有需要的符号导数;否则,进行使用有限差分计算导数所需要的预处理
数值计算反复使用不同的数值计算函数(和在必要时的导数)

命令中处理函数的步骤.

FindFit 不具有 HoldAll 属性,因此它的参数在命令开始之前都被计算. 但是,它使用如上所述所有步骤,除了一个例外,即它不进行计算函数,而是根据模型函数,变量,和所提供的数据构建一个函数来进行极小化.

有时候,您要防止进行符号计算,这往往是当您的函数不是一个明确的公式,而是通过运行一个程序所得的一个值. 我们通过一个例子来显示会发生什么情况,以及如何防止符号计算.

这里试图使用打靶法数值化地求解一个简单的边值问题.
In[1]:=
Click for copyable input
Out[1]=

由于函数的符号计算,命令失败. 当您在 Block 中计算它的时候,您可以看到是怎么回事.

这里用 的一个局部(未定义)的值,对赋给 FindRoot 的函数进行计算.
In[2]:=
Click for copyable input
Out[2]=

当然,这根本不是该函数的目的所在;它甚至不依赖于 . 问题出现在,没有 的一个数值值时,NDSolve 失败,所以ReplaceAll () 失败,因为没有规则. First 只返回它的第一个参数,即 . 由于函数在 没有数值值时是毫无意的,我们应该适当地定义它.    

这里定义一个函数,它以 的一个数值值的函数的形式返回值 .
In[3]:=
Click for copyable input

FindRoot 之外有一个简单的函数定义的一个优点是,它可以独立地被测试,以确保它就是您的目的所在.

这里画 的图形.
In[4]:=
Click for copyable input
Out[4]=

从图中,您推断出两个包围根的值,因此有可能利用布伦特方法的优势,来快速而准确地求解问题.

这里求解打靶问题.
In[5]:=
Click for copyable input
Out[5]=

看起来似乎符号计算只是创造了麻烦,因为您必须专门地定义函数来避免它. 然而,如果没有符号计算,Wolfram 语言很难利用它的综合了数值和符号功能的独特优势. 符号计算意味着命令可以持续利用来自符号分析带来的好处,比如算法决定,导数的自动计算,自动优化和编,以及结构分析.