(Latest Revision: 11/17/2000)
11/17/00: Added Rule-2'
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://shalim.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 representing the fully parenthesized infix expression to
be differentiated. The expression is composed of non-negative
integers, variable names (single character), and the binary
operators +, -, *, /, and # (exponentiation). You may assume that
the expression is fully and correctly parenthesized. The input
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
Rule-2: The derivative of the variable with respect to which we are
differentiating is 1.
Diff(X) = 1
Rule-2': The derivative of any variable besides the
one with respect to which we are differentiating is 0.
Diff(V) = O
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. You may assume that the variable with respect to
which you are differentiating does not appear in the expression representing
the exponent. Assuming that X is not contained in expression T:
Diff( (S # T) ) = ((T * (S # (T-1))) * Diff(S))
EXAMPLES
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-1 */
ELSE IF Info(Ptr) == a constant OR Info(Ptr) == a different variable
THEN Diff <-- 0 /* Rule-2 */
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. You should choose the best place(s) in your program to apply
the simplification rules. 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.
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 two 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.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.