~ubuntu-branches/ubuntu/precise/r5rs-doc/precise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
\extrapart{Example} % -*- Mode: Lisp; Package: SCHEME; Syntax: Common-lisp -*-

\nobreak
{\cf Integrate-system} integrates the system 
$$y_k^\prime = f_k(y_1, y_2, \ldots, y_n), \; k = 1, \ldots, n$$
of differential equations with the method of Runge-Kutta.

The parameter {\tt system-derivative} is a function that takes a system
state (a vector of values for the state variables $y_1, \ldots, y_n$)
and produces a system derivative (the values $y_1^\prime, \ldots,
y_n^\prime$).  The parameter {\tt initial-state} provides an initial
system state, and {\tt h} is an initial guess for the length of the
integration step.

The value returned by {\cf integrate-system} is an infinite stream of
system states.

\begin{schemenoindent}
(define integrate-system
  (lambda (system-derivative initial-state h)
    (let ((next (runge-kutta-4 system-derivative h)))
      (letrec ((states
                (cons initial-state
                      (delay (map-streams next
                                          states)))))
        states))))%
\end{schemenoindent}

{\cf Runge-Kutta-4} takes a function, {\tt f}, that produces a
system derivative from a system state.  {\cf Runge-Kutta-4}
produces a function that takes a system state and
produces a new system state.

\begin{schemenoindent}
(define runge-kutta-4
  (lambda (f h)
    (let ((*h (scale-vector h))
          (*2 (scale-vector 2))
          (*1/2 (scale-vector (/ 1 2)))
          (*1/6 (scale-vector (/ 1 6))))
      (lambda (y)
        ;; y {\rm{}is a system state}
        (let* ((k0 (*h (f y)))
               (k1 (*h (f (add-vectors y (*1/2 k0)))))
               (k2 (*h (f (add-vectors y (*1/2 k1)))))
               (k3 (*h (f (add-vectors y k2)))))
          (add-vectors y
            (*1/6 (add-vectors k0
                               (*2 k1)
                               (*2 k2)
                               k3))))))))
%|--------------------------------------------------|

(define elementwise
  (lambda (f)
    (lambda vectors
      (generate-vector
        (vector-length (car vectors))
        (lambda (i)
          (apply f
                 (map (lambda (v) (vector-ref  v i))
                      vectors)))))))

%|--------------------------------------------------|
(define generate-vector
  (lambda (size proc)
    (let ((ans (make-vector size)))
      (letrec ((loop
                (lambda (i)
                  (cond ((= i size) ans)
                        (else
                         (vector-set! ans i (proc i))
                         (loop (+ i 1)))))))
        (loop 0)))))

(define add-vectors (elementwise +))

(define scale-vector
  (lambda (s)
    (elementwise (lambda (x) (* x s)))))%
\end{schemenoindent}

{\cf Map-streams} is analogous to {\cf map}: it applies its first
argument (a procedure) to all the elements of its second argument (a
stream).

\begin{schemenoindent}
(define map-streams
  (lambda (f s)
    (cons (f (head s))
          (delay (map-streams f (tail s))))))%
\end{schemenoindent}

Infinite streams are implemented as pairs whose car holds the first
element of the stream and whose cdr holds a promise to deliver the rest
of the stream.

\begin{schemenoindent}
(define head car)
(define tail
  (lambda (stream) (force (cdr stream))))%
\end{schemenoindent}

\bigskip
The following illustrates the use of {\cf integrate-system} in
integrating the system
$$ C {dv_C \over dt} = -i_L - {v_C \over R}$$\nobreak
$$ L {di_L \over dt} = v_C$$
which models a damped oscillator.

\begin{schemenoindent}
(define damped-oscillator
  (lambda (R L C)
    (lambda (state)
      (let ((Vc (vector-ref state 0))
            (Il (vector-ref state 1)))
        (vector (- 0 (+ (/ Vc (* R C)) (/ Il C)))
                (/ Vc L))))))

(define the-states
  (integrate-system
     (damped-oscillator 10000 1000 .001)
     '\#(1 0)
     .01))%
\end{schemenoindent}

\todo{Show some output?}

% (letrec ((loop (lambda (s)
%                (newline)
%                (write (head s))
%                (loop (tail s)))))
%   (loop the-states))

% #(1 0)
% #(0.99895054 9.994835e-6)
% #(0.99780226 1.9978681e-5)
% #(0.9965554 2.9950552e-5)
% #(0.9952102 3.990946e-5)
% #(0.99376684 4.985443e-5)
% #(0.99222565 5.9784474e-5)
% #(0.9905868 6.969862e-5)
% #(0.9888506 7.9595884e-5)
% #(0.9870173 8.94753e-5)