bulirsch-stoer.scm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. #| -*-Scheme-*-
  2. Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
  3. 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  4. 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Massachusetts
  5. Institute of Technology
  6. This file is part of MIT/GNU Scheme.
  7. MIT/GNU Scheme is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11. MIT/GNU Scheme is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with MIT/GNU Scheme; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
  18. USA.
  19. |#
  20. ;;;; Bulirsch-Stoer integration: Send bug reports to gjs@mit.edu
  21. ;;; Ideas from Jack Wisdom, from Michel Henon, from B&S
  22. #|
  23. ((advance-generator
  24. (bulirsch-stoer-lisptran ;integrator
  25. (lambda (vin vout) ;x'= x
  26. (vector-set! vout 0
  27. (vector-ref vin 0)))
  28. 1 ;1 dimension
  29. .0001)) ;error tolerated
  30. #(1.0)
  31. 1.0
  32. 0.1
  33. 0.5 ;no step larger than .5
  34. (lambda (ns dt h cont)
  35. (pp (list dt ns))
  36. (cont))
  37. (lambda (ns dt sdt)
  38. ;; assert ns = #(2.718...)
  39. ;; assert dt = 1.000...+-
  40. (list ns dt sdt)))
  41. (0. #(1.))
  42. (.1 #(1.1051708858929685))
  43. (.25 #(1.2840251054195329))
  44. (.47500000000000003 #(1.6080138082200066))
  45. (.8125 #(2.2535342510080656))
  46. ;Value: (#(2.7182794600110927) 1. .28125)
  47. ((advance-generator
  48. (bulirsch-stoer-lisptran ;integrator
  49. (lambda (vin vout)
  50. (vector-set! vout 0 1.0)
  51. (vector-set! vout 1 (flo:- 0.0 (vector-ref vin 2)))
  52. (vector-set! vout 2 (vector-ref vin 1)))
  53. 3 ;3 dimensions
  54. 1e-12)) ;error tolerated
  55. #(0.0 1.0 0.0)
  56. 2pi
  57. 0.1
  58. 1.0 ;no step larger than 1.0
  59. (lambda (ns dt h cont)
  60. (pp (list dt ns))
  61. (cont))
  62. (lambda (ns dt sdt)
  63. ;; assert ns = #(2.718...)
  64. ;; assert dt = 1.000...+-
  65. (list ns dt sdt)))
  66. (0. #(0. 1. 0.))
  67. (.1 #(.1 .9950041652780256 .09983341664682824))
  68. (.25 #(.25 .9689124217106447 .24740395925452305))
  69. (.47500000000000003 #(.4750000000000001 .8892927216231684 .4573384471789555))
  70. (.8125 #(.8125 .6876855622205039 .7260086552607131))
  71. (1.31875 #(1.31875 .2493861513251363 .9684041240759129))
  72. ...
  73. (5.328125 #(5.328125 .5775595272329195 -.8163485729163036))
  74. ;Value: (#(6.283185307179586 .9999999999999994 1.3276830294967203e-15)
  75. ;;;; 6.283185307179586 1.4325904607693793)
  76. (define (f x) (sin (/ 1.0 x)))
  77. ;Value: f
  78. ((advance-generator
  79. (bulirsch-stoer-lisptran ;integrator
  80. (lambda (vin vout)
  81. (let ((x (vector-ref vin 0)))
  82. (vector-set! vout 0 1.0)
  83. (vector-set! vout 1
  84. (flo:- 0.0
  85. (flo:/ (flo:cos (flo:/ 1.0 x))
  86. (flo:* x x))))))
  87. 2
  88. 1e-14)) ;error tolerated
  89. (vector -2.0 (f -2.0))
  90. 1.9
  91. 0.1
  92. 1.0
  93. (lambda (ns dt h cont)
  94. (pp (list dt ns))
  95. (cont))
  96. (lambda (ns dt sdt)
  97. ;; assert ns = #(2.718...)
  98. ;; assert dt = 1.000...+-
  99. (list ns dt sdt)))
  100. (0. #(-2. -.479425538604203))
  101. (.1 #(-1.9 -.5023511546035125))
  102. (.25 #(-1.75 -.5408342133588315))
  103. (.47500000000000003 #(-1.525 -.6097441128783215))
  104. (.8125 #(-1.1875 -.7460466536513232))
  105. (1.31875 #(-.6812499999999999 -.9947098054628543))
  106. (1.5465625 #(-.45343749999999994 -.8053211890895082))
  107. (1.6319921875 #(-.3680078124999999 -.4116456228081236))
  108. (1.76013671875 #(-.2398632812499999 .8559828752025934))
  109. (1.8178017578125 #(-.18219824218749991 .7136241717900977))
  110. (1.86970029296875 #(-.13029970703124993 -.9839567688364803))
  111. ;Value: (#(-.10000000000000009 .5440211108893656) 1.9 2.7269736328124856e-2)
  112. |#
  113. (declare (usual-integrations))
  114. (declare (integrate-operator for less-than))
  115. (define (for initial test increment to-do)
  116. (declare (integrate initial test increment to-do))
  117. (let loop ((x initial))
  118. (declare (integrate x))
  119. (if (test x)
  120. (begin (to-do x)
  121. (loop (increment x)))
  122. 'done)))
  123. (define (less-than n)
  124. (declare (integrate n))
  125. (lambda (i)
  126. (declare (integrate i))
  127. (fix:< i n)))
  128. ;;; FBE: make these parameters
  129. (define *max-tableau-depth* (make-parameter (void)))
  130. (define *max-tableau-width* (make-parameter (void)))
  131. (define bulirsch-stoer-steps (make-parameter (void)))
  132. (define bulirsch-stoer-magic-vectors (make-parameter (void)))
  133. (define (bulirsch-stoer-setup max-depth max-width)
  134. (define (bsi n)
  135. (cons-stream (expt 2 (+ n 1))
  136. (cons-stream (* 3 (expt 2 n))
  137. (bsi (+ n 1)))))
  138. (*max-tableau-depth* max-depth)
  139. (*max-tableau-width* max-width)
  140. (let ((bulirsch-stoer-integers (cons-stream 1 (bsi 0))))
  141. (pp (stream-head bulirsch-stoer-integers max-depth))
  142. (bulirsch-stoer-steps
  143. (list->vector
  144. (map (lambda (x) (fix:* 2 x))
  145. (stream-head bulirsch-stoer-integers max-depth))))
  146. (bulirsch-stoer-magic-vectors
  147. (make-initialized-vector (*max-tableau-depth*)
  148. (lambda (m)
  149. (flo:make-initialized-vector (min m (*max-tableau-width*))
  150. (lambda (k)
  151. (exact->inexact
  152. (square (/ (stream-ref bulirsch-stoer-integers m)
  153. (stream-ref bulirsch-stoer-integers
  154. (fix:- m (fix:1+ k)))))))))))
  155. 'done))
  156. (define %numerics-ode-bulirsch-stoer-dummy-1
  157. (bulirsch-stoer-setup 10 6))
  158. ;;; (1 2 3 4 6 8 12 16 24 32)
  159. #|
  160. ;; bulirsch-stoer-integers = #(1 repeated{2^n+1 3*2^n})
  161. (define bulirsch-stoer-integers
  162. #(1 2 3 4 6 8 12 16 24 32 48 64 96))
  163. |#
  164. (define-integrable (vector-copy-into-vector dim v1 v2)
  165. (for 0 (less-than dim) fix:1+
  166. (lambda (i)
  167. (declare (integrate i))
  168. (vector-set! v2 i (vector-ref v1 i)))))
  169. (define-integrable (flo:vector-copy-into-vector dim v1 v2)
  170. (for 0 (less-than dim) fix:1+
  171. (lambda (i)
  172. (declare (integrate i))
  173. (flo:vector-set! v2 i (flo:vector-ref v1 i)))))
  174. (define-integrable (flo:vector-copy source)
  175. (flo:make-initialized-vector (flo:vector-length source)
  176. (lambda (i)
  177. (declare (integrate i))
  178. (flo:vector-ref source i))))
  179. (define-integrable (c*v+v dim c v1 v2 ans)
  180. (for 0 (less-than dim) fix:1+
  181. (lambda (i)
  182. (declare (integrate i))
  183. (flo:vector-set! ans i
  184. (flo:+ (flo:* c (flo:vector-ref v1 i))
  185. (flo:vector-ref v2 i))))))
  186. (define-integrable (c*v+v+v*c dim c1 v1 v2 v3 c2 ans)
  187. (for 0 (less-than dim) fix:1+
  188. (lambda (i)
  189. (declare (integrate i))
  190. (flo:vector-set! ans i
  191. (flo:* c2
  192. (flo:+
  193. (flo:+ (flo:* c1 (flo:vector-ref v1 i))
  194. (flo:vector-ref v2 i))
  195. (flo:vector-ref v3 i)))))))
  196. (define-integrable (vector-copy-into-floating-vector dim v1 v2)
  197. (for 0 (less-than dim) fix:1+
  198. (lambda (i)
  199. (declare (integrate i))
  200. (flo:vector-set! v2 i (->flonum (vector-ref v1 i))))))
  201. (define-integrable (floating-vector-copy-into-vector dim v1 v2)
  202. (for 0 (less-than dim) fix:1+
  203. (lambda (i)
  204. (declare (integrate i))
  205. (vector-set! v2 i (flo:vector-ref v1 i)))))
  206. (define vector-Gragg
  207. (lambda (g dim)
  208. (let ((temp0 (flo:make-vector dim 0.0))
  209. (temp1 (flo:make-vector dim 0.0))
  210. (temp2 (flo:make-vector dim 0.0))
  211. (temp3 (flo:make-vector dim 0.0)))
  212. (let ((g$y0 temp0)
  213. (eta_1 temp1)
  214. (eta_j+2 temp1)
  215. (eta_j+1 temp2)
  216. (g$eta_j temp3)
  217. (g$eta_j+1 temp3))
  218. (lambda (y0 HH)
  219. (g y0 g$y0)
  220. (lambda (n yn)
  221. (let* ((h (flo:/ HH (exact->inexact n)))
  222. (2h (flo:* 2.0 h)))
  223. ;; Fortran
  224. (c*v+v dim h g$y0 y0 eta_1)
  225. (let lp ((j 2) (eta_j-1 y0) (eta_j eta_1))
  226. (if (fix:< j n)
  227. (begin (g eta_j g$eta_j)
  228. (c*v+v dim 2h g$eta_j eta_j-1 eta_j+1)
  229. (g eta_j+1 g$eta_j+1)
  230. (c*v+v dim 2h g$eta_j+1 eta_j eta_j+2)
  231. (lp (fix:+ j 2) eta_j+1 eta_j+2))
  232. (begin (g eta_j g$eta_j)
  233. (c*v+v dim 2h g$eta_j eta_j-1 eta_j+1)
  234. (g eta_j+1 g$eta_j+1)
  235. (c*v+v+v*c dim h g$eta_j+1 eta_j eta_j+1 0.5 yn)))))))))))
  236. ;;;; (bulirsch-stoer-lisptran f n tolerance)
  237. ;;; f is a system derivative,
  238. ;;; n is the system dimension,
  239. ;;; tolerance is the maximum allowable relative error.
  240. ;;;
  241. ;;; As in FORTRAN, f takes an n-dimensional state vector,
  242. ;;; and an answer vector to clobber
  243. ;;; it clobbers the answer to be the state derivative vector.
  244. ;;;
  245. ;;; (bulirsch-stoer-lisptran f n tolerance) returns a procedure
  246. ;;; that takes
  247. ;;; a state and
  248. ;;; a requested advance,
  249. ;;; it calls a continuation
  250. ;;; that takes a new state,
  251. ;;; the advance achieved, and
  252. ;;; a guestimate of the achievable advance.
  253. (define (lisptran-derivative->floating-lisptran-derivative f n) ; f!(y y')
  254. (let ((vy (make-vector n 0.0)) (vyp (make-vector n 0.0)))
  255. (define (floating-lisptran-derivative fvy fvyp)
  256. (floating-vector-copy-into-vector n fvy vy)
  257. (f vy vyp)
  258. (vector-copy-into-floating-vector n vyp fvyp))
  259. floating-lisptran-derivative))
  260. (define (error-measure->floating-error-measure error-measure n)
  261. (let ((old-state-estimate-lisp (make-vector n 0.0))
  262. (new-state-estimate-lisp (make-vector n 0.0)))
  263. (define (floating-error-measure new-state-estimate old-state-estimate)
  264. (floating-vector-copy-into-vector n new-state-estimate new-state-estimate-lisp)
  265. (floating-vector-copy-into-vector n old-state-estimate old-state-estimate-lisp)
  266. (error-measure new-state-estimate-lisp old-state-estimate-lisp))
  267. floating-error-measure))
  268. (define (bulirsch-stoer-lisptran f n tolerance)
  269. (let ((floating-stepper
  270. (bulirsch-stoer-floating-lisptran
  271. (lisptran-derivative->floating-lisptran-derivative f n)
  272. n
  273. (error-measure->floating-error-measure
  274. (parse-error-measure tolerance)
  275. n))))
  276. (lambda (state delta-t-suggested continuation) ;lisp vector states
  277. (floating-stepper (vector->flonum-vector state)
  278. delta-t-suggested
  279. (lambda (floating-new-state actual-delta-t suggested-delta-t)
  280. (continuation (flonum-vector->vector floating-new-state)
  281. actual-delta-t suggested-delta-t))))))
  282. (define (bulirsch-stoer-floating-lisptran f n error-measure)
  283. (let ((mm (vector-Gragg f n))
  284. (state-estimate1 (flo:make-vector n 0.0))
  285. (state-estimate2 (flo:make-vector n 0.0))
  286. (gragg-output1 (flo:make-vector n 0.0))
  287. (gragg-output2 (flo:make-vector n 0.0))
  288. (tableau
  289. (make-initialized-vector n
  290. (lambda (i) (flo:make-vector (*max-tableau-width*) 0.0)))))
  291. (lambda (state delta-t-suggested continuation)
  292. ;; continuation = (lambda (new-state actual-delta-t suggested-delta-t) ...)
  293. (if bulirsch-stoer-state-wallp
  294. (pp `(bulirsch-stoer-state ,state ,delta-t-suggested)))
  295. (let outside ((delta-t delta-t-suggested))
  296. (let ((modified-midpoint (mm state delta-t)))
  297. (modified-midpoint 2 state-estimate1)
  298. (flo:vector-copy-into-vector n state-estimate1 gragg-output1)
  299. (let m-loop ((m 1)
  300. ;;(old-verr) ; FBE must give a value
  301. (old-verr unspecific)
  302. (old-state-estimate state-estimate1)
  303. (new-state-estimate state-estimate2)
  304. (old-out gragg-output1)
  305. (new-out gragg-output2)
  306. (fail #f)) ;zero divide would have happened
  307. (if (fix:< m (*max-tableau-depth*))
  308. (let ((m1 (min m (*max-tableau-width*)))
  309. (d (vector-ref (bulirsch-stoer-magic-vectors) m)))
  310. (modified-midpoint (vector-ref (bulirsch-stoer-steps) m) new-out)
  311. (for 0 (less-than n) fix:1+
  312. (lambda (i) ;coordinates
  313. (declare (integrate i))
  314. (let* ((dta (flo:vector-ref old-out i))
  315. (yb (flo:vector-ref new-out i))
  316. (c yb))
  317. (for 0 (less-than m1) fix:1+
  318. (lambda (k) ;width of tableau
  319. (declare (integrate k))
  320. (let* ((b1 (flo:* (flo:vector-ref d k) dta))
  321. (den (flo:- b1 c))
  322. (dtn dta))
  323. (if (not (flo:= den 0.0))
  324. (let ((b (flo:/ (flo:- c dta) den)))
  325. (set! dtn (flo:* c b))
  326. (set! c (flo:* b1 b)))
  327. (set! fail #t))
  328. (set! dta (flo:vector-ref (vector-ref tableau i) k))
  329. (flo:vector-set! (vector-ref tableau i) k dtn)
  330. (set! yb (flo:+ yb dtn)))))
  331. (flo:vector-set! new-state-estimate i yb))))
  332. (let ((verr (error-measure new-state-estimate old-state-estimate)))
  333. (if bulirsch-stoer-error-wallp
  334. (pp `(bulirsch-stoer-error level: ,m error: ,verr h: ,delta-t)))
  335. ;; In Jack's C program the first two conditions
  336. ;; below are interchanged and the minimum number
  337. ;; of iterations is set to (fix:< m 4)
  338. (cond ;;(fail)
  339. ;;not good to (outside (* 0.9 delta-t)) or to m-loop with m+1
  340. ((flo:< verr 2.0)
  341. (continuation (flo:vector-copy new-state-estimate)
  342. delta-t
  343. (flo:* (flo:* delta-t bulirsch-stoer-magic-multiplier)
  344. (flo:expt bulirsch-stoer-magic-base
  345. (exact->inexact (fix:- m m1))))))
  346. ((fix:< m 2)
  347. (m-loop (fix:1+ m) verr
  348. new-state-estimate old-state-estimate
  349. new-out old-out #f))
  350. ((not (flo:< verr old-verr))
  351. (outside (flo:* 0.5 delta-t)))
  352. (else
  353. (m-loop (fix:1+ m) verr
  354. new-state-estimate old-state-estimate
  355. new-out old-out #f)))))
  356. (outside (flo:* 0.5 delta-t)))))))))
  357. (define bulirsch-stoer-magic-multiplier 1.5)
  358. (define bulirsch-stoer-magic-base 0.6)
  359. (define bulirsch-stoer-error-wallp false)
  360. (define bulirsch-stoer-state-wallp false)
  361. (define %numerics-ode-bulirsch-stoer-dummy-2
  362. (add-integrator!
  363. 'bulirsch-stoer-lisptran
  364. (lambda (lisptran-derivative
  365. dimension
  366. lte-tolerance
  367. start-state
  368. step-required
  369. h-suggested
  370. max-h
  371. continue
  372. done)
  373. ((advance-generator
  374. (bulirsch-stoer-lisptran lisptran-derivative dimension lte-tolerance))
  375. start-state
  376. step-required
  377. h-suggested
  378. max-h
  379. continue
  380. done))
  381. '(lisptran-derivative
  382. dimension
  383. lte-tolerance
  384. start-state
  385. step-required
  386. h-suggested
  387. max-h
  388. continue
  389. done)))
  390. ;;; A convenience for interchangeable use of lisptran and functional
  391. ;;; forms of system derivative.
  392. (define (system-derivative->lisptran-derivative f) ; y' = f(y)
  393. (define (lisptran-derivative y yprime)
  394. (subvector-move-left! (f y) 0 (vector-length y) yprime 0))
  395. lisptran-derivative)
  396. (define (lisptran-derivative->system-derivative f!) ; f!(y y')
  397. (define (system-derivative y)
  398. (let ((ans (make-vector (vector-length y))))
  399. (f! y ans)
  400. ans))
  401. system-derivative)