exercise 3.73~82

ようやく3章終了か。

ex3.73
(define (RC r c dt)
 (lambda (i v0)
   (add-stream (scale-stream i r)
               (integral (scale-stream i (/ 1.0 c))
                        v0 dt))))

実行してもあってるか確かめにくいなぁ。

ex3.74
(define zero-crossing (stream-map sign-change-detector sense-data (cons-stream 0 sense-data)))

なんかmapで複数のリストを引数に取るのがおもしろく感じてきた今日この頃。

ex3.75
(define (make-zero-crossing input-stream last-value last-avpt)
  (if (stream-null? input-stream)
      the-empty-stream
      (let ((avpt (/ (+ (stream-car input-stream) last-value) 2.0)))
        (cons-stream (sign-change-detector avpt last-avpt)
                     (make-zero-crossing (stream-cdr input-stream)
                                         (stream-car input-stream)
                                         avpt)))))

問題自体は解けるが、なぜこうすると良いかがあまり理解できん。
日本語の方をどっかで見てくるかな。

ex3.76
(define (make-zero-crossing input-stream last-value)
  (if (null? input-stream)
      the-empty-stream
      (cons-stream
       (sign-change-detector (stream-car input-stream) last-value)
       (make-zero-crossing (stream-cdr input-stream)
                           (stream-car input-stream)))))


(define (smooth stream)
  (stream-map
   (lambda (x y) (/ (+ x y) 2.0))
   stream
   (cons-stream 0  stream)))

mapたのしい。

ex3.77
(define (integral delayed-integrand initial-value dt)
   (cons-stream initial-value
                (let ((integrand (force delayed-integrand)))
                  (if (stream-null? integrand)
                      the-empty-stream
                      (integral (delay (stream-cdr integrand))
                               (+ (* dt (stream-car integrand))
                                  initial-value)
                               dt)))))

再帰で引数を渡すときにdelayするのを忘れるな、と。

ex3.78
(define (solve-2nd a b y0 dy0 dt)
  (define ddy (add-stream (scale-stream dy a) (scale-stream y b)))
  (define dy (integral (delay ddy) dy0 dt))
  (define y (integral (delay dy) y0 dt))
  y)

うげっ、と最初は思ったが、図もかかれてるし簡単にできた。
ここら辺は結構楽しかったかも。
ちなみに実行結果らしきものは以下。
a=1.0, b=2.0, y0=1.0, dy0=2.0の場合
y(t)=e^(2*t)
となるので、t=0.5(すなわちdt=0.0001 なら stream-refは5000の時)
y≒eになるはずである

gosh> (stream-ref (solve-2nd 1.0 2.0 1.0 2.0 0.0001) 5000)
2.7180100501018587
ex3.79
(define (solve-2nd-generalized f a b y0 dy0 dt)
  (define ddy (add-stream (scale-stream dy a)
                          (add-stream (scale-stream y b)
                                      (stream-map f dy y))))
  (define dy (integral (delay ddy) dy0 dt))
  (define y (integral (delay dy) y0 dt))
  y)

generalizeしてhogehogeに使えるようにしろとあったのでこうなった。
が、与えられた微分方程式を解くだけなら

(define (solve-2nd-generalized f a b y0 dy0 dt)
  (define ddy (stream-map f dy y))
  (define dy (integral (delay ddy) dy0 dt))
  (define y (integral (delay dy) y0 dt))
  y)

で十分か.

ex3.80

これも意外と簡単、なはず。(実行したけどあってるか分からんがな)

(define (RLC r l c dt)
  (lambda (v0 i0)
    (define dv (scale-stream i (/ -1.0 c)))
    (define di (add-stream (scale-stream v (/ 1.0 l))(scale-stream i (- (/ r l)))))
    (define v (integral (delay dv) v0 dt))
    (define i (integral (delay di) i0 dt))
    (cons v i)))

;;表示用
(define (display-stream-n-lines stream n)
  (if (= n 0)
      'done
      (begin (display-line (stream-car stream))
             (display-stream-n-lines (stream-cdr stream) (- n 1)))))

(define (display-stream s)
  (stream-for-each display-line s))

まぁ一応実行してみるか

gosh> (define RLC0 (RLC 1.0 1.0 0.2 0.1))   
RLC0                                        
gosh> (define vc (car (RLC0 10 0)))         
vc                                          
gosh> (define il (cdr (RLC0 10 0)))         
il
gosh> (display-stream-n-lines vc 10)        
10                                          
10.0                                        
9.5                                         
8.55                                        
7.220000000000001                           
5.5955                                      
3.77245                                     
1.8519299999999999                          
-0.0651605000000004                         
-1.8831384500000004                         
done
gosh> (display-stream-n-lines il 10)        
0                                           
1.0                                         
1.9                                         
2.66                                        
3.249                                       
3.6461                                      
3.84104                                     
3.834181                                    
3.6359559                                   
3.2658442599999997
done

自分で方程式解いて確認するべきかなぁ。
ちょうど前期に電気回路と微分方程式とか言う講義を受けたのだし。

ex3.81

問題文がちゃんと理解できているのか不安。
要はgenerateとresetのストリームを受け取って、それに合うような乱数のリストを返せば良いのかな?

(define (list-stream x)
  (if (null? x)
      the-empty-stream
      (cons-stream (car x)
                   (list-stream (cdr x)))))
(define operation (list-stream '(generate generate generate reset generate generate generate generate reset generate)))

(define (random-number-generater op-stream init)
  (define randoms
    (cons-stream init
                 (stream-map
                  (lambda (num op)
                    (cond ((eq? op 'generate) (rand-update num))
                          ((eq? op 'reset) init)
                          (else (error "Unknown operation!!" op))))
                  randoms
                  op-stream)))
  randoms)

;;resetで値を指定したいのでこうしてみた↓
(define (random-number-generater op-stream init)
  (define randoms
    (cons-stream init
                 (stream-map
                  (lambda (num op)
                    (cond ((eq? op 'generate) (rand-update num))
                          ((eq? op 'reset) init)
                          ((and (pair? op)
                                (eq? (car op) 'reset)
                                (number? (cadr op)))
                           (cadr op))
                          (else (error "Unknown operation!!" op))))
                  randoms
                  op-stream)))
  randoms)

(define operation (list-stream '(generate generate generate reset generate generate generate generate (reset 5)  generate generate generate (reset 5) generate)))
ex3.82

Pに与える関数が間違っていたのに気づかず結構悩んだ・・・orz

(use srfi-27)
(define (random n)
    (* (random-real) n))

(define (random-in-range low high)
    (let ((range (- high low)))
          (+ low (random range))))

(define (random-in-range-numbers low high)
  (cons-stream (random-in-range low high)
               (random-in-range-numbers low high)))

;;monte-carloを用いる場合
(define (estimate-integral-stream P x1 x2 y1 y2)
  (scale-stream (monte-carlo
                 (stream-map P
                             (random-in-range-numbers x1 x2)
                             (random-in-range-numbers y1 y2))
                 0
                 0)
                (* (- x2 x1) (- y2 y1))))

(define (P x y)
  (>= (square 3)
      (+ (square (- x 5))
      (square (- y 7)))))

;;用いないと
(define (estimate-integral P x1 x2 y1 y2)
  (define (next passed failed)
    (cons-stream (* (/ passed (+ passed failed))
                    (- x2 x1)
                    (- y2 y1))
                 (if (P (random-in-range x1 x2) (random-in-range y1 y2))
                     (next (+ passed 1) failed)
                     (next passed (+ failed 1)))))
  (next 0 1)) ;;0を渡すと乗算で揉める

とりあえずこれで終了。