MASSACHVSETTS INSTITVTE OF TECHNOLOGY
Department of Electrical Engineering and Computer Science
6.001--Structure and Interpretation of Computer Programs
Spring Semester, 1998

Problem Set 1 Solutions

The purpose of these exercises was for you to understand how to create procedures and how you can pass them as arguments to other procedures.

Computer Exercise 1:

Part A:

To create a picture that is upside down with respect to the one generated by the example we need the brightness to increase uniformly as you move diagonally from black near (0, 127) to white near (127, 0). This implies that diagonal lines with a positive slope should have a constant brightness value. This is achieved by letting the brightness at point (x, y) be x - y. The following procedure call achieves this behavior:

        (picture-display g2 (procedure->picture 128 128 -))

Part B:

For the brightness to increase horizontally from left to right, each vertical line should have a constant brightness and the brightness should increase as we move to the right. By letting the brightness at point (x, y) be x we get the correct gradient. The following procedures implement this:

        (define (left-to-right x y) x)

        (picture-display g3 (procedure->picture 128 128 left-to-right))

Alternatively, we could use a lambda expression in substitution of the left-to-right procedure:

        (picture-display g3 (procedure->picture 128 128 (lambda(x y) x)))

Part C:

To obtain a pattern where the brightness increases uniformly as we move outward from the center of the window, each circle around the center should have a constant brightness. Thus, we could let the brightness at point (x, y) be sqrt(x^2 + y^2).

However, we also need to consider that the coordinates of our windows go from 0 to 128 on each axis, so we need to place the centers of the circles at the center of the window (i.e. (64, 64) ) by shifting each circle 64 units in the x-direction and 64 units in the y-direction. Hence, the brightness at point (x, y) should be sqrt((x - 64)^2 + (y - 64)^2). The following procedures implement this:

        (define (outwards x y)
          (sqrt (+ (square (- x 64)) (square (- y 64)))))

        (picture-display g1 (procedure->picture 128 128 outwards))

Again, we could use a lambda expression in place of the procedure outwards:

        (picture-display g1 (procedure->picture 128 128
                              (lambda (x y)
                                (sqrt (+ (square(- x 64)) (square(- y 64)))))))

Computer Exercise 2:

The cosine-y-grate procedure should look something like this. Note that when given an f, the procedure returns a picture that is ready to be displayed with the picture-display procedure.

        (define (cosine-y-grate f)
          (procedure->picture 128 128 (lambda (x y) (cos (* f y)))))

Computer Exercise 3:

The cosine-x-grate procedure should be as follows:

        (define (cosine-x-grate f)
          (procedure->picture 128 128 (lambda (x y) (cos (* f x)))))

Computer Exercise 4:

To make the bands run diagonally, we use the cosine of the sum of x and y. Just as we saw on the example on exercise 1, this yields lines that run diagonally with a slope of -1. To obtain a cosine grating that runs diagonally with a slope of 1 (just as in part (A) of exercise 1), we should take the cosine of x - y. Here's the procedure that yields a diagonal cosine grating with a slope of -1:

        (define (cosine-x-and-y-grate f)
          (procedure->picture 128 128 (lambda (x y) (cos (* f (+ x y))))))

Computer Exercise 5:

The purpose of this exercise was to show you how you can use procedural abstractions in order to simplify certain programming tasks. In order to obtain the given cosine grate you were asked to first define a procedure that yields the new multiplied-cosines grating directly from the corresponding value at each point (x, y). Then you were asked to use the picture-map abstractions as well as the abstractions you created in exercises 2 and 3 to yield the same grating.

Part A:

Cosine-multiplied grating calculated at each point:

        (define (cosine-mul-grate f1 f2)
          (procedure->picture 128 128 (lambda(x y) (* (cos (* f1 x))
                                                      (cos (* f2 y))))))

Part B:

Now, we use the picture-map, cosine-x-grate and cosine-y-grate abstractions:

        (define (cosine-mul-map-grate f1 f2)
          (picture-map * (cosine-x-grate f1) (cosine-y-grate f2)))

Note that both approaches yield the same behavior. In part (A) we explicitly let the value at each point (x, y) be cos f1x cos f2y. In part (B), we first generate two pictures: the first will have a value of cos f1x at each point (x, y) while the second will have a value of cos f2y. We use the procedures we defined in exercises 2 and 3 to obtain these two pictures. Then, we use the picture-map abstraction to multiply the value of the two pictures at each point (x, y) which will yield a third picture with a value of cos f1x cos f2y at each point.

Computer Exercise 6:

By careful inspection of the mixed picture we can guess that the grating used to mix the pictures is diagonal and has a negative slope. From exercise 4, we know that we can obtain this kind of grating by taking the cosine of x + y. From exercises 2, 3 and 4 we also know that we can control the frequency by multiplying the cosine expression by some factor f. With this in mind we define our function r(x, y):

        (define (r x y)
          (/ (+ 1 (cos (* f (+ x y)))) 2))

After trying a few values of f, we find that f is 1.5 and we can obtain a picture with the correct grating by evaluating the following expressions:

        (define f 1.5)

        (define pic2 (procedure->picture 128 128 r))

Now, we need to multiply each point the original mixed picture by the value of the points in pic2. Let's assume that we named the mixed picture pic1 as follows:

        (define pic1 (pgm-file->picture "mix-sp98.pgm"))

We obtaign the image of the first personality by multiplying the values of the two pictures using the picture-map abstraction as follows:

        (define pic3 (picture-map * pic1 pic2))

Then, we obtain the image of the second personality by subtracting the value at each point in the picture of the personality from the value of the points in the original mixed picture. To do this, we use the picture-map abstraction again:

        (define pic4 (picture-map - pic1 pic3))

Now we can display the pictures of the two personalities (i.e. pic3 and pic4) and we see that the personalities are:

Counsellor Diana Troi (Marina Sirtis) from Star Trek (empathic character) and RoboCop (handles the flack).