-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathexample.tex
173 lines (148 loc) · 4.83 KB
/
example.tex
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
\chapter{Example }
\label{exampleappendix}
\nobreak
This section describes an example consisting of the
\library{runge-kutta} library, which provides an {\cf integrate-system}
procedure that 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.
As the \library{runge-kutta} library makes use of the \rsixlibrary{base}
library, its skeleton is as follows:
\begin{scheme}
\#!r6rs
(library (runge-kutta)
(export integrate-system
head tail)
(import (rnrs base))
\hyper{library body})
\end{scheme}
The procedure definitions described below go in the place of \hyper{library body}.
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
(lambda ()
(map-streams next states)))))
states))))%
\end{schemenoindent}
The {\cf runge-kutta-4} procedure takes a function, {\tt f}, that produces a
system derivative from a system state. The {\cf runge-kutta-4} procedure
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}
The {\cf map-streams} procedure 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))
(lambda () (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 procedure that delivers the rest
of the stream.
\begin{schemenoindent}
(define head car)
(define tail
(lambda (stream) ((cdr stream))))%
\end{schemenoindent}
\bigskip
The following program illustrates the use of {\cf integrate-\hp{}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}
\#!r6rs
(import (rnrs base)
(rnrs io simple)
(runge-kutta))
(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))
(letrec ((loop (lambda (s)
(newline)
(write (head s))
(loop (tail s)))))
(loop the-states))%
\end{schemenoindent}
This prints output like the following:
\begin{scheme}
\#(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)
\end{scheme}
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "r6rs"
%%% End: