deriv.scm 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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. ;;;; General Derivative Procedures
  21. (declare (usual-integrations))
  22. ;;; In DIFF.SCM we define the primitive mechanism extending the
  23. ;;; generic operators for differential quantities. We also defined
  24. ;;; DIFF:DERIVATIVE, the procedure that produces the derivative
  25. ;;; function of a real-valued function of a real argument. Here we
  26. ;;; use this mechanism to build derivatives of systems with
  27. ;;; structured arguments and structured values. The basic rule is
  28. ;;; that a derivative function produces a value which may be
  29. ;;; multiplied by an increment of the argument to get a linear
  30. ;;; approximation to the increment in the function.
  31. ;;; Let's start with functions on Euclidean space. We create a
  32. ;;; Euclidean-space derivative so that we may pass in an arbitrary
  33. ;;; structure of nested vectors and covectors.
  34. ;;;
  35. ;;; f
  36. ;;; R^n -----> R^m
  37. ;;;
  38. ;;; The derivative Df of this function is a function defined on R^n.
  39. ;;; It maps incremental vectors in R^n to incremental vectors in R^m.
  40. ;;;
  41. ;;; Df df
  42. ;;; R^n -----> (R^n -----> R^m)
  43. ;;;
  44. ;;; It is only for these Euclidean spaces that we can identify the
  45. ;;; manifold with its tangent space at each point. This will be a
  46. ;;; problem we will get back to later. Note that df is a linear
  47. ;;; function, so it can be represented by an mXn matrix. (That is,
  48. ;;; one with m rows and n columns.)
  49. ;;; Note: it makes no difference if the deriv:euclidean-structure is
  50. ;;; linear-memoized... Never get a cache hit.
  51. (define (deriv:euclidean-structure f selectors)
  52. (define (sd g v)
  53. (cond ((structure? v)
  54. (s:generate (s:length v) (s:opposite v)
  55. (lambda (i)
  56. (sd (lambda (xi)
  57. (g (s:with-substituted-coord v i xi)))
  58. (s:ref v i)))))
  59. ((or (numerical-quantity? v) (abstract-quantity? v))
  60. (simple-derivative-internal g v))
  61. (else
  62. (error "Bad structure -- DERIV:EUCLIDEAN-STRUCTURE" g v))))
  63. (define (a-euclidean-derivative v)
  64. (cond ((structure? v)
  65. (sd (lambda (w)
  66. (f (s:subst-internal v w selectors)))
  67. (ref-internal v selectors)))
  68. ((null? selectors)
  69. (simple-derivative-internal f v))
  70. (else
  71. (error "Bad selectors -- DERIV:EUCLIDEAN-STRUCTURE"
  72. f selectors v))))
  73. a-euclidean-derivative)
  74. #|
  75. ;;; An old failed experiment...
  76. (define (deriv:euclidean-structure f)
  77. (define (sd g v)
  78. (cond ((structure? v)
  79. (s:generate (s:length v) (s:opposite v)
  80. (lambda (i)
  81. (sd (lambda (xi)
  82. (g (s:with-substituted-coord v i xi)))
  83. (s:ref v i)))))
  84. ((or (numerical-quantity? v)
  85. (abstract-quantity? v))
  86. (simple-derivative-internal g v))
  87. (else
  88. (error "Bad structure -- DERIV:EUCLIDEAN-STRUCTURE"
  89. g v))))
  90. (define (a-euclidean-derivative v)
  91. (fluid-let ((differential-tag-count differential-tag-count))
  92. (sd f v)))
  93. a-euclidean-derivative)
  94. ;;; The fluid let greatly improves the efficiency of the system by
  95. ;;; reducing more intermediate expressions to a canonical form, but it
  96. ;;; causes the following bug:
  97. (pe ((simple-derivative-internal
  98. (lambda (eps)
  99. (lambda (t)
  100. ((D (* cos eps)) t)))
  101. 'e)
  102. 't))
  103. (* -1 (sin t)) ;; correct
  104. (pe (((D
  105. (lambda (eps)
  106. (lambda (t)
  107. ((D (* cos eps)) t))))
  108. 'e)
  109. 't))
  110. 0 ;; wrong!
  111. ;;; To recover this idea see custom-repl.scm
  112. |#
  113. ;;; Once we have this, we can implement derivatives of multivariate
  114. ;;; functions by wrapping their arguments into an UP-STRUCTURE for
  115. ;;; differentiation by DERIV:EUCLIDEAN-STRUCTURE. This code sucks!
  116. (define (deriv:multivariate-derivative f selectors)
  117. (let ((a (g:arity f))
  118. (d (lambda (f) (deriv:euclidean-structure f selectors))))
  119. (cond ((equal? a *exactly-zero*)
  120. (lambda () :zero))
  121. ((equal? a *at-least-one*)
  122. (lambda (x . y)
  123. ((d (lambda (s) (g:apply f (up-structure->list s))))
  124. (list->up-structure (cons x y)))))
  125. ((equal? a *exactly-one*)
  126. (d f))
  127. ((equal? a *at-least-two*)
  128. (lambda (x y . z)
  129. ((d (lambda (s) (g:apply f (up-structure->list s))))
  130. (list->up-structure (cons* x y z)))))
  131. ((equal? a *exactly-two*)
  132. (lambda (x y)
  133. ((d (lambda (s) (g:apply f (up-structure->list s))))
  134. (list->up-structure (list x y)))))
  135. ((equal? a *at-least-three*)
  136. (lambda (u x y . z)
  137. ((d (lambda (s) (g:apply f (up-structure->list s))))
  138. (list->up-structure (cons* u x y z)))))
  139. ((equal? a *exactly-three*)
  140. (lambda (x y z)
  141. ((d (lambda (s) (g:apply f (up-structure->list s))))
  142. (list->up-structure (list x y z)))))
  143. ((equal? a *one-or-two*)
  144. (lambda* (x #:optional y)
  145. (if (default-object? y)
  146. ((d f) x)
  147. ((d (lambda (s)
  148. (g:apply f (up-structure->list s))))
  149. (list->up-structure (list x y))))))
  150. (else
  151. (lambda args
  152. (cond ((null? args)
  153. (error "No args passed to derivative?")
  154. 0)
  155. ((null? (cdr args)) ; one argument
  156. ((d f) (car args)))
  157. (else
  158. ((d (lambda (s)
  159. (g:apply f (up-structure->list s))))
  160. (list->up-structure args)))))))))
  161. (define %kernel-deriv-dummy-1
  162. (assign-operation 'partial-derivative
  163. deriv:multivariate-derivative
  164. (disjunction function? structure?)
  165. any?))
  166. ;;; In order to implement derivatives with respect to abstract
  167. ;;; quantities we need to create more types -- differential vector,
  168. ;;; differential matrix, etc? Let's attack that later.