(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:
- A string (an expression string) representing the fully
parenthesized infix expression to be differentiated. The expression
string is composed of non-negative integers, variable names (single
character), and the binary operators +, -, *, /, and #
(exponentiation). You may assume that the expression string is fully
and correctly parenthesized. The expression string is terminated by a
semicolon (;).
- A single character representing the variable with respect to which you
are differentiating.
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:
- C is an integer constant.
- S and T are expressions containing the variable X.
- X is the variable with respect to which we are differentiating.
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:
- Build a binary expression tree
representing the expression.
- Differentiate the expression in the tree
with respect to the variable.
- 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:
- Always send me e-mail as plain text in the main
message body. Never send me attachments.
- I will tell you what subject line to use with each
message, and I need you to use exactly the
subject lines I give you. (I get hundreds of e-mail
messages at a time and your subject line allows me to
sort messages.)
Here is the list of things you have to turn in:
- 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.
- 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