; ; 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.