CSE 413 Spring 2000

Assignment 3 -- Scheme Programming

Due: at the beginning of lecture on Wednesday, April 19, 2000

For this project you will be write a scheme program to differentiate simple expressions.  In case calculus is a distant memory, the rules for differentiation go something like:

Basic rules:

(d/dx) (constant) = 0
(d/dx) (x) = 1
(d/dx) (y) = 0                                        (if y does not depend on x)
(d/dx) (E1+ E2 + E3) = (d/dx)(E1) + (d/dx)(E2) + (d/dx)(E3)   	Differentiation 
								  of sums
(d/dx) (E1 * E2) = (E1 * (d/dx)(E2)) + (E2 * (d/dx)(E1)) 	Product rule
(d/dx) (xr) = r * (x)r-1                               		 Power rule

More complex rules:

(d/dx) (ex) = ex                                                              
(d/dx) (ln x) = 1/x
(da/dx) = (da/db) * (db/dx)                       	Chain rule
(d/dx) ((f(x))r) = r * (f(x))r-1 * (d/dx)(f(x))		 Applying the chain rule. 
(d/dx) (ef(x)) = ef(x) *  (d/dx)(f(x))               	  Applying the chain rule.

Your program should be able to differentiate expressions containing constants, variables, sums with an arbitrary number of terms (+ E1 E2 E3 ... En), products with two terms (* E1 E2), and exponents of the form xy where y can be an integer or a variable other than x (expt x y).

You should implement the function (diff x E) to differentiate the expression E with respect to the variable x.  Expressions should be represented in list format.  That is,

Formula List Representation
4
4
2x + 4
(+ (* 2 x) 4)
x + (x * x) 
(+ x (* x x))
3x + 4y + 6x3
(+ (* 3 x) (* 4 y) (* 6 (expt x 3)))

Examples: (Your exact output may differ, but should be algebraically equivalent.)

> (diff 'x '4)			=>  0
> (diff 'x '(* 2 x))		=> (+ (* 0 (* x)) (* 2 1)) 	   (i.e. 2)
> (diff 'x '(+ x (* x x)))	=> (+ 1 (+ (* 1 (* x)) (* x 1)))   (i.e. 1 + x + x)
> (diff 'x '(expt x 4))		=> (* 4 (expt x 3))		   (i.e. 4 * x3)

Implementation:

You should implement function (diff x E) to differentiate the expression E with respect to the variable x.

Your program must include functions to differentiate different kinds of expressions, and a dispatch table that function diff will use to determine the appropriate sub-function to handle an expression, based on the expression's operator.  Use these fragments as starting points for your code. 

(define (diff-sum x E) ...)        ; differentiate (+ x1 x2 ...)
(define (diff-product x E) ...)    ; (* x y)
(define (diff-expt x E) ...)       ; (expt x y)
;; Dispatch Table of supported operators.
 (define diff-dispatch
   (list (list '+ diff-sum)
         (list '* diff-product)
         (list 'expt diff-expt)
         ))

Be sure that the functions diff-sum, diff-product and diff-expt are defined before your dispatch table in your .scm file.   To expand the program to differentiate other functions, you should only have to write an appropriate function to do the transformation, and then add an entry to the dispatch table with the operator atom and the function name in a list. Once the code for diff is working on the basic cases, it should not need further changes to add additional kinds of expressions.

Your main diff function will look something like this:

;; Differentiate expression E w.r.t. x.
(define (diff x E)
  (cond ((number? E) (diff-constant x E))
        ;; insert code here to handle the other base case - variables
	...
        (else 	; insert code here to lookup the appropriate function in the 
		; dispatch table based on the operator in the expression,
                ; then call that function to differentiate the expression
                    (diff-func x E)))) ))

You should implement the functions: diff-sum, diff-product and diff-expt.  Your diff function should handle differentiation of numbers and symbols (single variables such as x or y) directly, as well as looking up and applying the appropriate differentiating function for sums, products, expt and any other functions you add.

Scheme Style:

Be sure to include the code above in your program exactly as written (with, of course, additions needed to implement the various functions).   That is, you should use the function names diff-sum, diff-product etc with dashes (NOT underscores). 

Good Scheme style is to define functions to abstract away from representation details. So instead of (car E) to access the operator of an expression, a better way of doing this is to define a function get-op to extract the operator from an expression, as follows:.

	(define (get-op E) (car E))

You should define similar functions to access other parts of expressions, create various kinds of expressions, and so forth.  Example: if you need to create a sum given a list of arguments, you could use a function like this:

	(define (make-sum alist) (cons '+ alist))

If you include appropriate constructor and access functions, the code that differentiates expressions can be written in terms of arguments and operators, not cars, cdrs and cadars, which should make it much more readable.

Use higher-order functions when appropriate; don't implement special-purpose map functions when you can use library functions and functional parameters to do the job.  For example, do not write your own specialized version of map that differentiates sums (instead you should use map to write diff-sum).

Testing:

Part of this assignment is to demonstrate that your program works using well-chosen test cases.   A good set of test cases verifies basic and edge cases with a reasonably small set of carefully thought out test data, not just a large scattershot test with a bunch of random expressions.  The examples listed above are only meant to illustrate how your program should work, they do not comprise a reasonable test suite!  For full credit, you must 1) create a good suite of test cases and 2) write appropriate function(s) to simplify testing.

Here is one way you could do this.  Define individual tests and a list that contains all of the tests.

(define test1 '(+ x 4))
(define test2 '(+ 9 8))
(define test-suite (list test1 test2))

Then define a function (runtest atest) that has a test as an argument, and prints its argument and the result of applying (diff 'x arg) to that argument all neatly formatted.  Then you can use that function to run an individual test, or map it over the list of tests to run all of them.  Example:

> (runtest test1)
diff x (+ x 4) => (+ 1 0)
> (map runtest tests)
diff x (+ x 4) => (+ 1 0)
diff x (+ 9 8) => (+ 0 0)
(#<void> #<void>) <--- ignore this, the return types of the 2 expressions 
			evaluated while printing newlines.
> 

This makes it easy to re-run your test cases after modifying your program.   Include the test cases and functions to process them in your Scheme file.  Be sure that it is obvious how to run the tests.

Alternative:  Instead of differentiating everything with respect to x, you might want a test cases to include both the expression and the differentiation variable.  Example:

(define test10 '(x (+ x 4)))
(define test11 '(y (+ x 4)))

Optional Extra Credit Extensions:

Be sure to have the original version of the program in perfect working order before attempting any extra credit options.  Do an electronic turn in of your code once you have the basic part of the assignment working and print out the receipt you receive.  This will serve as a record of your program without extra credit. (Our turn-in program will save all versions of your .scm file you turn in.)  After adding in any extra credit options you so desire, in your .scm file, clearly label those extra credit options added and resubmit your files via electronic turnin.  Print out a the receipt you receive and write on this receipt EXTRA CREDIT VERSION.  Turn in this receipt as well as the receipt from the version of your program without extra credit.  Here are a few suggestions for extra credit:

 What to Hand In

For this (as well as most) assignments, you should turn in your work both electronically over the web and on paper.

Electronic Submission

Turn in a copy of your Scheme source file using this turnin form.

Paper Submission

Hand in the following:

  1. A printout of the receipt you received from the online submission of the file containing your Scheme functions.  This listing will include a copy of your Scheme code.
  2. A printout showing the transcript of the Scheme session demonstrating the results produced by your test suite.  (Don't worry if there are some minor typos in the transcript - just draw a line through anything we should ignore.)
  3. If you attempted extra credit, then you should turn in 1. and 2. for your extra credit version IN ADDITION to 1. and 2. for the version of your program without extra credit.