@comment(Hey, EMACS, this is -*- SCRIBE -*- input)
@make(6001)
@set(chapter=1)
@set(page=1)

@PageHeading(even,
             left "@Value(Page)",
             right "6.001 -- Fall Semester 1983")

@PageHeading(odd,
             Left "Problem Set 7",
             right "@value(page)")

@begin(center)
MASSACHUSETTS INSTITUTE OF TECHNOLOGY
Department of Electrical Engineering and Computer Science
6.001 Structure and Interpretation of Computer Programs

Problem Set 7
@end(center)
@blankspace(0.25 in)

@begin(format)
Issued: 1 November 1983@>Due: in recitation, 9 November 1983

Reading Assignment: finish Chapter 3
@end(format)

@begin(center)
@b[Exercises]
@end(center)

Write up and turn in the following exercises from Chapter 3 of
the course notes:

@begin(itemize)
Exercise 3-32 -- page 204

Exercise 3-34 -- page 216

Exercise 3-42 -- page 227

Exercise 3-43 -- page 227

@end(itemize)

@blankspace(0.25 in)

@begin(center)
@b[Streams and Delayed Evaluation]
@end(center)

The purpose of this assignment is to give you some experience with the
use of streams and delayed evaluation as a mechanism for organizing
systems.  Delayed evaluation is a powerful technique, so be careful.
Some of the phenomena you will see here may be mind-boggling -- hold
onto your chairs.  Many of the procedures which you will need have
been provided in the code attached, which will be loaded automatically
when you begin work on this problem set.  You should be familiar with
their contents before starting work in the laboratory.  Most of the
work in this laboratory assignment is conceptual.  There are no large
programs to write, but lots of hard ideas to understand.

The code to be loaded with this problem set contains a number of
useful stream operations that you can play with.  Listings are
attached to this handout.

@paragraph(Problem 1)

As explained in section 3.4.4, we can define an infinite stream of
ones and use this to define the stream of integers.
@begin(programexample)
(define ones (cons-stream 1 ones))

(define integers (cons-stream 1 (add-streams ones integers)))
@end(programexample)
Type in these definitions and verify that they work by using the
@a[print-stream] procedure, which has been loaded with this problem
set.  Show how to define the stream of all integers that are not
divisible by either 2 or 3.  (Use @a[filter].)

@paragraph(Problem 2)

Do exercise 3-41 on page 226 of the notes.  The @a[merge] procedure
has been predefined and loaded with the code for this problem set.
Use @a[print-stream] to print the first few elements of the stream
@a[S].  What are the 6 numbers immediately following 144 in the
sequence?

@paragraph(Plotting streams)

The code you load with the problem set contains definitions for
procedure called @a[plot-stream], which plots values of a stream on
the graphics screen.  @a[Plot-stream] takes three inputs -- a stream,
a maximum y value y@-[m] and number @a[n], and plots the first @a[n]
values of the stream.  The plot is scaled so that the vertical
distance on the screen is the range @plusminus()y@-[m] and the
horizontal distance on the screen is the range 0 through @a[n].  (The
procedure will truncate values so that they lie within the range
@plusminus()y@-[m], that is, values outside of this range will be
plotted as points at the top and bottom edges of the screen.)

To see how this works, try
@begin(programexample)
(define square-roots (map sqrt integers))

(plot-stream square-roots 10 100)
@end(programexample)

The code also contains the following definition
@begin(programexample)
(define (tty-stream) (cons-stream (read) (tty-stream)))
@end(programexample)
which produces the stream of expressions that you type in at the
keyboard.  To experiment with this, try
@begin(programexample)
(plot-stream (tty-stream) 100 50)
@end(programexample)
and type in numbers (in the range @plusminus()100), pressing
@c[execute] each time you complete a number.  Notice how the delayed
evaluation of @a[tty-stream] works: the values are plotted as you type
them in because the @a[tty-stream] is evaluated, element-by-element,
as @a[plot-stream] calls for successive values.  To see the
interaction another way, try evaluating
@begin(programexample)
(print-stream (tty-stream))
@end(programexample)
and notice how your typed values are printed back at you.

@paragraph(Problem 3)

Try evaluating the expression
@begin(programexample)
(plot-stream (integral (tty-stream) 0 1.0)
             100
             100)
@end(programexample)
Where you type in numbers at the terminal.  (@a[Integral], defined on
page 229 of the notes, is included in the problem-set code.)  Explain
the results you get if you type in 
@begin(alphaenumerate)
all 1's

successive integers 1, 2, 3, ...

the sequence 1, -1, 2, -2, 3, -3, ...
@end(alphaenumerate)

@paragraph(Problem 4)

Do exercise 3-48, which asks you to implement a procedure @a[RC] that
models RC circuits.  @a[Scale-stream] and @a[add-streams] are provided
in the problem-set code.  Note that @a[RC] should produce a
@i[procedure] that takes as arguments a stream (of currents) and an
initial voltage, and produces an output stream (of voltages).  Use
@a[RC] to define the procedure @a[RC1] as described in the exercise.
@a[RC1] models an RC circuit with resistance 5 ohms, capacitance 1 farad,
and a 0.5 second time-step.

Using, @a[RC1], @a[tty-stream], and @a[plot-stream], make plots of the
voltage across the circuit given an initial capacitor voltage of -2
volts and the following input stream of currents:

@begin(itemize)
2 seconds of 1 amp, followed by 3 seconds of @t[-]1 amp, followed by 3
seconds of 0 amps, followed by 3 seconds of 1 amp, followed by 3
seconds of 0 amps, followed by 2 seconds of @t[-]1 amp 
@end(itemize)

Remember that each time tick is 1/2 second.  Play with the scale on
the plot until you get a reasonable picture.
Turn in a sketch of the resulting graph.

@paragraph(Problem 5)

Redefine the @a[integral] procedure as on page 232, so that it takes a
delayed stream as its first argument.  Using this new version of
@a[integral], do exercise 3-54 on page 233, which asks you to generate
solutions to second-order linear differential equations.  To check
your procedure, see if you can compute a sine curve as the solution to
the differential equation
@begin(example)
d@+[2]y/dt@+[2] = y
@end(example)
with initial value 0 for @a[y] and 1 for @a[dy/dt].  You should be
able to plot your curve by typing:
@begin(programexample)
(define sine-stream (2nd 0 -1 .01 0 1))

(plot-stream sine-stream 2 1000)
@end(programexample)
As a hint, here is a sketch of the procedure @a[2nd], which you are to
define:
@begin(programexample)
(define (2nd a b dt)
  (lambda (y-init dy-init)
    (define y
      (integral ...))
    (define dy
      (integral ...))
    y))
@end(programexample)
Watch out for the needed @a[delay]s!

Also generate and sketch the solution to the differential equation
@begin(example)
d@+[2]y/dt@+[2] - dy/dt + 4y = 0
@end(example)
with initial value 0 for @a[y]  and 1 for @a[dy/dt].  Experiment to
get a reasonable scale for your plot.

You will notice that your sine curve plot is not perfect (the size of
the bumps should increase) due to numerical error in the integration
procedure.  Optional exercise @i[cum] Bachelor's Thesis:  Experiment
with reformulating other methods of solving differential equations in
terms of stream processes.

@paragraph(Problem 6 -- Optional)

Do exercise 3-56 on page 233.  Construct the model of the circuit for
the parameters given, and plot the output streams I@-[L] and V@-[C].
Sketch your plots.

@newpage()
@begin(programexample)
;;; This is the file PS7-CODE.SCM
;;; Useful stream utility functions

(define the-empty-stream nil)
(define empty-stream? null?)

(define (add-streams s1 s2)
  (cond ((empty-stream? s1) s2)
	((empty-stream? s2) s1)
	(else
	 (cons-stream (+ (head s1) (head s2))
		      (add-streams (tail s1) (tail s2))))))

(define (scale-stream c s)
  (map (lambda (x) (* c x)) s))

(define (nth-stream n s)
  (cond ((empty-stream? s)
	 (error "empty stream -- nth-stream" n))
	((= n 0) (head s))
	(else (nth-stream (- n 1) (tail s)))))

(define (accumulate combiner initial-value stream)
  (cond ((empty-stream? stream) initial-value)
	(else
	 (combiner (head stream)
	      (right-accumulate combiner
                                initial-value
                                (tail stream))))))

(define (filter pred stream)
  (cond ((empty-stream? stream) the-empty-stream)
	((pred (head stream))
	 (cons-stream (head stream)
		      (filter pred (tail stream))))
	(else (filter pred (tail stream)))))

(define (map proc stream)
  (cond ((empty-stream? stream) the-empty-stream)
	(else (cons-stream (proc (head stream))
			   (map proc (tail stream))))))

(define (map-2 f s1 s2)
  (cond ((or (empty-stream? s1) (empty-stream? s2))
	 the-empty-stream)
	(else
	 (cons-stream (f (head s1) (head s2))
		      (map-2 f (tail s1) (tail s2))))))

(define (enumerate-fringe tree)
  (cond ((atom? tree)
	 (cons-stream tree the-empty-stream))
	(else
	 (append-streams (enumerate-fringe (car tree))
			 (enumerate-fringe (cdr tree))))))

(define (enumerate-interval n1 n2)
  (cond ((> n1 n2)
	 the-empty-stream)
	(else
	 (cons-stream n1
		      (enumerate-interval (1+ n1) n2)))))


(define (append-streams s1 s2)
  (cond ((empty-stream? s1) s2)
	(else
	 (cons-stream (head s1)
		      (append-streams (tail s1) s2)))))


(define (merge s1 s2)
  (cond ((empty-stream? s1) s2)
        ((empty-stream? s2) s1)
        (else
	 (let ((h1 (head s1))
	       (h2 (head s2)))
	   (cond ((< h1 h2)
		  (cons-stream h1
			       (merge (tail s1)
				      s2)))
		 ((> h1 h2)
		  (cons-stream h2
			       (merge s1
				      (tail s2))))
		 (else
		  (cons-stream h1
			       (merge (tail s1)
				      (tail s2)))))))))

(define print-stream
  (let ()
    (define (iter s)
      (cond ((empty-stream? s)
	     (princ "}"))
	    (else
	     (princ (head s))
	     (princ " ")
	     (iter (tail s)))))
    (lambda (s)
      (princ "{")
      (iter s))))

(define (plot-stream s max-y num-vals)
  (define (sign x) (if (< x 0) -1 1))
  (define hp-screen-width 200)
  (define hp-screen-height 180)
  (define x-scale (* 2 (/ hp-screen-width num-vals)))
  (define y-scale (/ hp-screen-height max-y))
  (define (screen-x-point x)
    (round (- (* x x-scale)
              hp-screen-width)))
  (define (screen-y-point y)
    (let ((intended-y (round (* y-scale y))))
       (if (> (abs intended-y) hp-screen-height)
          (* (sign intended-y) hp-screen-height)
          intended-y)))
  (define (iter s count)
    (if (> count num-vals)
        'done
        (sequence (draw-line-to (screen-x-point count)
                                (screen-y-point (head s)))
                  (iter (tail s) (1+ count)))))
  (clear-graphics)
  (position-pen (screen-x-point 0)
                (screen-y-point (head s)))
  (iter (tail s) 1))


(define (tty-stream) (cons-stream (read) (tty-stream)))

(define (integral integrand initial-value dt)
  (define int
    (cons-stream initial-value
		 (add-streams (scale-stream dt integrand) int)))
  int)
@end(programexample)
