interface.scm 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  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. ;;;; State advancer for parametric system derivatives with
  21. ;;; arbitrarily-structured states.
  22. (declare (usual-integrations))
  23. ;;; Assumptions:
  24. ;;; Integrators never step further than suggested dt.
  25. ;;; System derivatives always have independent variable in slot 0.
  26. #|
  27. ;;; Example of use
  28. (pe ((evolve
  29. (lambda (a)
  30. (lambda (s)
  31. (up 1 (* a (ref s 1)))))
  32. 2) ;parameter a=2
  33. (up 0 1) ;initial state
  34. pp ;print monitor
  35. .1 ;monitor interval
  36. -10 ;target time
  37. 1.e-12 ;eps -- optional
  38. 1.1 ;initial integration step
  39. ))
  40. |#
  41. (define (evolve parametric-sysder . parameters)
  42. (lambda* (initial-state monitor dt-monitor tfinal #:optional eps dt)
  43. (let* (;; First float all numeric arguments.
  44. (dt-monitor (->flonum dt-monitor))
  45. (dt (if (default-object? dt)
  46. dt-monitor
  47. (->flonum dt)))
  48. (eps (cond ((default-object? eps)
  49. (*default-advancer-tolerance*))
  50. ((number? eps)
  51. (->flonum eps))
  52. (else eps))) ; may be a custom procedure
  53. (tfinal (->flonum tfinal))
  54. (parameters (map ->flonum parameters))
  55. (initial-state (s:map/r ->flonum initial-state))
  56. (direction (sign (- tfinal (s:ref initial-state 0))))
  57. (dt-monitor (* direction (abs dt-monitor)))
  58. (dt (* direction (abs dt)))
  59. (free-run
  60. (apply free-run-state-advancer parametric-sysder parameters)))
  61. (define (zero-in state next-state ttarget)
  62. (let ((current-time (s:ref state 0))
  63. (next-time (s:ref next-state 0)))
  64. (if (<= (abs (- ttarget current-time)) (abs (- ttarget next-time)))
  65. (go-to state ttarget (- ttarget current-time) monitor)
  66. (go-to next-state ttarget (- ttarget next-time) monitor))))
  67. (define (go-to state target-time dt continue)
  68. (let lp ((state state) (dt dt))
  69. (if (close-enuf? target-time (s:ref state 0) (*time-tolerance*))
  70. (continue state)
  71. (let ((time-to-target (- target-time (s:ref state 0))))
  72. (free-run state
  73. (* (sign time-to-target)
  74. (min (abs time-to-target) (abs dt)))
  75. eps
  76. (lambda (new-state dt-obtained dt-suggested)
  77. (lp new-state dt-suggested)))))))
  78. (define (between? t0 t1 t2)
  79. (<= (* direction t0) (* direction t1) (* direction t2)))
  80. (monitor initial-state)
  81. (free-run initial-state dt eps
  82. (lambda (new-state dt-obtained dt-suggested)
  83. (let loop ((state initial-state)
  84. (next-state new-state)
  85. (dt-suggested dt-suggested)
  86. (tmonitor (+ (s:ref initial-state 0) dt-monitor)))
  87. (let ((current-time (s:ref state 0))
  88. (next-time (s:ref next-state 0))
  89. (dt-suggested (* direction (abs dt-suggested))))
  90. (define (do-monitor)
  91. (zero-in state next-state tmonitor)
  92. (loop state next-state dt-suggested (+ tmonitor dt-monitor)))
  93. (if (between? current-time tfinal next-time)
  94. (if (between? current-time tmonitor tfinal)
  95. (do-monitor)
  96. (go-to state tfinal (- tfinal current-time)
  97. (lambda (s) (monitor s) s)))
  98. (if (between? current-time tmonitor next-time)
  99. (do-monitor)
  100. (free-run next-state dt-suggested eps
  101. (lambda (new-state dt-obtained dt-suggested)
  102. (loop next-state new-state dt-suggested tmonitor))))))))))))
  103. ;;; FBE: make parameters
  104. (define *time-tolerance* (make-parameter 1e-13))
  105. (define *default-advancer-tolerance* (make-parameter 1e-12))
  106. #|
  107. ;;; Takes a step in the direction of the specified dt. Returns the
  108. ;;; state achieved, the step taken, which may be smaller than
  109. ;;; requested, and a suggested next step.
  110. (pe ((free-run-state-advancer
  111. (lambda (a)
  112. (lambda (s)
  113. (up 1 (up (* a (ref s 1 0)) (/ (ref s 1 1) a)))))
  114. 2)
  115. (up -1 (up 1 1))
  116. 1
  117. 1.e-12
  118. list))
  119. ((up 0. (up 7.389056098930656 1.6487212707001282)) 1 .8999999999999999)
  120. (exp 2)
  121. ;Value: 7.38905609893065
  122. (exp 1/2)
  123. ;Value: 1.6487212707001282
  124. ;;; Takes a step of the size specified. Returns the target state, the
  125. ;;; last step size, and a suggested further step. The last two may
  126. ;;; not be very useful.
  127. (pe ((state-advancer
  128. (lambda (a)
  129. (lambda (s)
  130. (up 1 (* a (ref s 1)))))
  131. 2)
  132. (up 0 1)
  133. 10
  134. 1.e-12
  135. list))
  136. ((up 10. 485165195.4098082) 2.1316282072803006e-14 3.197442310920451e-14)
  137. (exp 20)
  138. ;Value: 485165195.40979075
  139. |#
  140. #|
  141. (set-ode-integration-method! 'gear)
  142. ;Value: bulirsch-stoer
  143. (set! *compiling-sysder? #f)
  144. ;Value: #t
  145. ((free-run-state-advancer
  146. (lambda ()
  147. (lambda (x)
  148. (vector 1.0 (vector-ref x 1)))))
  149. #(0.0 1.0) ;initial conditions
  150. 1.0 ;target advance
  151. .000000000001 ;lte
  152. list)
  153. ;Value: (#(.999999999999987 2.7182818284594377) 1. 5.010573747095126e-4)
  154. |#
  155. (define (state-advancer sysder . params)
  156. (let* ((params (map ->flonum params))
  157. (free-run (apply free-run-state-advancer sysder params)))
  158. (lambda* (initial-state dt-required #:optional eps continue)
  159. (let ((initial-state (s:map/r ->flonum initial-state))
  160. (dt-required (->flonum dt-required))
  161. (eps (cond ((default-object? eps)
  162. (*default-advancer-tolerance*))
  163. ((number? eps)
  164. (->flonum eps))
  165. (else eps)))
  166. (continue
  167. (if (default-object? continue)
  168. (lambda (new-state dt-obtained dt-suggested) new-state)
  169. continue)))
  170. (define (go-to state target-time dt continue)
  171. (let lp ((state state) (dt dt))
  172. (if (close-enuf? target-time (s:ref state 0) (*time-tolerance*))
  173. (continue state dt-required dt)
  174. (let ((time-to-target (- target-time (s:ref state 0))))
  175. (free-run state
  176. (* (sign time-to-target)
  177. (min (abs time-to-target) (abs dt)))
  178. eps
  179. (lambda (new-state dt-obtained dt-suggested)
  180. (lp new-state dt-suggested)))))))
  181. (let ((tinitial (s:ref initial-state 0))
  182. (tfinal (+ (s:ref initial-state 0) dt-required)))
  183. (go-to initial-state tfinal (- tfinal tinitial) continue))))))
  184. (define (advance-beyond parametric-sysder . parameters)
  185. (let ((advancer (apply free-run-state-advancer parametric-sysder parameters)))
  186. (define (run state dt-suggested eps target-time continue)
  187. (let lp ((state state) (dt-suggested dt-suggested))
  188. (if (< (* dt-suggested (s:ref state 0)) (* dt-suggested target-time))
  189. (advancer state dt-suggested eps
  190. (lambda (new-state dt-obtained dt-suggested)
  191. (lp new-state dt-suggested)))
  192. (continue state dt-suggested dt-suggested))))
  193. run))
  194. ;;; Proceed below this line with caution. HIC SVNT DRACONES!
  195. (define* (free-run-state-advancer parametric-sysder #:rest params)
  196. (let ((stepper #f))
  197. (define (flatten state)
  198. (list->vector (ultra-flatten state)))
  199. (define (unflatten state fstate)
  200. (ultra-unflatten state (vector->list fstate)))
  201. (define (advance-state state dt eps continue)
  202. ;; Continue = (lambda (new-state dt-obtained dt-suggested) ...)
  203. (let* ((fstate (flatten state))
  204. (parametric-flat-sysder
  205. (make-parametric-flat-sysder parametric-sysder
  206. (lambda (params)
  207. (lambda (fstate)
  208. (flatten ((apply parametric-sysder params)
  209. (unflatten state fstate)))))
  210. params
  211. fstate)))
  212. ((or stepper
  213. (begin (set! stepper
  214. (ode-advancer (parametric-flat-sysder params)
  215. eps
  216. (vector-length fstate)))
  217. stepper))
  218. fstate
  219. dt
  220. (lambda (new-fstate dt-obtained dt-suggested)
  221. (continue (unflatten state new-fstate) dt-obtained dt-suggested)))))
  222. advance-state))
  223. (define (make-parametric-flat-sysder
  224. parametric-sysder parametric-flat-sysder params fstate)
  225. (cond ((gear? *ode-integration-method*)
  226. ;; produce f&df
  227. (if (*compiling-sysder?)
  228. (let* ((cpfs
  229. (compile-parametric-memoized parametric-sysder
  230. parametric-flat-sysder
  231. params
  232. fstate))
  233. (parametric-flat-jacobian
  234. (lambda (params)
  235. (lambda (fstate)
  236. (s->m (compatible-shape fstate)
  237. ((g:derivative (parametric-flat-sysder params))
  238. fstate)
  239. fstate))))
  240. (cpfj
  241. (compile-parametric-memoized cpfs
  242. parametric-flat-jacobian
  243. params
  244. fstate)))
  245. (lambda (params)
  246. (let ((f (cpfs params)) (df (cpfj params)))
  247. (lambda (fstate cont)
  248. (cont (f fstate) (df fstate))))))
  249. (let ((cs (compatible-shape fstate)))
  250. (lambda (params)
  251. (let ((f (parametric-flat-sysder params))
  252. (df (g:derivative (parametric-flat-sysder params))))
  253. (lambda (fstate cont)
  254. (cont (f fstate) (s->m cs (df fstate) fstate))))))))
  255. ((*compiling-sysder?)
  256. ;; produce compiled flat sysder
  257. (compile-parametric-memoized
  258. parametric-sysder ;for memoizer
  259. parametric-flat-sysder ;to be compiled
  260. params
  261. fstate))
  262. (else
  263. parametric-flat-sysder)))
  264. ;;; FBE: make parameters
  265. (define *compiling-sysder? (make-parameter #t))
  266. (define *max-compiled-sysder-table-size* (make-parameter 3))
  267. (define *compiled-sysder-table-size* (make-parameter 0))
  268. (define *compiled-sysder-table* (make-parameter '()))
  269. (define compile-parametric-memoized
  270. (let ((sm1 (fix:- (*max-compiled-sysder-table-size*) 1)))
  271. (define (run parametric-sysder parametric-flat-sysder params fstate)
  272. (let* ((n-params (length params))
  273. (n-state (vector-length fstate))
  274. (x (list n-params n-state parametric-sysder))
  275. (seen (assoc x (*compiled-sysder-table*))))
  276. (if seen
  277. (cadr seen)
  278. (let ((ans (compile-parametric n-params n-state parametric-flat-sysder)))
  279. (cond ((fix:= (*compiled-sysder-table-size*)
  280. (*max-compiled-sysder-table-size*))
  281. (*compiled-sysder-table*
  282. (cons (list x ans)
  283. (list-head (*compiled-sysder-table*) sm1))))
  284. (else
  285. (*compiled-sysder-table*
  286. (cons (list x ans) (*compiled-sysder-table*)))
  287. (*compiled-sysder-table-size*
  288. (fix:+ (*compiled-sysder-table-size*) 1))))
  289. ans))))
  290. run))
  291. ;;; For compiling a parametric function of a vector.
  292. ;;; The procedure is of the form (lambda (p1 ... pn) (lambda (v) ...))
  293. ;;; The number of parameters is n-params.
  294. ;;; The length of the vector v is n-state-vars.
  295. ;;; Makes a compiled procedure which takes a list of parameters
  296. ;;; (lambda (params) (lambda (v) ...))
  297. ;;; instead of the parameters spread out as in the source.
  298. ;;; FBE: make it a parameter and initialize it here.
  299. (define *compiler-simplifier* (make-parameter simplify))
  300. ;;; If no "simplification" is desired
  301. ;;;(set! *compiler-simplifier* expression)
  302. ;;; Default is to use usual simplifier
  303. ;;(set! *compiler-simplifier* simplify)
  304. (define* (compile-parametric n-params n-state-vars procedure #:optional simplifier compiler)
  305. (let ((parameter-arity (procedure-arity procedure)))
  306. #|
  307. (if (not (and (number? (cdr parameter-arity))
  308. (fix:= (car parameter-arity) (cdr parameter-arity))))
  309. (error "Indeterminate parameters in parametric procedure"))
  310. (if (not (fix:= n-params (car parameter-arity)))
  311. (error "Wrong number of parameters to parametric procedure"))
  312. |#
  313. (if (default-object? simplifier) (set! simplifier (*compiler-simplifier*)))
  314. (if (default-object? compiler) (set! compiler lambda->numerical-procedure))
  315. (let ((param-names
  316. (generate-list n-params
  317. (lambda (i)
  318. (string->uninterned-symbol
  319. (string-append "c" (number->string i))))))
  320. (params (string->uninterned-symbol "params"))
  321. (state-var-names
  322. (generate-list n-state-vars
  323. (lambda (i)
  324. (string->uninterned-symbol
  325. (string-append "x" (number->string i))))))
  326. (state (string->uninterned-symbol "state")))
  327. (let* ((state-procedure
  328. (with-literal-apply-enabled
  329. (lambda () (procedure param-names))))
  330. (sderiv-exp
  331. (flush-column
  332. (simplifier
  333. (with-literal-apply-enabled
  334. (lambda ()
  335. (state-procedure
  336. (list->vector state-var-names))))))))
  337. (let ((lexp
  338. `(lambda (,params)
  339. (let (,@(map (lambda (pn j)
  340. `(,pn (list-ref ,params ,j)))
  341. param-names
  342. (generate-list n-params (lambda (j) j))))
  343. (lambda (,state)
  344. (let (,@(map (lambda (xi i)
  345. `(,xi (vector-ref ,state ,i)))
  346. state-var-names
  347. (generate-list n-state-vars (lambda (i) i))))
  348. ,sderiv-exp))))))
  349. (compiler lexp))))))
  350. (define (flush-column exp)
  351. (if (eq? (car exp) up-constructor-name)
  352. (cons 'vector (cdr exp))
  353. exp))
  354. #|
  355. (define ((L-coupled-harmonic m k) state)
  356. (let ((q (coordinate state))
  357. (qdot (velocity state)))
  358. (- (* 1/2 qdot m qdot)
  359. (* 1/2 q k q))))
  360. (pe ((phase-space-derivative
  361. (Lagrangian->Hamiltonian
  362. (L-coupled-harmonic (down (down 'm_1 0)
  363. (down 0 'm_2))
  364. (down (down 'k_1 'c)
  365. (down 'c 'k_2)))))
  366. (->H-state 't
  367. (coordinate-tuple 'x_1 'x_2)
  368. (momentum-tuple 'p_1 'p_2))))
  369. (up 1
  370. (up (/ p_1 m_1)
  371. (/ p_2 m_2))
  372. (down (+ (* -1 c x_2) (* -1 k_1 x_1))
  373. (+ (* -1 c x_1) (* -1 k_2 x_2))))
  374. (define (sysder-HO m1 m2 k1 k2 c)
  375. (phase-space-derivative
  376. (Lagrangian->Hamiltonian
  377. (L-coupled-harmonic (down (down m1 0)
  378. (down 0 m2))
  379. (down (down k1 c)
  380. (down c k2))))))
  381. ((state-advancer sysder-HO 1. 1. 1. 1. 0.)
  382. (up 0. (up 1. 2.) (down 3. 4.))
  383. 10
  384. 1.e-12)
  385. ;Value: #(10.000000000000004 #(-2.4711348617445603 -3.854227501710379) (*down* #(-1.9731934763399812 -2.2682438945270498)))
  386. (length (*compiled-sysder-table*))
  387. ;Value: 1
  388. (pp (cadr (car (*compiled-sysder-table*))))
  389. (lambda (params)
  390. (let ((c4 (list-ref params 4)))
  391. (lambda (state)
  392. (let ((V-212 (&* (vector-ref state 2) -1)) (V-211 (&* (vector-ref state 1) -1)))
  393. (vector 1
  394. (&/ (vector-ref state 3) (list-ref params 0))
  395. (&/ (vector-ref state 4) (list-ref params 1))
  396. (&+ (&* V-211 (list-ref params 2)) (&* V-212 c4))
  397. (&+ (&* V-212 (list-ref params 3)) (&* V-211 c4)))))))
  398. ((evolve sysder-HO 1. 1. 1. 1. 0.)
  399. (up 0 (up 1 2) (down 3 4))
  400. pe
  401. 1
  402. 10
  403. )
  404. (up 0 (up 1 2) (down 3 4))
  405. (up 1. (up 3.064715260291832 4.4464885509678655) (down .7794359327965212 .47826725385676705))
  406. (up 2. (up 2.3117454439299054 2.8048960342084457) (down -2.157737936467112 -3.483182199839933))
  407. (up 3. (up -.5666324724208439 -1.4155049609614183) (down -3.111097497861209 -4.24221000252152))
  408. (up 3.9999999999999996 (up -2.9240511067874 -4.3344972229589365) (down -1.2041283672829095 -1.100969492838598))
  409. (up 5. (up -2.593110638526191 -3.2683727277261077) (down 1.8099108310528178 3.052497291179177))
  410. (up 6. (up .1219237920535883 .8026785805050183) (down 3.159926358150026 4.39951214299932))
  411. (up 7. (up 2.724862050499671 4.13575090356176) (down 1.6047201643111262 1.701635819935653))
  412. (up 8. (up 2.8225747060615296 3.666432918876308) (down -1.425858348049221 -2.5607166284812077))
  413. (up 9. (up .3252251938405927 -.17378658280231318) (down -3.1455092708957855 -4.468758018022222))
  414. (up 10. (up -2.47113486174456 -3.8542275017103753) (down -1.9731934763399899 -2.2682438945270835))
  415. ;Value: #(10. #(-2.47113486174456 -3.8542275017103753) (*down* #(-1.9731934763399899 -2.2682438945270835)))
  416. |#