Download |
;
; This is a small example of symbolic differentiation adapted from the Scheme
; version in _Programming_Lanugages_,_Concepts_and_Constructs_, First
; Edition, by Ravi Sethi.
;
; We will represent the expressions as lisp lists using the usual lisp
; prefix syntax. For instance, (+ x 2) will mean x + 2. And, (d '(+ x 2))
; will yield 2. Note that (+) is legal and means 0, and (*) is legal and
; means 1.
;
; ** Basic parts. **
; In this section we present some simple functions to identify the basic
; parts.
(defun is-constant (x) (numberp x))
(defun is-variable (x) (symbolp x))
(defun is-sum (x) (and (listp x) (equal (car x) '+)))
(defun is-product (x) (and (listp x) (equal (car x) '*)))
; The functions numberp, symbolp and listp, are built-in predicates
; identifying, respectively, numbers, symbols, and lists.
; ** Main derivative function **
; This function takes the derivative of an expression. It actually just
; decides what sort of expression it is and farms the work out to
; specialized functions based on the type of expression.
(defun d (x E)
(cond
((is-constant E) (diff-constant x E))
((is-variable E) (diff-variable x E))
((is-sum E) (diff-sum x E))
((is-product E) (diff-product x E))
(t (error "d: Cannot parse " E))
)
)
; The (error) function enters a break loop.
; ** Trivial derivatives. **
; The derivative of a constant is 0, the derivative of a variable with
; respect to itself is 1, with respect to any other variable is 0.
(defun diff-constant (x E) 0)
(defun diff-variable (x E) (if (equal x E) 1 0) )
; ** Derivation of sums **
; For anyone who recalls calculus, the derivative of a sum is the sum of
; the derivatives of the terms. We use mapcar to go through the list
; and take all the derivatives.
(defun diff-sum (x E)
(cons '+ ; Result is a sum.
(mapcar ; Apply to each term.
(lambda (term) (d x term)) ; Take the derivative of the term.
(cdr E) ; Extract the terms (discard old +)
)
)
)
; ** Derivation of a product **
; This is done in two steps. The function diff-product takes care of the
; simple cases where there are zero or one factor: (*) or (* subE). The
; more complex cases it passes off to diff-product-args. This is actually
; done to simplify diff-product-args so that it can be written knowing
; there are at least two factors.
(defun diff-product (x E)
(let*
(
(arg-list (cdr E)) ; Just the args, ma'am
(num-args (length arg-list)) ; And how may there are.
)
(cond
((= num-args 0) 0) ; (*) is 1, deriv is 0.
((= num-args 1) ; (* M), deriv is deriv of M.
(d x (car arg-list))
)
(t (diff-product-args x arg-list)) ; Real work here.
)
)
)
; Here is where the real work of the product differentiation is done. It
; receives a list of factors (the leading * having been removed).
; It computes using the chain rule, which says the derivative of UV is
; U times the derivative of V plus V times the derivative of U. That
; is: d(UV) = UdV + VdU. Note that if the product has multiple factors,
; U will be the first one, and V will be the product of all the remaining ones.
(defun diff-product-args (x arg-list)
(let*
(
(U (car arg-list)) ; U is the head of the list.
(dU (d x U))
(V (cons '* (cdr arg-list))) ; V is all the rest, so keep *.
(dV (d x V))
(UdV (list '* U dV))
(VdU (list '* V dU))
)
(list '+ UdV VdU)
)
)
; The list function simply returns the list of its arguments.