Symbolic differentiation is one of the easier problems in symbolic
algebra; it is often presented as a student exercise in
artificial-intelligence courses. Even though it is easy, it remains
useful (and often underutilized) for mathematical computations such as
rootfinding, minimization and maximization of functions, and solving
ordinary differential equations. The most time-consuming part of
writing a symbolic differentiator, in many languages, is writing a
parser for the expressions to be differentiated. Fortunately, Tcl,
being an interpretive language, comes with a parser for expressions
that is available at run time. While the parser is not normally
exported to scripts, the parser interface that the instrumentor in
TclPro uses allows for script access via an extension. One advantage to
using the built-in parser is that the programmer can be certain that
the language of expressions to be differentiated is exactly the
language of expressions to be evaluated. The differentiator begins with
a Tcl expression whose derivative is to be found, and the variable with
respect to which it is being differentiated. The first thing that it
does is to se the `parser' extension to parse the expression. It then
rewrites the parse tree into a form that is suitable for evaluation as
a Tcl command. For instance, the Tcl expression,
2 * sin($x) * cos($x)
would be rewritten into the Tcl command:
{operator *} \ {{operator *} \
{constant 2.} \ {{operator sin} \ {var x}}} \ {{operator cos} \ {var
x}}
Various rewritings are then available by evaluating the command in
various namespaces. In particular, the command:
namespace eval math::symdiff::differentiate \ [linsert $parseTree 1 $varName]
differentiates the given expression with respect to the given variable.
The result is a tree in the same form: second and higher derivatives can be obtained by the same method. The differentiator itself is fairly stupid. It includes the rules for finding the derivatives of sums, differences, products, quotients and powers. It also has the basic rules for differentiating the built-in functions, and a number of these rules also invoke common code for the Chain Rule. A typical rule, in fact an unusually complex one, is the one for the two-argument arc-tangent function:
proc {math::symdiff::differentiate::operator atan2} {var f g} {
set df [eval [linsert $f 1 $var]]
set dg [eval [linsert $g 1 $var]]
return [MakeQuotient \
[MakeDifference \
[MakeProd $df $g] \
[MakeProd $f $dg]] \
[MakeSum \ [MakeProd $f $f] \ [MakeProd $g $g]]]
}
Tcl 8.5 is not far from being an extremely capable system for ad-hoc mathematical calculations; extensions such as this one point the way.