Functional Problem Solving (CSC 151 2013F) : Assignments
Primary: [Front Door] [Schedule] - [Academic Honesty] [Disabilities] [Email] [FAQ] [IRC] [Teaching & Learning] [Grading]
Current: [Assignment] [EBoard] [Lab] [Outline] [Partners] [Reading]
Sections: [Assignments] [EBoards] [Examples] [Handouts] [Labs] [Outlines] [Partners] [Readings]
Reference: [Setup] - [Functions A-Z] [Functions By Topic] - [Racket] [Scheme Report (R5RS)] [R6RS] [TSPL4]
Related Courses: [Davis (2013F)] [Rebelsky (2010F)] [Weinman (2012F)]
Misc: [SamR] [Glimmer Labs] [CS@Grinnell] [Grinnell] [Issue Tracker (Course)]
Assigned: Wednesday, 27 November 2013
Due:
This is a take-home examination. You may use any time or times you deem appropriate to complete the exam, provided you return it to me by the due date.
This examination has a prologue that must be completed by the Friday afternoon before the exam is due. The prologue is intended to help you get started thinking about the examination. The prologue is optional. However, if you intend to invoke the “there's more to life” option, you must turn in the prologue by the specified deadline.
There are 10 problems on this examination. Each problem is worth 10 points, for a total of 100 points. Although each problem is worth the same amount, problems are not necessarily of equal difficulty.
Read the entire exam before you begin.
We expect that someone who has mastered the material and works at a moderate rate should have little trouble completing the exam in a reasonable amount of time. In particular, this exam is likely to take you about three to four hours, depending on how well you've learned the topics and how fast you work. You should not work more than five hours on this exam. Stop at five hours and write “There's more to life than CS” and you will earn at least 70 on this exam, provided you filled in the prologue by the specified deadline. You should count the time you spend on the prologue in the five hours. With such evidence of serious intent, your score will be the maximum of (1) your actual score out of 100, (2) the average of your best 7 answers scaled to a maximum of 90, or (3) 70. The bonus points for errors are usually not applied in such circumstances.
We will give two points of extra credit to the first two people who honestly report that they have completed the exam in four hours or less or have spent at least four hours on the exam. In the latter case, they should also report on what work they've completed in the four hours. After receiving such notices, we may change the exam.
This examination is open book, open notes, open mind, open computer, open Web. However, it is closed person. That means you should not talk to other people about the exam. Other than as restricted by that limitation, you should feel free to use all reasonable resources available to you.
As always, you are expected to turn in your own work. If you find ideas in a book or on the Web, be sure to cite them appropriately. If you use code that you wrote for a previous lab or homework, cite that lab or homework and any students who worked with you. If you use code that you found on the course Web site, be sure to cite that code. You need not cite the code provided in the body of the examination.
Although you may use the Web for this exam, you may not post your answers to this examination on the Web. And, in case it's not clear, you may not ask others (in person, via email, via IM, via IRC, by posting a please help message, or in any other way) to put answers on the Web.
Because different students may be taking the exam at different times, you are not permitted to discuss the exam with anyone until after I have returned it. If you must say something about the exam, you are allowed to say “This is among the hardest exams I have ever taken. If you don't start it early, you will have no chance of finishing.” You may also summarize these policies. You may not tell other students which problems you've finished. You may not tell other students how long you've spent on the exam.
You must include both of the following statements on the cover sheet of the examination.
Please sign and date each statement. Note that the statements must be true; if you are unable to sign either statement, please talk to me at your earliest convenience. You need not reveal the particulars of the dishonesty, simply that it happened. Note also that inappropriate assistance is assistance from (or to) anyone other than Professor Rebelsky.
You must present your exam to me in two forms: both physically and electronically. That is, you must write all of your answers using the computer, print them out, number the pages, put your name on the top of every page, and hand me the printed copy. You must also email me a copy of your exam. You should create the emailed version by copying the various parts of your exam and pasting them into an email message. In both cases, you should put your answers in the same order as the problems. Failure to name and number the printed pages will lead to a penalty of two points. Failure to turn in both versions may lead to a much worse penalty.
While your electronic version is due at 10:30 p.m. Monday, your physical copy will be submitted in class on Tuesday. It is presumed the physical copy matches the electronic copy. Any discrepancies (other than formatting) will be considered a misrepresentation of your work and referred to the Committee on Academic Standing.
In many problems, we ask you to write code. Unless we specify otherwise in a problem, you should write working code and include examples that show that you've tested the code. You should use examples other than those that may be provided with the exam. Do not include images; we should be able to regenerate those.
Unless we explicitly ask you to document your procedures, you need not write introductory comments.
Just as you should be careful and precise when you write code and documentation, so should you be careful and precise when you write prose. Please check your spelling and grammar. Because we should be equally careful, the whole class will receive one point of extra credit for each error in spelling or grammar you identify on this exam. We will limit that form of extra credit to five points.
We will give partial credit for partially correct answers. We are best able to give such partial credit if you include a clear set of work that shows how you derived your answer. You ensure the best possible grade for yourself by clearly indicating what part of your answer is work and what part is your final answer.
I may not be available at the time you take the exam. If you feel that a question is badly worded or impossible to answer, note the problem you have observed and attempt to reword the question in such a way that it is answerable. If it's a reasonable hour (8am-10pm), feel free to try to call me (cell phone - 641-990-2947).
I will also reserve time at the start of each class before the exam is due to discuss any general questions you have on the exam.
Topics: List recursion, higher-order procedures, encapsulating control.
As you may recall, we began our investigation of recursion by considering how we might step through a list of numbers, adding them (or multiplying them or ...). Here are variants of the two versions we wrote:
One uses simple recursion.
(define sum-right
(lambda (numbers)
(if (null? (cdr numbers))
(car numbers)
(+ (car numbers) (sum-right (cdr numbers))))))
The other uses a helper to accumulate the results.
(define sum-left
(lambda (numbers)
(let kernel ((so-far (car numbers))
(remaining (cdr numbers)))
(if (null? remaining)
so-far
(kernel (+ so-far (car remaining))
(cdr remaining))))))
If you think carefully about it, the two processes compute results
slightly differently. Given the list (n0 n1 n2 n3 n4),
the first computes
(+ n0 (+ n1 (+ n2 (+ n3 n4))))
while the second computes
(+ (+ (+ (+ n0 n1) n2) n3) n4)
For addition, this doesn't make a difference. If the operation were subtraction, it would certainly make a difference. (Rimshot!)
The process of combining a list of values using a binary procedure
is quite common. We've seen it for addition, subtraction, and
multiplication.
We might also use it for appending strings and many other operations.
Computer scientists have various names for such a process.
We'll call
it fold, but others use inject
(as in “inject this
operation into this list”)
or reduce (as in, “reduce this list to a
single value”).
Write, but do not document, a procedure,
(, that mimics
fold-right proc
lst)sum-right, but with proc
in place of +. That is, (fold-right
should
compute
proc (list v0 v1 v2 ... vn-1 vn))
(proc v0 (proc v1 (proc v2 (... (proc vn-1 vn) ... ))))
For example,
>(fold-right + (list 1 2 3 4))10>(fold-right * (list 1 2 3 4))24>(fold-right - (list 1 2 3 4))-2>(fold-right (lambda (s1 s2) (string-append s1 ", " s2)) (list "sentient" "malicious" "powerful" "stupid"))"sentient, malicious, powerful, stupid">(fold-right list (list 'a 'b 'c 'd 'e))(a (b (c (d e))))
Write, but do not document, a procedure,
(, that mimics
fold-left proc
lst)sum-left, but with proc
in place of +. That is, (fold-left
should compute
proc (list v0 v1 v2 ... vn-1 vn))
(proc (proc ... (proc (proc v0 v1) v2) ... vn-1) vn)
For example,
>(fold-left + (list 1 2 3 4))10>(fold-left * (list 1 2 3 4))24>(fold-left - (list 1 2 3 4))-8>(fold-left (lambda (s1 s2) (string-append s1 ", " s2)) (list "sentient" "malicious" "powerful" "stupid"))"sentient, malicious, powerful, stupid">(fold-left list (list 'a 'b 'c 'd 'e))((((a b) c) d) e)
Topics: Deep recursion, pair structures, predicates.
In the lab on trees,
you wrote a predicate color-tree?
that determines whether every leaf in a tree is a
color. Generalize this idea by writing the predicate
(, which indicates whether the
predicate tree-all? pred?
tree)pred? is satisfied for all leaves
in tree. You need not document
tree-all?.
For example,
>(tree-all? number? (cons (cons (cons 1 2) (cons 3 4)) (cons 5 (cons 6 7))))#t>(tree-all? even? (cons (cons (cons 1 2) (cons 3 4)) (cons 5 (cons 6 7))))#f>(tree-all? char? (cons (cons #\a #\b) #\c))#t>(tree-all? char? (cons (cons #\a #\b) "c"))#f>(tree-all? odd? 1)#t>(tree-all? char? 1)#f
list-subtract Topics: Higher-order procedures, code reading, documentation.
Many implementations of Scheme contain the following procedures.
(define negate
(lambda (pred?)
(lambda (val)
(not (pred? val)))))
(define select
(lambda (lst pred?)
(cond
((null? lst)
null)
((pred? (car lst))
(cons (car lst) (select (cdr lst) pred?)))
(else
(select (cdr lst) pred?)))))
(define member?
(lambda (val lst)
(and (not (null? lst))
(or (equal? val (car lst))
(member? val (cdr lst))))))
Suppose we've defined the following procedure using those standard procedures.
(define list-subtract
(lambda (lst1 lst2)
(select lst2 (negate (r-s member? lst1)))))
Read and experiment with list-subtract to understand
its purpose and use. Then write 8 Ps documentation for
list-subtract. In addition to the standard 6 Ps,
include two additional sections:
Topics: Higher-order procedures, sorting, documentation, code reading, code analysis, efficiency.
Some 151 students have decided to implement selection
sort. One of the first things they want to do is find the smallest
element in a list. They understand that “smallest” may
depend on our understanding of order. So their algorithm takes two inputs,
the list to process and a may-precede? function that
lets us determine whether one value may precede another.
And they work out the logic.
Here's their implementation.
(define smallest
(lambda (lst may-precede?)
(if (= (length lst) 1)
(car lst)
(let ([smallest-remaining (smallest (cdr lst) may-precede?)])
(if (may-precede? (car lst) smallest-remaining)
(car lst)
smallest-remaining)))))
And a few sample runs.
>(smallest (list 5 1 2 3 4 0 6) <=)0>(smallest (list 5 1 2 3 8 4 0 6) <=)0>(smallest (list 5 1 2 3 8 4 0 6) >=)8>(smallest (list "alpha" "beta" "aardvark" "foxtrot" "echo") string<=?)"aardvark"
a. Document this procedure.
b. Your instructors have some significant concerns about the running time
of this procedure. Explain why by analyzing the number of recursive calls
to the length procedure.
To do this, replace each call to the
built-in length procedure with a call to the new procedure,
my-length:
(define my-length
(lambda (lst)
(if (null? lst)
0
(+ 1 (my-length (cdr lst))))))
Augment my-length so that it counts the number of times it
is called. Do some experiments and summarize what you learn.
c. Revise the definition of smallest to address the issue
you identified in part b.
Topics: Image transformations, numeric values, anonymous procedures, RGB colors.
In this problem, we consider an approach to keeping messages secret. Steganography is the process of hiding a message in an image such that no one, other than the sender and receiver, even knows there is any hidden information. One approach to hiding an image inside a full-color image is to use the "least significant bits" to store the secret image. In the same way you're not likely to notice if two numbers far after the decimal point have changed, no one is likely to notice if the colors in a photo have been changed by only 1/8 from the original brightness values. How do we do that?
Just like the decimal numbers you're probably used to have "places" for the ones digit, tens digit, thousands digit, etc., the numbers storing the colors have eight "places" for binary bits that are either zero or one. We can shift and manipulate these binary bits by dividing and multiplying the number by powers of two (rather than powers of ten as for decimal numbers), as we do in the following.
Here is the algorithm we used to create a steganographic image.
Decoding the image is much simpler. At each pixel, for each color channel you can get the last three bits (which contain our hidden image) by taking its modulus with respect to 8 and rescaling the result to the range 0-255.
(a) Write, but do not document, a procedure,
(, that takes a
steganographic image produced using this algorithm and produces the
secret image.
image-steg-decode
steg-image)
Note: Use image-variant
in your procedure. You should write your procedure with as little repeated code as possible. However, the fewer lambdas you use to write your solution the more points you will receive. Bonus points will be given for a completely lambda-free solution.
(b) Download this image of the kitten and test your procedure on it. Describe the secret image hidden inside it.
Topics: Divide-and-conquer, numeric recursion, local procedure bindings.
We learned the divide-and-conquer strategy when studying binary search. We have also applied that strategy to the problem of sorting. Let's consider one other instance in which divide-and-conquer may help: computing cube roots.
To compute the cube root of a number, n, we start with two
estimates, one that we know is lower than the cube root and one that we
know is higher than the cube root. We repeatedly find the average of
those two numbers and refine our guess. We stop when the cube of
the average is “close enough” to n.
What should we start as the lower-bound and upper-bound of the cube root? Well, if n is at least 1, we can use 0 as the lower-bound and n as the upper bound.
For example, our procedure produces the following sequence of guesses to find the cube root of 2 with an accuracy of 3 decimal places.
>(cube-root 2.0)(lower: 0.0 upper: 2.0 avg: 1.0 avg-cubed: 1.0) (lower: 1.0 upper: 2.0 avg: 1.5 avg-cubed: 3.375) (lower: 1.0 upper: 1.5 avg: 1.25 avg-cubed: 1.953125) (lower: 1.25 upper: 1.5 avg: 1.375 avg-cubed: 2.599609375) (lower: 1.25 upper: 1.375 avg: 1.3125 avg-cubed: 2.260986328) (lower: 1.25 upper: 1.3125 avg: 1.28125 avg-cubed: 2.103302002) (lower: 1.25 upper: 1.28125 avg: 1.265625 avg-cubed: 2.02728653) (lower: 1.25 upper: 1.265625 avg: 1.2578125 avg-cubed: 1.989975452) (lower: 1.2578125 upper: 1.265625 avg: 1.26171875 avg-cubed: 2.008573234) (lower: 1.2578125 upper: 1.26171875 avg: 1.259765625 avg-cubed: 1.999259926)1.259765625
Write, but do not document, a procedure, (, which should approximate the cube
root of cube-root
n)n to three decimal places of accuracy. That
is, the difference between n and the cube of
(
should be less than 0.001. You can assume that cube-root n)n
is at least one.
Topics: Repetition, images as pixels, randomness.
Consider the following algorithm for drawing a shape.
Repeat many times:
We call this a Monte Carlo method; just like there is randomness at a casino, there is randomness in our method. You could think of this approach to drawing as like spray-painting through a stencil: each position inside the shape has some probability of being painted, but it's unpredictable which ones will actually be chosen.
Write, but do not document, a procedure,
(.
Your procedure should use the following algorithm.
stencil-quarter-circle
radius
n
color)
Create an image of size radius x radius.
Do the following n times:
Select a random column and row within the image.
If the distance from that point to the origin is less than radius,
then color the pixel.
Produce the image.
The result should look something like this:
> (image-show (stencil-quarter-circle 100 5000 (rgb-new 0 0 0)))

Topics: Numeric recursion, randomness.
The technique you just used to “spray-paint” a quarter-circle forms the basis of a Monte Carlo method for estimating the value of pi.
Consider the quarter-circle with radius 1. We select N random points where both the x and y values fall between 0 and 1. As we go along, we count how many of those points fall within the quarter-circle; call this M.
Observe that M/N is equal to the ratio between the area of the quarter-circle and the area of the unit square. So, we estimate that pi is approximately M/N * 4, and produce this value.
The larger N is, the better our estimate will be.
Write and document a procedure, (, which implements this algorithm.
estimate-pi
n)
In your sample output, show that providing larger values of
n leads to
increasingly precise estimates. For example:
>pi3.141592653589793>(estimate-pi 10)3.6>(estimate-pi 100)3.0>(estimate-pi 1000)3.204>(estimate-pi 10000)3.1304>(estimate-pi 100000)3.1503>(estimate-pi 1000000)3.141568
Topics: Strings, numeric recursion, verifying preconditions.
As you may recall, ( extracts a substring
from substring
str start
finish)str that runs from position
start to position
finish-1. The string-length
procedure lets you find the length of a string.
Write, but do not document, a procedure,
(, that generates a list of all
the substrings of all-substrings str
len)str of length
len.
For full credit, your procedure should verify its preconditions.
For example,
>(all-substrings "television" 3)("tel" "ele" "lev" "evi" "vis" "isi" "sio" "ion")>(all-substrings "cat" 3)("cat")>(all-substrings "hi" 3)Error: substrings cannot be longer than the given string.
Topics: Association lists, searching, vectors.
In standard Scheme, an association list is a list of lists. Each sublist is called a “record”. For example, consider this association list from the reading on association lists:
;;; Value:
;;; named-colors
;;; Type:
;;; List of lists.
;;; Each sublist is of length at least four and contains a name,
;;; red, green, and blue components, and a sequence of attributes.
;;; Each component is an integer between 0 and 255, inclusive.
;;; Contents:
;;; A list of common colors, their components, and some attributes.
(define named-colors
(list (list "black" 0 0 0)
(list "blah grey" 128 128 128)
(list "blood red" 102 0 0)
(list "blue" 0 0 255)
(list "green" 0 128 0)
(list "indigo" 102 0 255)
(list "medium grey" 128 128 128)
(list "orange" 255 119 0)
(list "red" 255 0 0)
(list "violet" 79 47 79)
(list "white" 255 255 255)
(list "violet red" 204 50 153)
(list "yellow" 255 255 0)))
But, we often think of records as having a fixed length, as above. If all records are the same length, would it make more sense to represent each record as a vector? For example, consider the following definition:
(define color-records
(list (vector "black" 0 0 0)
(vector "blah grey" 128 128 128)
(vector "blood red" 102 0 0)
(vector "blue" 0 0 255)
(vector "green" 0 128 0)
(vector "indigo" 102 0 255)
(vector "medium grey" 128 128 128)
(vector "orange" 255 119 0)
(vector "red" 255 0 0)
(vector "violet" 79 47 79)
(vector "white" 255 255 255)
(vector "violet red" 204 50 153)
(vector "yellow" 255 255 0)))
Storing each record as a vector allows us to look up any value in a record with equal speed. As with standard association lists, we will assume that the key is found in the first position of each record.
Write, but do not document, a procedure,
(. Your procedure should search the
assoc-vector
list-of-vectors
key)list-of-vectors until it finds a record with the given
key as its first value. If no such record is found, your
procedure should return #f.
For example,
>(assoc-vector color-records "red")#("red" 255 0 0)>(assoc-vector color-records "plaid")#f
You may not use vector->list in
solving this problem!
Here we will post answers to questions of general interest. Please check here before emailing your questions!
Here you will find errors of spelling, grammar, and design that students have noted. Remember, each error found corresponds to a point of extra credit for everyone. We usually limit such extra credit to five points. However, if we make an astoundingly large number of errors, then we will provide more extra credit. (And no, we don't count errors in the errata section or the question and answer sections.)
Many of the problems on this exam are based on (and at times copied from) problems on previous exams for the course. Those exams were written by Janet Davis, Rhys Price Jones, Samuel A. Rebelsky, John David Stone, Henry Walker, and Jerod Weinman. Many were group projects, or based upon prior examinations, so precise credit is impossible.
Some problems on this exam were inspired by conversations with our students. We thank our students for that inspiration. Usually, a combination of questions or discussions inspired a problem, so it is difficult and inappropriate to credit individual students.
Primary: [Front Door] [Schedule] - [Academic Honesty] [Disabilities] [Email] [FAQ] [IRC] [Teaching & Learning] [Grading]
Current: [Assignment] [EBoard] [Lab] [Outline] [Partners] [Reading]
Sections: [Assignments] [EBoards] [Examples] [Handouts] [Labs] [Outlines] [Partners] [Readings]
Reference: [Setup] - [Functions A-Z] [Functions By Topic] - [Racket] [Scheme Report (R5RS)] [R6RS] [TSPL4]
Related Courses: [Davis (2013F)] [Rebelsky (2010F)] [Weinman (2012F)]
Misc: [SamR] [Glimmer Labs] [CS@Grinnell] [Grinnell] [Issue Tracker (Course)]
Samuel A. Rebelsky, rebelsky@grinnell.edu
Copyright (c) 2007-2013 Janet Davis, Samuel A. Rebelsky, and Jerod Weinman. (Selected materials are copyright by John David Stone or Henry Walker and are used with permission.)

This work is licensed under a Creative Commons Attribution 3.0 Unported License. To view a copy of this
license, visit http://creativecommons.org/licenses/by-nc/3.0/
or send a letter to Creative Commons, 543 Howard Street, 5th Floor,
San Francisco, California, 94105, USA.