derive2.lisp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. ;;;; derive2.lisp
  2. ;;;;
  3. ;;;; Copyright (c) 2015 Samuel W. Flint <swflint@flintfam.org>
  4. (defpackage #:derive2
  5. (:use #:cl)
  6. (:export :derive
  7. :csc
  8. :sec
  9. :define-equation-functions
  10. :take-derivative))
  11. (in-package #:derive2)
  12. ;;; "derive2" goes here.
  13. (defvar *rules* '())
  14. (defun generate-match-expression (on arity &optional (type '=))
  15. (declare (symbol on type)
  16. (integer arity))
  17. (case type
  18. (=
  19. `(and (eq function ',on)
  20. (= arg-count ,arity)))
  21. (>
  22. `(and (eq function ',on)
  23. (> arg-count ,arity)))
  24. (>=
  25. `(and (eq function ',on)
  26. (>= arg-count ,arity)))))
  27. (defmacro def-expansion (name (on arity &optional type) (&rest arguments) &body expansion)
  28. (declare (ignorable name on arity type arguments expansion))
  29. (let ((match-expression (if type
  30. (generate-match-expression on arity type)
  31. (generate-match-expression on arity))))
  32. `(progn
  33. (push (list ',name
  34. (lambda (function &rest arguments &aux (arg-count (length arguments)))
  35. ,match-expression)
  36. (lambda (,@arguments)
  37. ,@expansion))
  38. *rules*)
  39. ',name)))
  40. (defun get-expansion (expression)
  41. (first
  42. (remove-if #'null
  43. (map 'list
  44. #'(lambda (nte)
  45. (let ((test (second nte))
  46. (expander (third nte)))
  47. (if (apply test expression)
  48. expander
  49. nil)))
  50. *rules*))))
  51. (defun derive (function)
  52. (declare (cons function))
  53. (let ((op (first function)))
  54. (cond
  55. ((numberp op)
  56. 0)
  57. ((and (symbolp op)
  58. (= 1 (length function)))
  59. 1)
  60. (t
  61. (let ((expansion-function (get-expansion function)))
  62. (if (functionp expansion-function)
  63. (apply expansion-function (rest function))
  64. (error "Undefined expansion: ~a" op)))))))
  65. (defun csc (x)
  66. "csc -- (csc x)
  67. Calculate the cosecant of x"
  68. (/ (sin x)))
  69. (defun sec (x)
  70. "sec -- (sec x)
  71. Calculate the secant of x"
  72. (/ (cos x)))
  73. (def-expansion mult/2 (* 2) (first second)
  74. (cond
  75. ((numberp first)
  76. `(* ,first ,(derive (if (listp second) second (list second)))))
  77. ((numberp second)
  78. `(* ,second ,(derive (if (listp first) first (list second)))))
  79. (t
  80. `(+ (* ,first ,(derive (if (listp second) second (list second))))
  81. (* ,second ,(derive (if (listp first) first (list first))))))))
  82. (def-expansion mult/3+ (* 3 >=) (first &rest rest)
  83. (derive `(* ,first ,(cons '* rest))))
  84. (def-expansion div/2 (/ 2) (numerator denominator)
  85. `(/ (- (* ,numerator ,(derive denominator))
  86. (* ,denominator ,(derive numerator)))
  87. (expt ,denominator 2)))
  88. (def-expansion plus/2+ (+ 2 >=) (&rest clauses)
  89. `(+ ,@(map 'list #'(lambda (clause)
  90. (if (listp clause)
  91. (derive clause)
  92. (derive (list clause))))
  93. clauses)))
  94. (def-expansion minus/2+ (- 2 >=) (&rest clauses)
  95. `(- ,@(map 'list #'(lambda (clause)
  96. (if (listp clause)
  97. (derive clause)
  98. (derive (list clause))))
  99. clauses)))
  100. (def-expansion exp/1 (exp 1) (expression)
  101. (if (listp expression)
  102. `(* (expt ,expression) ,(derive expression))
  103. (if (numberp expression)
  104. 0
  105. `(expt ,expression))))
  106. (def-expansion expt/2 (expt 2) (base exponent)
  107. (if (listp base)
  108. `(* ,exponent (expt ,base (1- ,exponent)) ,(derive base))
  109. `(* ,exponent (expt ,base (1- ,exponent)))))
  110. (def-expansion log/1 (log 1) (expression)
  111. `(/ ,(derive (if (listp expression) expression (list expression))) ,expression))
  112. (def-expansion log/2 (log 2) (number base)
  113. (declare (ignorable number base))
  114. `(/ (derive (cons 'log number)) (log ,base)))
  115. (def-expansion sin/1 (sin 1) (arg)
  116. `(* (cos ,arg) ,(derive arg)))
  117. (def-expansion cos/1 (cos 1) (arg)
  118. `(* (- (sin ,arg)) ,(derive arg)))
  119. (def-expansion tan/1 (tan 1) (arg)
  120. `(* (expt (sec ,arg) 2) ,(derive arg)))
  121. (def-expansion csc/1 (csc 1) (arg)
  122. `(* (- (csc ,arg)) (cot ,arg) ,(derive arg)))
  123. (def-expansion sec/1 (sec 1) (arg)
  124. `(* (sec ,arg) (tan ,arg) ,(derive arg)))
  125. (def-expansion cot/1 (cot 1) (arg)
  126. `(* (- (expt (csc ,arg) 2)) ,(derive arg)))
  127. (defmacro define-equation-functions (name variable equation)
  128. (let ((derivative-name
  129. (intern
  130. (string-upcase
  131. (format nil "d/d~a-~a" variable name))))
  132. (derivative (derive equation)))
  133. `(progn
  134. (defun ,name (,variable)
  135. ,equation)
  136. (defun ,derivative-name (,variable)
  137. ,derivative))))
  138. (defmacro take-derivative (equation)
  139. (let ((derivative (derive equation)))
  140. `',derivative))
  141. ;;; End derive2