derive.lisp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. ;;;; derive.lisp
  2. ;;;;
  3. ;;;; Copyright (c) 2015 Samuel W. Flint <swflint@flintfam.org>
  4. #+quicklisp (ql:quickload :uiop)
  5. (defpackage #:derive
  6. (:use #:cl)
  7. (:export :derive
  8. :csc
  9. :sec
  10. :define-equation-functions
  11. :take-derivative)
  12. #-(or ccl sbcl) (:import-from #:uiop
  13. #:quit))
  14. (in-package #:derive)
  15. ;;; "derive" goes here.
  16. (defun derive (equation)
  17. "derive -- (derive equation)
  18. Derives an equation using the normal rules of differentiation."
  19. (declare (cons equation))
  20. (let ((op (first equation)))
  21. (cond
  22. ((member op '(sin cos tan csc sec cot))
  23. (chain equation))
  24. ((equal op 'expt)
  25. (power (rest equation)))
  26. ((equal op '*)
  27. (mult (rest equation)))
  28. ((equal op '/)
  29. (div (rest equation)))
  30. ((or (equal op '+)
  31. (equal op '-))
  32. (apply #'plus/minus op (rest equation)))
  33. ((numberp op)
  34. 0)
  35. (t
  36. 1))))
  37. (defun plus/minus (op &rest args)
  38. "plus/minus -- (plus/minus op &rest args)
  39. Derive for plus/minus"
  40. (declare (symbol op)
  41. (cons args))
  42. (let ((out (list op)))
  43. (loop for arg in args
  44. do (let ((derivative (derive (if (not (listp arg)) (list arg) arg))))
  45. (if (eq 0 derivative)
  46. nil
  47. (push derivative out))))
  48. (if (equal (list op) out)
  49. nil
  50. (reverse out))))
  51. (defun mult (equation)
  52. "mult -- (mult equation)
  53. Derive multiplication"
  54. (if (= (length equation) 2)
  55. (if (numberp (first equation))
  56. `(* ,(first equation) ,(derive (if (not (listp (second equation))) (list (second equation)) (second equation))))
  57. (if (numberp (second equation))
  58. `(* ,(second equation) ,(derive (if (not (listp (first equation))) (list (first equation)) (first equation))))
  59. `(+ (* ,(first equation) ,(derive (second equation)))
  60. (* ,(second equation) ,(derive (first equation))))))
  61. (mult (list (first equation) (mult (rest equation))))))
  62. (defun div (equation)
  63. "div -- (div equation)
  64. Derive using quotient rule"
  65. (let ((numerator (nth 0 equation))
  66. (denominator (nth 1 equation)))
  67. `(/ (- (* ,numerator ,(derive denominator))
  68. (* ,denominator ,(derive numerator)))
  69. (expt ,denominator 2))))
  70. (defun chain (equation)
  71. "chain -- (chain equation)
  72. Apply the chain rule to the equation"
  73. (declare (cons equation))
  74. (let ((op (first equation))
  75. (arg (second equation)))
  76. (case op
  77. (sin
  78. `(* (cos ,arg) ,(derive arg)))
  79. (cos
  80. `(* (- (sin ,arg)) ,(derive arg)))
  81. (tan
  82. `(* (expt (sec ,arg) 2) ,(derive arg)))
  83. (csc
  84. `(* (- (csc ,arg)) (cot ,arg) ,(derive arg)))
  85. (sec
  86. `(* (sec ,arg) (tan ,arg) ,(derive arg)))
  87. (cot
  88. `(* (- (expt (csc ,arg) 2)) ,(derive arg))))))
  89. (defun power (eq)
  90. "power -- (power rest)
  91. Apply the Power Rule"
  92. (declare (cons eq))
  93. (let ((equation (nth 0 eq))
  94. (power (nth 1 eq)))
  95. (if (listp equation)
  96. `(* ,power (expt ,equation ,(1- power)) ,(derive equation))
  97. `(* ,power (expt ,equation ,(1- power))))))
  98. (defun csc (x)
  99. "csc -- (csc x)
  100. Calculate the cosecant of x"
  101. (/ (sin x)))
  102. (defun sec (x)
  103. "sec -- (sec x)
  104. Calculate the secant of x"
  105. (/ (cos x)))
  106. (defun repl ()
  107. (format t "Welcome to the automatic derivative calculator. Type quit to exit.~&~&> ")
  108. (loop (progn (let ((in (read)))
  109. (cond
  110. ((eq in 'quit)
  111. #-(or ccl sbcl) (quit)
  112. #+sbcl (sb-ext:exit)
  113. #+ccl (ccl:quit))
  114. ((eq in 'trace)
  115. (trace derive plus/minus mult div chain power))
  116. ((eq in 'untrace)
  117. (untrace derive plus/minus mult div chain power))
  118. ((eq in nil))
  119. ((listp in)
  120. (format t "~%~a~%" (derive in)))))
  121. (format t "~&> "))))
  122. #+sbcl (progn
  123. (defun save-exec ()
  124. #+lparallel (lparallel:end-kernel)
  125. (sb-ext:save-lisp-and-die "derive"
  126. :toplevel #'repl
  127. :executable t
  128. :purify t
  129. :save-runtime-options t))
  130. (export 'save-exec))
  131. #+ccl (progn
  132. (defun save-exec ()
  133. #+lparallel (lparallel:end-kernel)
  134. (ccl:save-application "derive"
  135. :toplevel-function #'repl
  136. :prepend-kernel t
  137. :purify t))
  138. (export 'save-exec))
  139. (defmacro define-equation-functions (name variable equation)
  140. (let ((derivative-name
  141. (intern (string-upcase (format nil "d/d~a-~a" variable name))))
  142. (derivative (derive equation)))
  143. `(progn
  144. (defun ,name (,variable)
  145. ,equation)
  146. (defun ,derivative-name (,variable)
  147. ,derivative))))
  148. (defmacro take-derivative (equation)
  149. (let ((derivative (derive equation)))
  150. `',derivative))
  151. ;;; End derive