Concept programming is about correctly representing application concepts in the code. Symbolic differentiation is a relatively simple concept from mathematics, and a transformation that cheap calculators know how to do very well. It's cumbersome, it's error prone. In short, you don't want to do it manually.
Yet, a scientist who wants to introduce symbolic differentiation notations in her C, C++ or Java program cannot do so easily (papers have been written on how to do that in C++, it's hard). Mainstream programming languages today do not include a symbolic derivative feature, because it is too specialized. And they cannot easily be extended to incorporate it either.
Symbolic differentiation is a good example of application specific concept. The differentiation plugin is an example of thin tool which implements symbolic differentiation. The source code is about 400 lines of rather simple C++. You are invited to contrast this with the C++ approach.
Extending Java
Used in conjunction with Moka, the symbolic derivative plug-in recognizes the symbolic derivative notation in the following invalid Java program.
// This example shows the symbolic differentiation "plugin"
class Test
{
public static final double omega = 3.276;
public static final double theta = 0.227;
public static final double decay = 1.447E-3;
public static int main(String args[]) {
// Tabulate the following expression
for (double t = 0.0; t < 50.0; t += 0.01) {
double y = d(sin(2 * omega * t + theta) * exp(-decay * t))/dt;
System.out.println("t=" + t + ", y=" + y);
}
}
}
The plug-in can be invoked using the following command line (NB: 'derivation' is the french word for 'differentiation', which I incorrectly assumed applied in english as well):
% moka tests/derivation.java +derivation -out
The output is the following program, where the symbolic derivative has been transformed into valid Java and can now be compiled. Notice that the plug-in inserts annotation explaining the transformations that occured.
// This example shows the symbolic differentiation "plugin"
class Test
{
public static final double omega = 3.276;
public static final double theta = 0.227;
public static final double decay = 0.001447;
public static int main(String[] args)
{
// Tabulate the following expression
for(double t = 0; t < 50; t += 0.01)
{
double y =
/**d(x*y)/dz->dx/dz*y+x*dy/dz**/
/**dsin(x)/dx->cos(x)**/cos (2 * omega * t + theta) * (
/**d(x+y)/dz->dx/dz+dy/dz**/
/**d(x*y)/dz->dx/dz*y+x*dy/dz**/(
/**d(x*y)/dz->dx/dz*y+x*dy/dz**/
/**Integer Constant->0**/0 * omega + 2 *
/**dx/dy->0**/0) * t + 2 * omega *
/**dx/dx->1**/1 +
/**dx/dy->0**/0) * exp (-decay * t) + sin (2 * omega * t + theta) * (
/**dexp(x)/dx->exp(x)**/exp (-decay * t) * (
/**d(x*y)/dz->dx/dz*y+x*dy/dz**/-decay * t + -decay *
/**dx/dx->1**/1));
System.out.println ("t=" + t + ", y=" + y);
}
}
}
Symbolic Differentiation in XL
The XL pragmas are designed to support external plug-ins. Therefore, you can invoke the same differentiation plug-in on a local portion of an XL source file simply by prefixing the corresponding declaration or instruction with a pragma using the name of the plug-in, followed by possible arguments. The major difference compared to the Moka usage outlined above is that it doesn't apply to the whole source file. This is illustrated by the following XL compiler test:
// REF=.ref
import IO = XL.UI.CONSOLE
import XL.MATH
using XL.MATH
function dcos(real X) return real is
return X;
procedure Main is
with real X := 3.14159265358
with real Y := {derivation} dsin(X)/dX
IO.WriteLn "With pragma, dsin(X)/dX for X=", X, " is ", Y
with real dX := 0.1;
with real Z := dcos(X)/dX
IO.WriteLn "Without pragma, dcos(X)/dX for X=", X, " is ", Z
This test displays the following output:
With pragma, dsin(X)/dX for X=3.14159 is -1
Without pragma, dcos(X)/dX for X=3.14159 is 31.4159
The variable Y is computed by invoking the pragma, which computes cos(pi), which is -1, while the expression dcos(X)/dX is not processed by the derivative plug-in, and therefore computes pi/0.1.
Useful complements
If you need to actually deal with the resulting source code, the result of the symbolic differentiation can be further simplified by applying the constantfold plug-in. This removes the unnecessary operations from the original source code.
|