887 lines
26 KiB
Racket
887 lines
26 KiB
Racket
#lang sicp
|
|
|
|
(#%require (only racket/trace trace-define))
|
|
|
|
;; Code from the book
|
|
(define (stream-ref s n)
|
|
(if (= n 0)
|
|
(stream-car s)
|
|
(stream-ref (stream-cdr s) (- n 1))))
|
|
|
|
(define (stream-enumerate-interval a b)
|
|
(if (> a b)
|
|
the-empty-stream
|
|
(cons-stream a
|
|
(stream-enumerate-interval (+ a 1) b))))
|
|
|
|
(define (display-line x) (newline) (display x))
|
|
(define (show x)
|
|
(display-line x)
|
|
x)
|
|
|
|
(define (stream-for-each proc s)
|
|
(if (stream-null? s)
|
|
'done
|
|
(begin (proc (stream-car s))
|
|
(stream-for-each proc (stream-cdr s)))))
|
|
|
|
;; (define (display-stream s)
|
|
;; (stream-for-each display-line s))
|
|
|
|
(define (stream-filter pred stream)
|
|
(cond ((stream-null? stream) the-empty-stream)
|
|
((pred (stream-car stream))
|
|
(cons-stream (stream-car stream)
|
|
(stream-filter pred
|
|
(stream-cdr stream))))
|
|
(else (stream-filter pred (stream-cdr stream)))))
|
|
|
|
(define (add-streams s1 s2)
|
|
(stream-map + s1 s2))
|
|
|
|
(define (integers-starting-from n)
|
|
(cons-stream n (integers-starting-from (+ n 1))))
|
|
|
|
(define integers (integers-starting-from 1))
|
|
|
|
(define (merge s1 s2)
|
|
(cond ((stream-null? s1) s2)
|
|
((stream-null? s2) s1)
|
|
(else
|
|
(let ((s1car (stream-car s1))
|
|
(s2car (stream-car s2)))
|
|
(cond ((< s1car s2car)
|
|
(cons-stream s1car (merge (stream-cdr s1) s2)))
|
|
((> s1car s2car)
|
|
(cons-stream s2car (merge s1 (stream-cdr s2))))
|
|
(else
|
|
(cons-stream s1car
|
|
(merge (stream-cdr s1)
|
|
(stream-cdr s2)))))))))
|
|
|
|
(define (scale-stream stream factor)
|
|
(stream-map (lambda (x) (* x factor)) stream))
|
|
|
|
(define (integral integrand initial-value dt)
|
|
(define int
|
|
(cons-stream initial-value
|
|
(add-streams (scale-stream integrand dt)
|
|
int)))
|
|
int)
|
|
|
|
|
|
;; Racket versions of stream procedures
|
|
;; NB lang sicp uses promises for delayed evaluation. These can be forced
|
|
;; directly with force (no evaluation needed).
|
|
|
|
(define (stream-car stream) (car stream))
|
|
(define (stream-cdr stream) (force (cdr stream)))
|
|
|
|
;; Utility functions
|
|
(define (display-n-stream n s)
|
|
(if (and (> n 0) (not (stream-null? s)))
|
|
(begin (display-line (stream-car s))
|
|
(display-n-stream (- n 1) (stream-cdr s)))))
|
|
|
|
(define (mul-streams s1 s2)
|
|
(stream-map * s1 s2))
|
|
|
|
(define (div-streams s1 s2)
|
|
(stream-map / s1 s2))
|
|
|
|
;; 3.50
|
|
|
|
(define (stream-map proc . argstreams)
|
|
(if (null? (car argstreams))
|
|
the-empty-stream
|
|
(cons-stream
|
|
(apply proc (map stream-car argstreams))
|
|
(apply stream-map
|
|
(cons proc (map stream-cdr argstreams))))))
|
|
|
|
(#%require (only racket/base module+))
|
|
(#%require rackunit)
|
|
(module+ test
|
|
(define a (cons-stream 1 (cons-stream 2 (cons-stream 3 the-empty-stream))))
|
|
(define b (cons-stream 10 (cons-stream 20 (cons-stream 30 the-empty-stream))))
|
|
(define c (cons-stream 100 (cons-stream 200 (cons-stream 300 the-empty-stream))))
|
|
|
|
(define d (stream-map + a b c))
|
|
(check-equal? (stream-car d) 111)
|
|
(check-equal? (stream-car (stream-cdr d)) 222)
|
|
(check-equal? (stream-car (stream-cdr (stream-cdr d))) 333))
|
|
|
|
(module+ 3_51
|
|
(define x
|
|
(stream-map show
|
|
(stream-enumerate-interval 0 10)))
|
|
|
|
(stream-ref x 5)
|
|
;; Shows 0 1 2 3 4 5 5
|
|
|
|
(stream-ref x 7)
|
|
;; Shows 6 7 7
|
|
;; Because racket's implementation using promises memoises the delayed
|
|
;; objects. If this wasn't memoised, it would probably show
|
|
;; 0 1 2 3 4 5 6 7 7
|
|
)
|
|
|
|
(module+ 3_52
|
|
(define sum 0)
|
|
|
|
(define (accum x)
|
|
(set! sum (+ x sum))
|
|
sum)
|
|
;; sum shows the value of the element of seq that was last evaluated.
|
|
|
|
(define seq (stream-map accum (stream-enumerate-interval 1 20)))
|
|
;; sum is now 1, because we have evaluated accum on the first
|
|
;; element of the interval (1)
|
|
(define y (stream-filter even? seq))
|
|
;; sum is now 6, because we keep applying accum until we get to an
|
|
;; even number. The first is 6.
|
|
(define z (stream-filter (lambda (x) (= (remainder x 5) 0))
|
|
seq))
|
|
;; sum is now 10, because we keep applying accum until we get to a
|
|
;; multiple of 5. The first is 10.
|
|
|
|
(stream-ref y 7)
|
|
;; Displays 136, which is the 8th even element of seq. sum is 136,
|
|
;; because we've evaluated all stream elements up to this one.
|
|
(display-stream z)
|
|
;; Displays 10, 15, 45, 55, 105, 120, 190, 210, which are all
|
|
;; elements of seq that are multiples of 5. sum is 210,
|
|
;; If delay wasn't memoised, then sum would be 210+136 here, as we
|
|
;; would have double evaluated the elements of seq required to get
|
|
;; elements 0 to 7 of y.
|
|
|
|
)
|
|
|
|
;; 3.53: the program will output the powers of 2.
|
|
(module+ 3_53
|
|
(define s (cons-stream 1 (add-streams s s)))
|
|
|
|
(display-n-stream 10 s))
|
|
|
|
(module+ 3_54
|
|
(define factorials
|
|
(cons-stream 1
|
|
(mul-streams (integers-starting-from 2)
|
|
factorials)))
|
|
|
|
(display-n-stream 10 factorials))
|
|
|
|
|
|
;; 3.55
|
|
(define (partial-sums s)
|
|
(define sums
|
|
(cons-stream
|
|
(stream-car s)
|
|
(add-streams sums (stream-cdr s))))
|
|
sums)
|
|
|
|
(module+ 3_55
|
|
(display-n-stream 10 (partial-sums integers)))
|
|
|
|
(module+ 3_56
|
|
(define S (cons-stream
|
|
1
|
|
(merge (scale-stream S 2)
|
|
(merge (scale-stream S 3)
|
|
(scale-stream S 5)))))
|
|
|
|
(display-n-stream 20 S))
|
|
|
|
;; 3.57: With memoisation, calculating fib(n) needs n-1 additions
|
|
;; (fib(0) and fib(1) are predefined, so we have n-2 to get to
|
|
;; fib(n-1) and then another addition to do (fib(n-2) + fib(n-1))).
|
|
;; So this is O(n).
|
|
;; Without memoisation, show that fib(n) takes fib(n+1) additions.
|
|
;; Using an exercise 1.13, this implies that calculation of fib(n) is
|
|
;; exponential in the number of additions.
|
|
;; Proof by induction P(n): TODO base case.
|
|
;; fib(4) = fib(3) + fib(2), which requires 2+1 calls to stream-cdr
|
|
;; Assume P(n). fib(n+1) = fib(n) + fib(n-1). From P(n), this
|
|
;; requires fib(n+1) + fib(n) = fib(n+2) additions.
|
|
|
|
;; 3.58: expand outputs the fraction expansion of num/den in base radix.
|
|
(module+ 3_58
|
|
(define (expand num den radix)
|
|
(cons-stream
|
|
(quotient (* num radix) den)
|
|
(expand (remainder (* num radix) den) den radix)))
|
|
|
|
(display-n-stream 10 (expand 1 7 10))
|
|
(newline)
|
|
(display-n-stream 10 (expand 3 8 10))
|
|
|
|
)
|
|
|
|
;; 3.59
|
|
(define (integrate-series a)
|
|
(div-streams a (integers-starting-from 1)))
|
|
|
|
(define cosine-series
|
|
(cons-stream 1 (integrate-series (scale-stream sine-series -1))))
|
|
|
|
(define sine-series
|
|
(cons-stream 0 (integrate-series cosine-series)))
|
|
|
|
;; 3.60
|
|
(define add-series add-streams)
|
|
(define scale-series scale-stream)
|
|
|
|
;; (\Sigma_0^{\infinity} a_ix^i)(\Sigma_0^{\infinity} b_ix^i)
|
|
;; = a_0.b_0 + a_0.\Sigma_1^{\infinity} b_ix^i
|
|
;; + (\Sigma_1^{\infinity} a_ix^i)(\Sigma_0^{\infinity} b_ix^i)
|
|
;; (hint from https://eli.thegreenplace.net/2007/11/05/sicp-sections-351-352/)
|
|
(define (mul-series s1 s2)
|
|
(cons-stream
|
|
(* (stream-car s1) (stream-car s2))
|
|
(add-series (scale-series (stream-cdr s2) (stream-car s1))
|
|
(mul-series (stream-cdr s1) s2))))
|
|
|
|
(define zeroes (cons-stream 0 zeroes))
|
|
|
|
(define (make-stream l)
|
|
(cond ((null? l) zeroes)
|
|
(else (cons-stream
|
|
(car l)
|
|
(make-stream (cdr l))))))
|
|
|
|
(define make-series make-stream)
|
|
|
|
(define (display-stream s n)
|
|
(define (display-term s n)
|
|
(if (> n 0)
|
|
(begin
|
|
(display (stream-car s))
|
|
(display " ")
|
|
(display-term (stream-cdr s) (- n 1)))))
|
|
(display-term s n))
|
|
|
|
(define display-series display-stream)
|
|
|
|
(define (eval-series s x n)
|
|
(define (eval-iter s i sum)
|
|
(if (> i n)
|
|
sum
|
|
(eval-iter
|
|
(stream-cdr s)
|
|
(+ i 1)
|
|
(+ sum (* (stream-car s) (expt x i))))))
|
|
(eval-iter s 0 0))
|
|
|
|
(module+ test
|
|
;; (2) * (0 + x) = (0 + 2x)
|
|
(define prod-1
|
|
(mul-series
|
|
(make-series '(2))
|
|
(make-series '(0 1))))
|
|
(check-equal? (stream-ref prod-1 0) 0)
|
|
(check-equal? (stream-ref prod-1 1) 2)
|
|
|
|
;; (1 + x) * (1 + x) = (1 + 2x + x^2)
|
|
(define prod-2
|
|
(mul-series
|
|
(make-series '(1 1))
|
|
(make-series '(1 1))))
|
|
(check-equal? (stream-ref prod-2 0) 1)
|
|
(check-equal? (stream-ref prod-2 1) 2)
|
|
(check-equal? (stream-ref prod-2 2) 1))
|
|
|
|
(module+ test
|
|
(define s2+c2
|
|
(add-series
|
|
(mul-series cosine-series cosine-series)
|
|
(mul-series sine-series sine-series)))
|
|
(check-equal? (stream-ref s2+c2 0) 1)
|
|
(check-equal? (stream-ref s2+c2 1) 0)
|
|
(check-equal? (stream-ref s2+c2 2) 0))
|
|
|
|
;; 3.61
|
|
(define (invert-unit-series s)
|
|
(define x
|
|
(cons-stream
|
|
1
|
|
(scale-stream
|
|
(mul-series
|
|
(stream-cdr s)
|
|
x)
|
|
-1)))
|
|
x)
|
|
|
|
(module+ test
|
|
(define cos-inv (invert-unit-series cosine-series))
|
|
(define one (mul-series cosine-series cos-inv))
|
|
|
|
(check-equal? (stream-ref one 0) 1)
|
|
(check-equal? (stream-ref one 1) 0)
|
|
(check-equal? (stream-ref one 2) 0))
|
|
|
|
;; 3.62
|
|
(define (div-series s1 s2)
|
|
(let ((div-constant (stream-car s2)))
|
|
(if (= 0 div-constant)
|
|
(error "DIV-SERIES: divisor has zero constant term" s2)
|
|
(mul-series
|
|
(scale-stream s1 (/ 1 div-constant))
|
|
(invert-unit-series
|
|
(scale-stream s2 (/ 1 div-constant)))))))
|
|
|
|
(define tangent-series
|
|
(div-series sine-series cosine-series))
|
|
|
|
(module+ test
|
|
(define (close-to x y epsilon)
|
|
(and (< y (+ x epsilon))
|
|
(> y (- x epsilon))))
|
|
|
|
(define-simple-check (check-tan? x)
|
|
(close-to (tan x)
|
|
(eval-series tangent-series x 50)
|
|
0.01))
|
|
|
|
(check-tan? 0)
|
|
(check-tan? 1)
|
|
(check-tan? -1))
|
|
|
|
|
|
;; 3.63: Without the local variable definition of guesses in
|
|
;; sqrt-stream, there is no way for later elements of the stream to
|
|
;; refer to the previously calculated elements (that are bound to the
|
|
;; local variable guesses in the environment of the first version of
|
|
;; the procedure). As such, the earlier terms have to be recalculated
|
|
;; each time.
|
|
|
|
;; 3.64
|
|
|
|
|
|
(define (stream-limit s tolerance)
|
|
(let ((s0 (stream-car s))
|
|
(s1 (stream-car (stream-cdr s))))
|
|
(if (< (abs (- s0 s1)) tolerance)
|
|
s1
|
|
(stream-limit (stream-cdr s) tolerance))))
|
|
|
|
(define (convergence-steps s tolerance)
|
|
(define (converge-iter s n)
|
|
(let ((s0 (stream-car s))
|
|
(s1 (stream-car (stream-cdr s))))
|
|
(if (< (abs (- s0 s1)) tolerance)
|
|
n
|
|
(converge-iter (stream-cdr s) (+ n 1)))))
|
|
(converge-iter s 0))
|
|
|
|
(define (average a b)
|
|
(/ (+ a b) 2))
|
|
|
|
;; From the book
|
|
(define (sqrt-improve guess x)
|
|
(average guess (/ x guess)))
|
|
|
|
(define (sqrt-stream x)
|
|
(cons-stream 1.0
|
|
(stream-map (lambda (guess)
|
|
(sqrt-improve guess x))
|
|
(sqrt-stream x))))
|
|
(define (sqrt x tolerance)
|
|
(stream-limit (sqrt-stream x) tolerance))
|
|
|
|
(define (square x) (* x x))
|
|
|
|
(define (euler-transform s)
|
|
(let ((s0 (stream-ref s 0))
|
|
(s1 (stream-ref s 1))
|
|
(s2 (stream-ref s 2)))
|
|
(cons-stream (- s2 (/ (square (- s2 s1))
|
|
(+ s0 (* -2 s1) s2)))
|
|
(euler-transform (stream-cdr s)))))
|
|
|
|
(define (make-tableau transform s)
|
|
(cons-stream s
|
|
(make-tableau transform
|
|
(transform s))))
|
|
|
|
(define (accelerated-sequence transform s)
|
|
(stream-map stream-car
|
|
(make-tableau transform s)))
|
|
|
|
|
|
;; 3.65
|
|
|
|
(define (ln-summands n)
|
|
(cons-stream
|
|
(/ 1.0 n)
|
|
(stream-map - (ln-summands (+ n 1)))))
|
|
|
|
;; Takes 9998 steps to converge with tolerance 0.0001
|
|
(define ln-stream
|
|
(partial-sums (ln-summands 1)))
|
|
|
|
;; Takes 11 steps to converge with tolerance 0.0001
|
|
(define euler-ln-stream
|
|
(euler-transform ln-stream))
|
|
|
|
;; Takes 3 steps to converge with tolerance 0.0001
|
|
(define accelerated-ln-stream
|
|
(accelerated-sequence euler-transform ln-stream))
|
|
|
|
|
|
;; 3.66
|
|
|
|
;; From the book
|
|
(define (interleave s1 s2)
|
|
(if (stream-null? s1)
|
|
s2
|
|
(cons-stream (stream-car s1)
|
|
(interleave s2 (stream-cdr s1)))))
|
|
|
|
(define (element-pos s e)
|
|
(define (iter s n)
|
|
(if (equal? (stream-car s) e)
|
|
n
|
|
(iter (stream-cdr s) (+ n 1))))
|
|
(iter s 1))
|
|
|
|
(define (pairs s t)
|
|
(cons-stream
|
|
(list (stream-car s) (stream-car t))
|
|
(interleave
|
|
(stream-map (lambda (x) (list (stream-car s) x))
|
|
(stream-cdr t))
|
|
(pairs (stream-cdr s) (stream-cdr t)))))
|
|
|
|
;; By observation of the pattern, the following procedure calculates the
|
|
;; position in the stream (pairs integers integers) of (i j).
|
|
(module+ 3-66
|
|
(define (pos i j)
|
|
(if (= i j)
|
|
(- (expt 2 j) 1)
|
|
(+ (* (expt 2 i) (- j i))
|
|
(- (expt 2 (- i 1)) 1))))
|
|
|
|
(define int-pairs (pairs integers integers))
|
|
|
|
(check-equal? (pos 10 10) (element-pos int-pairs '(10 10)))
|
|
(check-equal? (pos 10 30) (element-pos int-pairs '(10 30)))
|
|
(check-equal? (pos 1 100) (element-pos int-pairs '(1 100)))
|
|
(check-equal? (pos 2 50) (element-pos int-pairs '(2 50))))
|
|
|
|
;; Positions in the list:
|
|
;; (1,100) 198
|
|
;; (99,100) 950737950171172051122527404031
|
|
;; (100,100) 1267650600228229401496703205375
|
|
;;
|
|
;; In general, the first row is augmented every 2nd element, the second row every
|
|
;; 4th, the third row every 8th, etc.
|
|
|
|
(module+ 3-67
|
|
|
|
;; Redefine pairs to return all pairs of integers. This needs the extra
|
|
;; stream of the left column to be mixed in
|
|
(define (pairs s t)
|
|
(cons-stream
|
|
(list (stream-car s) (stream-car t))
|
|
(interleave
|
|
(interleave
|
|
(stream-map (lambda (x) (list (stream-car s) x))
|
|
(stream-cdr t))
|
|
(stream-map (lambda (x) (list x (stream-car t)))
|
|
(stream-cdr s)))
|
|
(pairs (stream-cdr s) (stream-cdr t))))))
|
|
|
|
(module+ 3-68
|
|
(#%require racket/trace)
|
|
;; Louis definition of pairs from the book
|
|
(trace-define (pairs s t)
|
|
(interleave
|
|
(stream-map (lambda (x) (list (stream-car s) x))
|
|
t)
|
|
(pairs (stream-cdr s) (stream-cdr t))))
|
|
|
|
;; 3.68:
|
|
;; This goes into an infinite loop because interleave is evaluated immediately
|
|
;; which in turn evaluates pairs on the cdr of streams s and t.
|
|
;; There is no degenerate case to stop the recursion. In the previous
|
|
;; case, this is fine because the recursive call to pairs is only
|
|
;; evaluated on demand, whereas here, it is evaluated immediately.
|
|
)
|
|
|
|
|
|
;; 3.69
|
|
;; triples generates all triples (s_i, t_j, u_k) such that i<=j<=k.
|
|
;; Let S(n) = \bigcup_{i=0}^\infty \bigcup_{j=i}^\infty
|
|
;; \bigcup_{k=j}^\infty (i,j,k), such that i<=j<=k.
|
|
;;
|
|
;; Then: S(n) = {(n,n,n) \cup \bigcup_{j=1}^\infty
|
|
;; \bigcup_{k=j}^\infty (0,j,k) \cup \bigcup_{k=1}^\infty (0,0,k)
|
|
;; \cup S(n+1)}.
|
|
;; The set of triples is then S(0)
|
|
|
|
(define (triples s t u)
|
|
(cons-stream
|
|
(list
|
|
(stream-car s)
|
|
(stream-car t)
|
|
(stream-car u))
|
|
(interleave
|
|
(stream-map (lambda (x)
|
|
(list
|
|
(stream-car s)
|
|
(stream-car t)
|
|
x))
|
|
(stream-cdr u))
|
|
(interleave
|
|
(stream-map (lambda (x)
|
|
(cons
|
|
(stream-car s)
|
|
x))
|
|
(pairs
|
|
(stream-cdr t)
|
|
(stream-cdr u)))
|
|
(triples
|
|
(stream-cdr s)
|
|
(stream-cdr t)
|
|
(stream-cdr u))))))
|
|
|
|
(module+ 3-69
|
|
(define pythag-triples
|
|
(stream-filter
|
|
(lambda (s)
|
|
(let ((i (car s))
|
|
(j (cadr s))
|
|
(k (caddr s)))
|
|
(=
|
|
(+ (* i i) (* j j))
|
|
(* k k))))
|
|
(triples integers integers integers))))
|
|
|
|
;; 3.70
|
|
|
|
(define (merge-weighted s1 s2 weight)
|
|
(cond ((stream-null? s1) s2)
|
|
((stream-null? s2) s1)
|
|
(else
|
|
(let ((s1car (stream-car s1))
|
|
(s2car (stream-car s2)))
|
|
(cond ((< (weight s1car) (weight s2car))
|
|
(cons-stream s1car (merge-weighted (stream-cdr s1) s2 weight)))
|
|
(else
|
|
(cons-stream s2car (merge-weighted s1 (stream-cdr s2) weight))))))))
|
|
|
|
(define (weighted-pairs s t weight)
|
|
(cons-stream
|
|
(list (stream-car s) (stream-car t))
|
|
(merge-weighted
|
|
(stream-map (lambda (x) (list (stream-car s) x))
|
|
(stream-cdr t))
|
|
(weighted-pairs (stream-cdr s) (stream-cdr t) weight)
|
|
weight)))
|
|
|
|
(module+ 3-70
|
|
(define int-pairs-by-sum
|
|
(weighted-pairs integers integers
|
|
(lambda (x)
|
|
(+ (car x) (cadr x)))))
|
|
|
|
;; any-factors? is a procedure that returns true if any of n are factors
|
|
(define (any-factors? n)
|
|
(define (factors-of-x? factors x)
|
|
(if (null? factors)
|
|
#f
|
|
(or (= (remainder x (car factors)) 0)
|
|
(factors-of-x? (cdr factors) x))))
|
|
(lambda (x) (factors-of-x? n x)))
|
|
|
|
;; Would have been better to map (any-factors? '(2 3 5)) over x,
|
|
;; but racket's ormap doesn't seem to work here.
|
|
(define int-pairs-235
|
|
(stream-filter
|
|
(lambda (x)
|
|
(not (or ((any-factors? '(2 3 5)) (car x))
|
|
((any-factors? '(2 3 5)) (cadr x)))))
|
|
(weighted-pairs integers integers
|
|
(lambda (x)
|
|
(+ (* (car x) 2)
|
|
(* (cadr x) 3)
|
|
(* (car x) (cadr x) 5)))))))
|
|
|
|
(module+ 3-71-72
|
|
(define (sum-powers p)
|
|
(lambda (x)
|
|
(apply + (map (lambda (y) (expt y p)) x))))
|
|
|
|
(define (pairs-by-sum-powers p)
|
|
(weighted-pairs integers integers (sum-powers p)))
|
|
|
|
;; Mask (by #t) those elements of the stream s that have
|
|
;; n-1 following elements that are equal.
|
|
(define (n-consecutive-equal-mask s n)
|
|
;; Compare s with (n-1) stream-cdrs. If they are all equal,
|
|
;; then s has n consecutive equal elements.
|
|
(define (args s n)
|
|
(if (= n 0) '()
|
|
(cons s (args (stream-cdr s) (- n 1)))))
|
|
(apply stream-map = (args s n)))
|
|
|
|
(define (sum-powers-n-ways p n)
|
|
(let* ((pairs-stream (pairs-by-sum-powers p))
|
|
(sum-power-stream
|
|
(stream-map (sum-powers p) pairs-stream)))
|
|
;; If the element has n pairs following it such that each
|
|
;; pair (i,j) has the property that (i^p + j^p) is equal, then
|
|
;; the corresponding mask element will be #t. Pull out all such
|
|
;; elements of the pairs stream.
|
|
(stream-filter (lambda (x) (number? x))
|
|
(stream-map (lambda (i x) (if i x #f))
|
|
(n-consecutive-equal-mask sum-power-stream n)
|
|
sum-power-stream))))
|
|
|
|
(define (all-pairs sum-of-powers p n)
|
|
(let* ((all-pairs-stream (pairs-by-sum-powers p))
|
|
(pairs-stream
|
|
(stream-filter
|
|
(lambda (x) (= ((sum-powers p) x) sum-of-powers))
|
|
all-pairs-stream)))
|
|
(letrec ((n-pairs (lambda (pairs-stream n)
|
|
(if (= n 1)
|
|
(list (stream-car pairs-stream))
|
|
(cons (stream-car pairs-stream)
|
|
(n-pairs (stream-cdr pairs-stream) (- n 1)))))))
|
|
(n-pairs pairs-stream n))))
|
|
|
|
(define (sum-powers-n-ways-pairs p n)
|
|
(let* ((powers (sum-powers-n-ways p n))
|
|
(pairs (stream-map
|
|
(lambda (x) (all-pairs x p n))
|
|
powers)))
|
|
(stream-map (lambda (power pairs)
|
|
(list power pairs))
|
|
powers
|
|
pairs)))
|
|
|
|
(define ramanujan-pairs (sum-powers-n-ways-pairs 3 2))
|
|
;; First six Ramanujan numbers (and pairs):
|
|
;; (1729 ((9 10) (1 12))) (4104 ((9 15) (2 16)))
|
|
;; (13832 ((18 20) (2 24))) (20683 ((19 24) (10 27)))
|
|
;; (32832 ((18 30) (4 32))) (39312 ((15 33) (2 34)))
|
|
|
|
(define sum-squares-three-ways (sum-powers-n-ways-pairs 2 3))
|
|
;; First six:
|
|
;; (325 ((10 15) (6 17) (1 18))) (425 ((13 16) (8 19) (5 20)))
|
|
;; (650 ((17 19) (11 23) (5 25))) (725 ((14 23) (10 25) (7 26)))
|
|
;; (845 ((19 22) (13 26) (2 29))) (850 ((15 25) (11 27) (3 29)))
|
|
)
|
|
|
|
;; Streams as signals
|
|
|
|
(module+ 3-73
|
|
(define (RC R C dt)
|
|
(lambda (i v0)
|
|
(add-streams
|
|
(scale-stream i R)
|
|
(scale-stream (integral i v0 dt)
|
|
(/ 1 C))))))
|
|
|
|
|
|
(define (sign-change-detector x1 x2)
|
|
(cond ((and (< x1 0) (> x2 0)) 1)
|
|
((and (> x1 0) (< x2 0)) -1)
|
|
(else 0)))
|
|
|
|
(module+ 3-74
|
|
;; From the book
|
|
(define (make-zero-crossings input-stream last-value)
|
|
(cons-stream
|
|
(sign-change-detector (stream-car input-stream) last-value)
|
|
(make-zero-crossings (stream-cdr input-stream)
|
|
(stream-car input-stream))))
|
|
|
|
(define sense-data
|
|
(make-stream '(1 2 1.5 1 0.5 -0.1 -2 -3 -2 -0.5 0.2 3 4)))
|
|
|
|
;; This is equivalent to (make-zero-crossings sense-data 0)
|
|
(define zero-crossings
|
|
(stream-map sign-change-detector
|
|
sense-data
|
|
(cons-stream 0 sense-data))))
|
|
|
|
(module+ 3-75
|
|
(define sense-data
|
|
(make-stream '(1 2 1.5 1 0.5 -0.1 -2 -3 -2 -0.5 0.2 3 4)))
|
|
|
|
;; Updated from the book. It is necessary to calculate the
|
|
;; current and last point from the stream and then to compare
|
|
;; this average with the last average. This requires passing
|
|
;; in both the last value and the last average to make-zero-crossings.
|
|
(define (make-zero-crossings input-stream last-value last-avpt)
|
|
(let* ((current-value (stream-car input-stream))
|
|
(avpt (/ (+ current-value last-value) 2)))
|
|
(cons-stream (sign-change-detector last-avpt avpt)
|
|
(make-zero-crossings (stream-cdr input-stream)
|
|
current-value
|
|
avpt))))
|
|
|
|
)
|
|
|
|
(module+ 3-76
|
|
(define sense-data
|
|
(make-stream '(1 2 1.5 1 0.5 -0.1 -2 -3 -2 -0.5 0.2 3 4)))
|
|
|
|
(define (smooth input-stream)
|
|
(scale-stream
|
|
(add-streams input-stream
|
|
(cons-stream 0 input-stream))
|
|
1/2))
|
|
|
|
;; Apply condition to input before finding zero crossings
|
|
(define (zero-crossings condition input)
|
|
(stream-map sign-change-detector
|
|
(cons-stream 0 (condition input))
|
|
(smooth sense-data))))
|
|
|
|
;; Modified for delayed integrand
|
|
(define (integral-delayed delayed-integrand initial-value dt)
|
|
(cons-stream initial-value
|
|
(let ((integrand (force delayed-integrand)))
|
|
(if (stream-null? integrand)
|
|
the-empty-stream
|
|
(integral-delayed (delay (stream-cdr integrand))
|
|
(+ (* dt (stream-car integrand))
|
|
initial-value)
|
|
dt)))))
|
|
|
|
;; Implicit-style from the book
|
|
(define (integral-implicit delayed-integrand initial-value dt)
|
|
(define int
|
|
(cons-stream initial-value
|
|
(let ((integrand (force delayed-integrand)))
|
|
(add-streams (scale-stream integrand dt)
|
|
int))))
|
|
int)
|
|
|
|
(module+ 3-77
|
|
;; From the book but modified to use racket/local
|
|
(#%require racket/local)
|
|
(define (solve f y0 dt)
|
|
(local ((define y (integral-delayed (delay dy) y0 dt))
|
|
(define dy (stream-map f y)))
|
|
y)))
|
|
|
|
(module+ 3-78
|
|
(#%require racket/local)
|
|
(define (solve-2nd a b dt y0 dy0)
|
|
(local
|
|
((define y (integral-delayed (delay dy) y0 dt))
|
|
(define dy (integral-delayed (delay ddy) dy0 dt))
|
|
(define ddy (add-streams
|
|
(scale-stream dy a)
|
|
(scale-stream y b))))
|
|
y)))
|
|
|
|
;; (module+ test
|
|
;; ;; Test: a=0, b=-1, y0=1, dy0=0: d^2/dx(cos(x)) = -cos(x). Evaluate at pi -> -1
|
|
;; ;; a=0, b=-1, y0=0, dy0=1: d^2/dx(sin(x)) = -sin(x). Evaluate at pi -> 0
|
|
|
|
;; (check (close-to (stream-ref (solve-2nd 0 -1 (/ 3.1415 1000) 1 0) 1000)
|
|
;; -1
|
|
;; 0.01))
|
|
|
|
;; (check (close-to (stream-ref (solve-2nd 0 -1 (/ 3.1415 1000) 0 1) 1000)
|
|
;; 0
|
|
;; 0.01)))
|
|
|
|
(module+ 3-79
|
|
(#%require racket/local)
|
|
(define (solve-2nd f dt y0 dy0)
|
|
(local
|
|
((define y (integral-delayed (delay dy) y0 dt))
|
|
(define dy (integral-delayed (delay ddy) dy0 dt))
|
|
(define ddy (stream-map f dy y)))
|
|
y)))
|
|
|
|
(module+ 3-80
|
|
(#%require racket/local)
|
|
(define (RLC R L C dt)
|
|
(lambda (vC0 iL0)
|
|
(local
|
|
((define vC (integral-delayed (delay dvC) vC0 dt))
|
|
(define iL (integral-delayed (delay diL) iL0 dt))
|
|
(define dvC (scale-stream iL (/ -1 C)))
|
|
(define diL (add-streams
|
|
(scale-stream iL (/ (* -1 R) L))
|
|
(scale-stream vC (/ 1 L)))))
|
|
(cons vC iL)))))
|
|
|
|
(module+ 3-81
|
|
(define random-init 7)
|
|
|
|
;; From ch3support.scm:
|
|
;;For Section 3.1.2 -- written as suggested in footnote,
|
|
;; though the values of a, b, m may not be very "appropriately chosen"
|
|
(define (rand-update x)
|
|
(let ((a 27) (b 26) (m 127))
|
|
(modulo (+ (* a x) b) m)))
|
|
|
|
(define (rand-stream requests)
|
|
(define (next request val)
|
|
(if (and (pair? val)
|
|
(eq? (car request) 'reset))
|
|
(cadr request)
|
|
(rand-update val)))
|
|
(define rand
|
|
(cons-stream random-init
|
|
(stream-map next requests rand)))
|
|
rand)
|
|
|
|
;; Test with (define req (make-stream '(generate generate (reset 19) generate)))
|
|
|
|
;; 3.82
|
|
;; Accumulate stream to give a running total
|
|
(define (stream-acc input)
|
|
(define acc
|
|
(cons-stream (stream-car input)
|
|
(add-streams acc
|
|
(stream-cdr input))))
|
|
acc)
|
|
|
|
;; Scale stream of random numbers to lie in [low,high]
|
|
(define (random-stream-in-range low high)
|
|
(define ones (cons-stream 1 ones))
|
|
(define (random-stream)
|
|
(cons-stream (random (- high low))
|
|
(random-stream)))
|
|
(add-streams (scale-stream ones low)
|
|
(random-stream)))
|
|
|
|
;; A procedure that generates a stream of booleans:
|
|
;; Does a random element from [-1,1]x[-1,1] lie in the cirle
|
|
;; of radius 1 centred at (0, 0).
|
|
;; P(in circle) = pi*1^2 / 4 = pi/4
|
|
(define in-circle-test
|
|
(lambda ()
|
|
(define (in-circle? radius)
|
|
(lambda (x y)
|
|
(<= (+ (* x x) (* y y))
|
|
(* radius radius))))
|
|
(let ((radius 1)
|
|
(x (random-stream-in-range -1.0 1.0))
|
|
(y (random-stream-in-range -1.0 1.0)))
|
|
(stream-map (in-circle? radius) x y))))
|
|
|
|
(define (monte-carlo experiment-stream)
|
|
(define num-trials integers)
|
|
(define num-trials-passed
|
|
(stream-acc (stream-map (lambda (x) (if x 1 0)) experiment-stream)))
|
|
(div-streams num-trials-passed num-trials))
|
|
|
|
;; Area of circle is pi/r^2. Area of square is 2*2 = 4
|
|
;; So calculated probability is pi/4.
|
|
(define estimate-pi
|
|
(scale-stream (monte-carlo (in-circle-test)) 4.0))
|
|
|
|
)
|
|
|
|
|