(Latest Revision: 11/30/2003)
(11/30/2003: minor edits)
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 program 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 four main tasks per expression:
- Build a binary expression tree
representing the expression.
- Differentiate the expression tree with respect to the variable.
- Simplify the expression tree representing the derivative.
- Print the expression corresponding to the simplified tree.
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 turn in two "phases" of this assignment:
- a "level 2.5" version, and
- a final version.
The "level 2.5" version of the program will contain level two source plus
level three source for the part of the program that performs differentiation.
For each phase of the assignment, you will turn in a printer output (hardcopy)
and you will send me an e-mail message. Please follow these rules:
- Always send me e-mail as plain text in the main message body. Never
send me attachments.
- Always use the exact subject line I specify for each message.
(I often get hundreds of e-mail messages in a week. The subject line
allows me to find, filter and sort messages.) You will lose a
significant number of points on the assignment if you use the wrong
subject line.
- Be very careful when typing the command to send e-mail. You may use
the instructions in your
Hello World! lab excercise
for guidance. Of course, you will need to make the obvious changes to
those directions -- you have to use the correct subject line and
filename.
- Always send yourself a copy of each e-mail message you send to me, and
check immediately to see if you receive the message intact.
You are responsible for sending e-mail correctly.
Here is the list of things you have to turn in:
- At the start of class on the
first due date,
place the following item on the "counter" in front of me:
- a hardcopy of your test script showing adequate testing of
the level 2.5 version of your
program.
Make sure that all of the script content shows on the paper. Make sure
all content is plainly readable and properly formatted.
- Using the subject line: CS3100,prog4.2.5 send the following item
to me by e-mail before midnight on the
first due date:
One
shell archive file
(only one) containing items 1-4.
- All source files for your level 2.5
program (*.cpp files and *.h files)
- Your test script showing adequate testing of your level 2.5 program.
- A file named 'README' containing the compilation command one should
use to compile your program.
- A copy of your 'makefile' if you used one.
- At the start of class on the
second due date,
place the following item on the "counter" in front of me:
- a hardcopy of your test script showing adequate testing of
the final version of your
program.
Make sure that all of the script content shows on the paper. Make sure
all content is plainly readable and properly formatted.
- Using the subject line: CS3100,prog4.f send the following item
to me by e-mail before midnight on the
second due date:
One
shell archive file
(only one) containing items 1-4.
- All source files for your final level
program (*.cpp files and *.h files)
- Your test script showing adequate testing of your final level program.
- A file named 'README' containing the compilation command one should
use to compile your program.
- A copy of your 'makefile' if you used one.
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