quadrature.scm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  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. #!fold-case
  21. ;;;; Interface system for QUADRATURE
  22. (declare (usual-integrations))
  23. (define :-infinity ':-infinity)
  24. (define :+infinity ':+infinity)
  25. (define *infinities* (list :-infinity :+infinity))
  26. #|
  27. ;;; Bugs:
  28. ;;; The following should be pi.
  29. ;;; Unfortunately it converges so slowly that
  30. ;;; we never get a reasonable answer.
  31. ;;; The functions that we can integrate must
  32. ;;; decay at least as fast as 1/x^2
  33. ;;; as x->infinity.
  34. (* 2
  35. ((make-definite-integrator
  36. (lambda->numerical-procedure
  37. '(lambda (x) (/ (sin x) x)))
  38. 0.0
  39. :+infinity
  40. .01)
  41. 'integral))
  42. |#
  43. #|
  44. (define witch
  45. (lambda->numerical-procedure
  46. '(lambda (x)
  47. (/ 4.0 (+ 1.0 (* x x))))))
  48. (define integrator (make-definite-integrator))
  49. (integrator 'set-method! 'romberg)
  50. (integrator 'set-error! 1e-12)
  51. (integrator 'set-integrand! witch)
  52. (integrator 'set-lower-limit! 0.0)
  53. (integrator 'set-upper-limit! 1.0)
  54. (integrator 'integral)
  55. ;Value: 3.141592653589793
  56. ;;; Easy as pi.
  57. |#
  58. #|
  59. (define (foo n)
  60. (define int
  61. (make-definite-integrator
  62. (lambda (x) (expt (log (/ 1 x)) n))
  63. 0.0
  64. 1.0
  65. 1e-12))
  66. (int 'set-method! 'open-closed)
  67. (int 'integral))
  68. (foo 0)
  69. ;Value: 1.
  70. (foo 1)
  71. ;Value: .9999999999979357
  72. (foo 2)
  73. ;Value: 1.9999999999979101
  74. (foo 3)
  75. ;Value: 5.99999999999799
  76. (foo 4)
  77. ;Value: 23.999999999997893
  78. (foo 5)
  79. ;Value: 119.99999999999828
  80. ;;; Do you recognize the function FOO?
  81. (define (bar)
  82. (define int
  83. (make-definite-integrator
  84. (lambda (x) (* (exp (- x)) (log x)))
  85. 0.0
  86. :+infinity
  87. 1e-11))
  88. (int 'set-method! 'open-open)
  89. (int 'integral))
  90. ;Value: bar
  91. (bar)
  92. ;Value: -.5772156648993277
  93. ;;; Do you recognize this constant?
  94. |#
  95. (define* (make-definite-integrator
  96. #:optional integrand lower-limit upper-limit allowable-error method)
  97. (let* ((integrand
  98. (if (default-object? integrand) #f integrand))
  99. (lower-limit
  100. (if (default-object? lower-limit) #f lower-limit))
  101. (upper-limit
  102. (if (default-object? upper-limit) #f upper-limit))
  103. (allowable-error
  104. (if (default-object? allowable-error) 1.0e-10 allowable-error))
  105. (method
  106. (if (default-object? method) 'open method)))
  107. (define (the-integrator-control message . rest-of-arguments)
  108. (case message
  109. ((INTEGRAL)
  110. (evaluate-definite-integral
  111. method
  112. integrand
  113. lower-limit
  114. upper-limit
  115. allowable-error))
  116. ((INTEGRAND) integrand)
  117. ((SET-INTEGRAND!)
  118. (let ((x (car rest-of-arguments)))
  119. (set! integrand x)))
  120. ((LOWER-LIMIT) lower-limit)
  121. ((SET-LOWER-LIMIT!)
  122. (let ((x (car rest-of-arguments)))
  123. (set! lower-limit x)))
  124. ((UPPER-LIMIT) upper-limit)
  125. ((SET-UPPER-LIMIT!)
  126. (let ((x (car rest-of-arguments)))
  127. (set! upper-limit x)))
  128. ((ERROR) allowable-error)
  129. ((SET-ERROR!)
  130. (let ((x (car rest-of-arguments)))
  131. (set! allowable-error x)))
  132. ((METHOD) method)
  133. ((SET-METHOD!)
  134. (let ((x (car rest-of-arguments)))
  135. (set! method x)))
  136. (else
  137. (error "Unknown message -- ODE-INTEGRATOR") message)
  138. ))
  139. the-integrator-control))
  140. (define (evaluate-definite-integral method
  141. integrand
  142. lower-limit
  143. upper-limit
  144. allowable-error)
  145. (if (not (and integrand lower-limit upper-limit))
  146. (error "Missing parameter for definite integral"
  147. `(integrand ,integrand
  148. lower-limit ,lower-limit
  149. upper-limit ,upper-limit)))
  150. (let ((lower-limit (if (memq lower-limit *infinities*)
  151. lower-limit
  152. (exact->inexact lower-limit)))
  153. (upper-limit (if (memq upper-limit *infinities*)
  154. upper-limit
  155. (exact->inexact upper-limit)))
  156. (allowable-error (exact->inexact allowable-error)))
  157. (if (or (memq lower-limit *infinities*)
  158. (memq upper-limit *infinities*))
  159. (evaluate-improper-integral method
  160. integrand
  161. upper-limit
  162. lower-limit
  163. allowable-error)
  164. (case method
  165. ((OPEN)
  166. (integrate-open integrand
  167. lower-limit upper-limit
  168. allowable-error))
  169. ((CLOSED-CLOSED)
  170. (integrate-closed-closed-1 integrand
  171. lower-limit upper-limit
  172. allowable-error))
  173. ((CLOSED-OPEN)
  174. (integrate-closed-open-1 integrand
  175. lower-limit upper-limit
  176. allowable-error))
  177. ((OPEN-CLOSED)
  178. (integrate-open-closed-1 integrand
  179. lower-limit upper-limit
  180. allowable-error))
  181. ((OPEN-OPEN)
  182. (integrate-open-open integrand
  183. lower-limit upper-limit
  184. allowable-error))
  185. ((ROMBERG)
  186. (romberg-quadrature integrand
  187. lower-limit upper-limit
  188. allowable-error))
  189. ((BULIRSCH-STOER)
  190. (bulirsch-stoer-quadrature integrand
  191. lower-limit upper-limit
  192. allowable-error))
  193. (else
  194. (error "Unknown method -- DEFINITE-INTEGRAL" method))))))
  195. #|
  196. (define (evaluate-improper-integral method integrand upper-limit lower-limit allowable-error)
  197. (let ((new-integrand
  198. (lambda (theta)
  199. (/ (integrand (tan theta))
  200. (square (cos theta))))))
  201. (case lower-limit
  202. ((:-infinity)
  203. (case upper-limit
  204. ((:+infinity)
  205. (integrate-open-open new-integrand
  206. -pi/2 +pi/2
  207. allowable-error))
  208. ((:-infinity) 0.0)
  209. (else
  210. (if (memq method '(open-open closed-open))
  211. (integrate-open-open new-integrand
  212. -pi/2 (atan upper-limit)
  213. allowable-error)
  214. (integrate-open-closed new-integrand
  215. -pi/2 (atan upper-limit)
  216. allowable-error)))))
  217. ((:+infinity)
  218. (case upper-limit
  219. ((:+infinity) 0.0)
  220. ((:-infinity)
  221. (- (integrate-open-open new-integrand
  222. -pi/2 +pi/2
  223. allowable-error)))
  224. (else
  225. (if (memq method '(open-open open-closed))
  226. (- (integrate-open-open new-integrand
  227. (atan upper-limit) +pi/2
  228. allowable-error))
  229. (- (integrate-closed-open new-integrand
  230. (atan upper-limit) +pi/2
  231. allowable-error))))))
  232. (else
  233. (case upper-limit
  234. ((:+infinity)
  235. (if (memq method '(open-open open-closed))
  236. (integrate-open-open new-integrand
  237. (atan lower-limit) +pi/2
  238. allowable-error)
  239. (integrate-closed-open new-integrand
  240. (atan lower-limit) +pi/2
  241. allowable-error)))
  242. ((:-infinity)
  243. (if (memq method '(open-open open-closed))
  244. (- (integrate-open-open new-integrand
  245. -pi/2 (atan lower-limit)
  246. allowable-error))
  247. (- (integrate-closed-open new-integrand
  248. -pi/2 (atan lower-limit)
  249. allowable-error)))))))))
  250. |#
  251. ;;; Simpler version, from Press, et al.
  252. (define *improper-integral-breakpoint* +1.0)
  253. (define (evaluate-improper-integral method integrand upper-limit lower-limit allowable-error)
  254. (let ((new-integrand
  255. (lambda (t)
  256. (/ (integrand (/ 1.0 t))
  257. (* t t)))))
  258. (case lower-limit
  259. ((:-infinity)
  260. (case upper-limit
  261. ((:-infinity) 0.0)
  262. ((:+infinity)
  263. (+ (integrate-closed-open new-integrand
  264. (/ -1.0 *improper-integral-breakpoint*)
  265. 0.0
  266. allowable-error)
  267. (integrate-closed-closed integrand
  268. (- *improper-integral-breakpoint*)
  269. *improper-integral-breakpoint*
  270. allowable-error)
  271. (integrate-open-closed new-integrand
  272. 0.0
  273. (/ 1.0 *improper-integral-breakpoint*)
  274. allowable-error)))
  275. (else
  276. (if (<= upper-limit (- *improper-integral-breakpoint*))
  277. (integrate-open-open new-integrand
  278. (/ -1.0 upper-limit)
  279. 0.0
  280. allowable-error)
  281. (+ (integrate-closed-open new-integrand
  282. (/ -1.0 *improper-integral-breakpoint*)
  283. 0.0
  284. allowable-error)
  285. (integrate-closed-open integrand
  286. (- *improper-integral-breakpoint*)
  287. upper-limit
  288. allowable-error))))))
  289. ((:+infinity)
  290. (case upper-limit
  291. ((:-infinity)
  292. (- (+ (integrate-closed-open new-integrand
  293. (/ -1.0 *improper-integral-breakpoint*)
  294. 0.0
  295. allowable-error)
  296. (integrate-closed-closed integrand
  297. (- *improper-integral-breakpoint*)
  298. *improper-integral-breakpoint*
  299. allowable-error)
  300. (integrate-open-closed new-integrand
  301. 0.0
  302. (/ 1.0 *improper-integral-breakpoint*)
  303. allowable-error))))
  304. ((:+infinity) 0.0)
  305. (else
  306. (if (>= upper-limit *improper-integral-breakpoint*)
  307. (- (integrate-open-open new-integrand
  308. (/ 1.0 upper-limit)
  309. 0.0
  310. allowable-error))
  311. (- (+ (integrate-closed-open new-integrand
  312. (/ 1.0 *improper-integral-breakpoint*)
  313. 0.0
  314. allowable-error)
  315. (integrate-closed-open integrand
  316. *improper-integral-breakpoint*
  317. upper-limit
  318. allowable-error)))))))
  319. (else
  320. (case upper-limit
  321. ((:-infinity)
  322. (if (<= lower-limit (- *improper-integral-breakpoint*))
  323. (integrate-open-open new-integrand
  324. (/ -1.0 lower-limit)
  325. 0.0
  326. allowable-error)
  327. (+ (integrate-closed-open new-integrand
  328. (/ -1.0 *improper-integral-breakpoint*)
  329. 0.0
  330. allowable-error)
  331. (integrate-closed-open integrand
  332. *improper-integral-breakpoint*
  333. lower-limit
  334. allowable-error))))
  335. ((:+infinity)
  336. (if (>= lower-limit *improper-integral-breakpoint*)
  337. (integrate-open-open new-integrand
  338. 0.0
  339. (/ 1.0 lower-limit)
  340. allowable-error)
  341. (+ (integrate-open-closed integrand
  342. lower-limit
  343. *improper-integral-breakpoint*
  344. allowable-error)
  345. (integrate-open-closed new-integrand
  346. 0.0
  347. (/ 1.0 *improper-integral-breakpoint*)
  348. allowable-error))))
  349. (else
  350. (error "Should not get here -- IMPROPER-INTEGRAL")))))))
  351. (define (bulirsch-stoer-quadrature f t1 t2 allowable-error)
  352. ((advance-generator
  353. (bulirsch-stoer-lisptran
  354. ;; state = #(t int) ==> dstate = #(1.0 ,(integral f t1 t))
  355. (lambda (state dstate)
  356. (vector-set! dstate 0 1.0)
  357. (vector-set! dstate 1
  358. (f (vector-ref state 0))))
  359. 2
  360. allowable-error))
  361. (vector t1 0.0) ;initial state
  362. (- t2 t1)
  363. (/ (- t2 t1) 2)
  364. (- t2 t1)
  365. (lambda (ns dt h cont)
  366. (cont))
  367. (lambda (ns dt sdt)
  368. (vector-ref ns 1))))