(Latest Revision: 04/07/2003)

Recursion and Binary Expression Trees: A Program that Calculates Derivatives


PRELIMINARIES:

Before working on this problem you need to know how to program with trees, strings, and C++ classes. You need to understand recursion and tree algorithms too. You need to be familiar with the directions and examples here: http://www.cs.csustan.edu/~john/Classes/General_Info/progAsgRules/


THE ASSIGNMENT:

Write a program that differentiates and simplifies an expression with respect to a variable. You do not need to know anything about differentiation. You are given a set of rules to apply to the data. Your program must store each input expression as a binary expression tree. The algorithm for calculating the derivative becomes very simple when such an expression tree is available.


INPUT:

The program reads from standard input. The input is a series of pairs of strings, each consisting of the following: The final input is a pair of zeros.

Definition: An expression is fully parenthesized when for every binary operation in the expression there is an open-parenthesis just before the first argument to the operation and a close-parenthesis just after the second argument to the operation.

SAMPLE INPUT:

(X + 1); X
((3 * X) - 5); X
(((V * 4) * X) + (7 * V)); V
0 0



OUTPUT:

The program writes to standard output. It echo-prints each pair of inputs and prints out the result of the differentiation. The output expression, like the input expression, is fully parenthesized. Also, the the output expression is simplified as much as possible. The program does not write any output corresponding to the final line of input (the two zeros).

OUTPUT FOR THE SAMPLE INPUT ABOVE:

Expression: (X + 1); X
Derivative: 1

Expression: ((3 * X) - 5); X
Derivative: 3

Expression: (((V * 4) * X) + (7 * V)); V
Derivative: ((4 * X) + 7)



DISCUSSION OF PROCESSING:

The rules for differentiating an expression are given below. When reading the statements of Rules 1-7, assume:

RULES:

Rule-1: The derivative of a constant is zero.
Diff(C) = 0  
AND the derivative of any variable besides the one with respect to which we are differentiating is 0.
Diff(V) = 0  

Rule-2: The derivative of the variable with respect to which we are differentiating is 1.
Diff(X) = 1  

Rule-3: The derivative of the sum of expressions S and T is the sum of the derivative of expression S plus the derivative of expression T.
Diff( (S + T) ) = (Diff(S) + Diff(T))  

Rule-4: The derivative of the difference between expressions S and T is the derivative of expression S minus the derivative of expression T.
Diff( (S - T) ) = (Diff(S) - Diff(T))  

Rule-5: The derivative of the product of expressions S and T is equal to the product of expression S and the derivative of expression T plus the product of expression T and the derivative of expression S.
Diff( (S * T) ) = ((S * Diff(T)) + (T * Diff(S))) 

Rule-6: The derivative of the division of expression S by expression T is equal to the product of expression T and the derivative of expression S, minus the product of expression S and the derivative of expression T, divided by the square of expression T.
Diff(S / T) = (((T * Diff(S)) - (S * Diff(T))) / (T # 2))  

Rule-7: The derivative of expression S raised to the expression T power is expression T times expression S raised to the T-1 power times the derivative of expression S. (Assume that the variable with respect to which you are differentiating does not appear in the expression representing the exponent. In other words assume X is not contained in T.)
Diff( (S # T) ) = ((T * (S # (T-1))) * Diff(S))  

EXAMPLE CALCULATIONS THAT ILLUSTRATE THE RULES (These are not sample outputs of the program.)
Example-1: Expression = (X + 1)
           Variable = X

	   Diff((X + 1)) = (Diff(X) + Diff(1))               (by Rule-3)
	   = (1 + Diff(1))                                   (by Rule 2) 
	   = (1 + 0)                                         (by Rule 1) 
	   = 1                                               (Simplification)

Example-2: Expression = ((3 * X) - 5)
           Variable = X

           Diff(((3 * X) - 5)) = (Diff((3 * X)) - Diff(5))   (by Rule-4)
	    = (((3 * Diff(X)) + (X * Diff(3))) - Diff(5))    (by Rule-5)
	    = (((3 * Diff(X)) + (X * 0)) - 0)                (by Rule-1)
	    = (((3 * 1) + (X * 0)) - 0)                      (by Rule-2)
	    = 3                                              (Simplification)
You can see that this is a recursive process, because Diff is defined in terms of calls to Diff. The base cases are Diff(C) = 0 and Diff(X) = 1 (when X is the variable with respect to which you are differentiating).

If the expression you are differentiating is stored in a binary expression tree, applying these rules to the expression is very simple. Consider the binary expression tree that represents Example-2:

                 -
               /   \	    
	      /     \
             /       \
            *         5
          /   \
         /     \
        /       \
       3         X
To differentiate the expresssion we evaluate

Diff(expression in Left Tree) - Diff(expression in Right Tree)

The basic processing of function Diff, given a pointer to a node in the tree, Ptr, and a variable with respect to which we are differentiating, V, is:

IF    Info(Ptr) == V

THEN  Diff <-- 1    /* Rule-2 */

ELSE  IF    Info(Ptr) == a constant OR Info(Ptr) == a different variable
  
      THEN  Diff <-- 0   /* Rule-1 */

      ELSE
           CASE Info(Ptr) OF
	     '+': apply Rule-3 ;
	     '-': apply Rule-4;
	     '*': apply Rule-5;
             '/': apply Rule-6;
	     '#': apply Rule-7;
	   END CASE
SIMPLIFYING THE EXPRESSION:

You have one other task in evaluating the derivative of the expression: simplifying it "as much as possible." Following are some rules for simplifying. If S is an expression:

(S + 0) = S		(0 + S) = S		(S - 0) = S
(S * 0) = 0		(0 * S) = 0		(S * 1) = S
(0 / S) = 0		(S # 0) = 1		(S # 1) = S
(S - S) = 0		(S / S) = 1
Subexpressions involving only constants and the +, -, or * operators must be evaluated (e.g. (2 + 3) becomes 5).

I will not expect your program to do "perfect simplification." On the other hand, I will take away some points if your does not do a "fair" job on simplification.

Probably the easiest way to deal with the problem of simplification is to "ignore it" at first. Just write a function that returns the derivative of an expression tree. Once you have that working write another function that inputs an expression tree and returns a simplification of it. You can then use your simplification function on the outputs of your differentiation function.

Your program has three main tasks per expression:
  1. Build a binary expression tree representing the expression.

  2. Differentiate the expression in the tree with respect to the variable.

  3. Simplify the expression representing the derivative and print the result.


TESTING:

You are responsible for deciding what sort of tests need to be done on your program to check it for correctness. I expect you to design your own test inputs. The sample inputs illustrated in this document are not adequate for thorough testing. Your test scripts must demonstrate adequate code coverage and data coverage.

When I do my testing of your program, time will be of the essence because I will be testing the programs of many students in your class and in other classes. I will prepare one or more files containing inputs to test your programs. I will run your program in a mode like this:

myNameForYourProgram < myinput > myoutput

I will then examine the contents of myoutput to see if it differs significantly from the output file I get when I run my own solution program.

If I have to change one of my input files in order to get your program to accept it, you will lose points.


WHAT TO TURN IN:

You will be sending me two e-mail messages. Please follow these rules: Here is the list of things you have to turn in:
  1. Send the following items to me by e-mail before midnight on the first due date:

    A "level 2.5" version of the source code (level two source plus level three source for the part of the program that performs differentiation) and a script showing your test runs. Include all the source files (*.h files and *.cpp files) that are required to compile the program into an executable image -- everything I need so that I can compile and test your program. Combine all the source files and the script into one shell archive file and e-mail me the archive file with the subject line: CS3100,prog4.2.5.

  2. Send the following items to me by e-mail before midnight on the second due date:

    A final version of the source code and a script showing your test runs. Include all the source files (*.h files and *.cpp files) that are required to compile the program into an executable image -- everything I need so that I can compile and test your program. Combine all the source files and the script into one shell archive file and e-mail me the archive file with the subject line: CS3100,prog4.f.
Note that there are no spaces in the subject lines given. It is important that you do not insert any spaces. My e-mail address is: john@ishi.csustan.edu.


DUE DATES:

For the due dates, see the class schedule.




Historical Note: This assignment has "been around" for quite a while. It may have been inspired originally by the DOE Macsyma project:

http://maxima.sourceforge.net/

http://www.franz.com/about/company.history.lhtml

http://www.ma.utexas.edu/pipermail/maxima/2001/001119.html