CS 313 - Homework 7 - More Scheme
Due: Friday 11/12 at 10am
This week you are encouraged to work in groups of two. Email me if you need help finding a partner. (Working alone is ok, too.) I only need one submission per group, as always with both of your names in a comment at the top. Please submit your code for this homework as a single file hw7.rkt containing all your functions; as well as plenty of sample output (copy and paste from DrRacket's Interactions window) in a single text file hw7-output.txt. Upload both files via the HW 7 submission page by 10am on Friday.Implement the following functions. Submit sample output for each function!
- Sorting of lists of integers.
- Implement a function "qsort" that performs quicksort on a
list of integers (Sethi, problem 10.6a). Use the
first element of the list as pivot. While scheme has vectors, you
should not use them here. To receive full credit on this problem,
make sure that your sorting function has an average run-time of O(N
log N) when sorting a list with N numbers. This requires your
partition function to run in linear time (hint: tail recursion may
come in handy here). Note: your sorting function should be
non-destructive, i.e., it should construct a new sorted list without
modifying the original list. Sample output:
> (define x '(4 -2 5 3 99 2 6 1)) > x '(4 -2 5 3 99 2 6 1) > (qsort x) '(-2 1 2 3 4 5 6 99) > x '(4 -2 5 3 99 2 6 1)
- Implement a function "msort" that performs mergesort on a list of integers. Again, for full credit, make sure that your sorting function runs in O(N log N) time. This requires both your split and merge functions to run in linear time.
- Write a function that returns a list with N random integers
(use "(random k)" to get an integer between 0 and k-1), and
test your two sorting functions using such random lists.
Note: Make sure the range of your random values is at least as high as N.
Otherwise, if there are lots of duplicate values, the performance of your
sorting algorithms might degrade to quadratic.
Use the following function to print timing results:
What are the runtimes of your methods? Include sample output showing the runtimes for four lists of integers, each twice as long as the previous (e.g. 20000, 40000, 80000, and 160000 integers). Do the observed runtimes reflect the expected O(N log N) model? (You might have to do multiple runs for each size to get reliable timing numbers -- use the lowest observed number in each case.) Include answers to this question together with your sample output in a text file.(define (test-sorting x) (display "timing sorting of list of length ") (display (length x)) (newline) (let*-values (((q1 q2 q3 q4) (time-apply qsort (list x))) ((m1 m2 m3 m4) (time-apply msort (list x))) ((same-result) (if (equal? q1 m1) 'yes 'no))) (display "quicksort runtime = ") (display q3) ; runtime w/o garbage collection (display " ms") (newline) (display "mergesort runtime = ") (display m3) ; runtime w/o garbage collection (display " ms") (newline) (display "same result: ") (display same-result) (newline)))
Hints:
- Avoid computing the same values twice. Use let* to define local variables.
- Avoid calling "length", which has runtime O(N). If you do need to know the length of a list, call "length" once and store the result (using let*). Do not use "length" to check if a list is empty or has only one element. Use (null? x) to check if x is empty and use (or (null? x) (null? (cdr x))) to check if the length is <= 1. Both take constant time.
- Implement a function "qsort" that performs quicksort on a
list of integers (Sethi, problem 10.6a). Use the
first element of the list as pivot. While scheme has vectors, you
should not use them here. To receive full credit on this problem,
make sure that your sorting function has an average run-time of O(N
log N) when sorting a list with N numbers. This requires your
partition function to run in linear time (hint: tail recursion may
come in handy here). Note: your sorting function should be
non-destructive, i.e., it should construct a new sorted list without
modifying the original list. Sample output:
- Symbolic differentiation.
The basic symbolic differentiator deriv.rkt discussed in class implements the following reduction rules:
dc/dx = 0 if c is a constant or a variable different from x dx/dx = 1 d(u + v)/dx = du/dx + dv/dx d(u * v)/dx = u * dv/dx + v * du/dx
Extend the differentiator to handle exponentiation of expressions with constant exponent. Using ^ as exponentiation operator, implement the differentiation ruled(u ^ n)/dx = n * (u ^ (n-1)) * du/dx
Add a new clause to the program "deriv.rkt" and extend the interface to the data by defining appropriate functions exponentiation? and make-exponentiation. Use the symbol ^ to denote the exponentiation operator. To be able to compute the exponentiation of two numbers, we can define ^ as the built-in exponentiation function expt:> (define ^ expt) > (^ 3 4) 81
Be sure that your code performs at least the following basic simplifications: (^ x 0) should be simplified to 1,
(^ x 1) should be simplified to x,
(^ a b) should be simplified to its numerical value for numbers a and b.Some examples:
> (deriv '(^ x 3) 'x) '(* 3 (^ x 2)) > (deriv '(^ x 2) 'x) '(* 2 x) > (deriv '(^ y n) 'y) '(* n (^ y (- n 1))) > (deriv '(^ x 1) 'x) 1 > (deriv '(+ (^ x 2) (^ x 3)) 'x) '(+ (* 2 x) (* 3 (^ x 2))) > (deriv '(^ x (* y 2)) 'x) '(* (* y 2) (^ x (- (* y 2) 1))) > (deriv '(^ (* 2 x) 3) 'x) '(* (* 3 (^ (* 2 x) 2)) 2)
- Infix printing of expressions.
Implement a function "(infix exp)" that prints an infix representation of exp. Use "display" to print strings, numbers, and symbols. For full credit, parentheses should only be output where necessary. Assume expressions are composed of numbers, symbols, and binary +, -, *, and ^ expressions.
Sample output:
Be careful when parenthesizing the non-associative operations - and ^. If you want, you can simply always parenthesize these expressions, which will only cost one point penalty. To receive this last point, avoid all redundant parentheses and match the output below. In both cases, include plenty of sample output so I can see whether your code works.> (define g '(* (+ (^ x 3) x) (^ x 2))) > (infix g) (x^3 + x) * x^2 > (define h (deriv g 'x)) > h '(+ (* (+ (^ x 3) x) (* 2 x)) (* (+ (* 3 (^ x 2)) 1) (^ x 2))) > (infix h) (x^3 + x) * 2 * x + (3 * x^2 + 1) * x^2
Hints:> (infix '(- (- 1 2) (+ 3 4))) 1 - 2 - (3 + 4) > (infix '(^ a (^ b c))) a^(b^c) > (infix '(^ (^ a b) c)) a^b^c > (infix '(* (- x 2) (* (^ y (- (+ a b) 3)) 7))) (x - 2) * y^(a + b - 3) * 7
- Try to get fully parenthesized printing to work first. This should be
pretty straightforward. Sample output:
Note that the expression should be printed using "display", not returned as a list. That is, it should be just as easy to have your code produce the following output by printing square brackets instead of parentheses:> (infix '(+ 1 (* 3 4))) (1 + (3 * 4))
> (infix '(+ 1 (* 3 4))) [1 + [3 * 4]]
- Once you have fully parenthesized printing working, make a copy of your code. Then tackle dropping redundant parentheses. This it where it gets tricky. If you can't get it to work, submit the earlier version of your code and include your non-working attempt commented out (ideally with some notes explaining what works and what doesn't) . This will give you more partial credit than if your code crashes in my tests.
- Note that the "display" function doesn't return anything. Well, technically it returns
#<void>, which DrRacket doesn't print (though you can show it using "display"):
So make sure that your code only calls "display" and doesn't return anything else.> (define x (display "hello")) hello > x ; note it doesn't show a value! > (display x) #<void>
- Most likely you will need to call "display" multiple times in a row. This means
you cannot use "if" since it only expects one expression for the "then" and "else" parts.
You cannot simpy group multiple statements in parentheses since
Scheme thinks you're trying to call a function. The solution is to use "cond" instead
of "if" which allows multiple expressions for each case:
> (display 1) (display 2) ; this works 12 > ((display 1) (display 2)) ; this doesn't 12 X X application: not a procedure; expected a procedure that can be applied to arguments given: #<void> arguments...: > (if (< 1 2) ((display 1) (display 2)) ; again, this doesn't work ((display 3) (display 4))) ; nor does this 12 X X application: not a procedure; expected a procedure that can be applied to arguments given: #<void> arguments...: > (cond ((< 1 2) (display 1) (display 2)) ; this works! (else (display 3) (display 4))) ; this too! 12
- Try to get fully parenthesized printing to work first. This should be
pretty straightforward. Sample output: