-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathderiv.lisp
145 lines (136 loc) · 5.41 KB
/
deriv.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
; Differentiate an infix polynomial with terms of the form +cax^n
; where c is an optional integer constant and a is an optional
; variable other than x, and optional exponent n is an integer > 0.
; Example: (3 a x ^ 5 + b x ^ 4 + 2 x ^ 3 + 6 x ^ 2 + 3 x + 7)
; Differentiate with respect to var, for example x.
; The derivative will be in the same infix form.
;
; Assumptions:
; The polynomial is in the "canonical" form as described above.
; There is no error checking of the form. In particular, only
; the variable we're differentiating with respect to (such as x)
; can have an exponent. Any deviation from canonical form may
; cause a runtime exception.
;
; CS 152 Programming Language Paradigms
; Department of Computer Science
; San Jose State University
; Fall 2013
; Instructor: Ron Mak
; Find the derivative of polynomial poly with repect to variable var.
; The polynomial must be in canonical infix form.
; First "terminize" the polynomial.
; Example:
; (terminize '(3 a x ^ 5 + b x ^ 4 + 2 x ^ 3 + 6 x ^ 2 + 3 x + 7))
; ==> ((3 a x ^ 5) (b x ^ 4) (2 x ^ 3) (6 x ^ 2) (3 x) (7)))
; Note that var is a free variable in local procedure deriv-term.
; At run time, deriv-term obtains the value of var from its closure,
; and it is mapped over each sublist in the terminized polynomial.
; The result is a list of sublists, each sublist representing the derivative
; of the corresponding term.
; Example:
; (map deriv-term '((3 a x ^ 5) (b x ^ 4) (2 x ^ 3) (6 x ^ 2) (3 x) (7))))
; ==> ((15 a x ^ 4) (4 b x ^ 3) (6 x ^ 2) (12 x) (3) (0))
; Example:
; (deriv '(3 a x ^ 5 + b x ^ 4 + 2 x ^ 3 + 6 x ^ 2 + 3 x + 7) 'x)
; ==> (15 a x ^ 4 + 4 b x ^ 3 + 6 x ^ 2 + 12 x + 3)
(define deriv
(lambda (poly var)
(let* ((terms (terminize poly)) ; "terminize" the polynomial
(deriv-term ; local procedure deriv-term
(lambda (term)
(cond
((null? term) '())
((not (member? var term)) '(0)) ; deriv = 0
((not (member? '^ term)) (upto var term)) ; deriv = coeff
(else (deriv-term-expo term var)) ; handle exponent
)))
(diff (map deriv-term terms))) ; map deriv-term over the terms
(remove-trailing-plus (polyize diff)) ; finalize the answer
)))
; Differentiate a single term that contains the var
; raised to a power (i.e., there's an exponent).
; If there are two adjacent integer constants in the new
; coefficient, replace them by their product.
; Example: (deriv-term-expo '(3 a x ^ 5) 'x) ==> (15 a x ^ 4)
(define deriv-term-expo
(lambda (term var)
(let* ((coeff (upto var term)) ; get the coefficient
(rev-term (reverse term)) ; reverse so that we can
(expo (car rev-term)) ; get the exponent at the end
(new-expo (sub1 expo)) ; new exponent
(new-coeff (if (number? (car coeff))
(cons (* (car coeff) expo) (cdr coeff)) ; product
(cons expo coeff))))
; The derivative:
(if (= new-expo 1)
(append new-coeff (list var))
(append new-coeff (list var '^ new-expo)))
)))
; Convert an infix polynomial into a list of sublists,
; where each sublist is a term.
; Example: (terminize '(3 a x ^ 5 + b x ^ 4 + 2 x ^ 3 + 6 x ^ 2 + 3 x + 7))
; ==> ((3 a x ^ 5) (b x ^ 4) (2 x ^ 3) (6 x ^ 2) (3 x) (7)))
(define terminize
(lambda (poly)
(cond
((null? poly) '())
(else (cons (upto '+ poly) (terminize (after '+ poly))))
)))
; Convert a list of term sublists to an infix polynomial.
; Do not include any + 0 term.
; There may be an extra + at the end.
; Example: (polyize '((15 a x ^ 4) (4 b x ^ 3) (6 x ^ 2) (12 x) (3) (0)))
; ==> (15 a x ^ 4 + 4 b x ^ 3 + 6 x ^ 2 + 12 x + 3 +)
(define polyize
(lambda (terms)
(cond
((null? terms) '())
((equal? '(0) (car terms)) '())
((null? (cdr terms)) (car terms))
(else (append (car terms) '(+) (polyize (cdr terms))))
)))
; Return the polynomial without any extra + at the end.
; If the polynomial is empty, return (0).
(define remove-trailing-plus
(lambda (poly)
(if (null? poly)
'(0)
(let ((rev-poly (reverse poly)))
(if (equal? '+ (car rev-poly))
(reverse (cdr rev-poly))
(reverse rev-poly))
))))
; Return #t if the given item is a top-level item of the given list.
; Else return #f.
(define member?
(lambda (item lst)
(cond
((null? lst) #f)
((equal? item (car lst)) #t)
(else (member? item (cdr lst)))
)))
; Return a list consisting of the items of the given list
; up to the first occurrence of the given item.
; Used to extract the coefficient of a term.
; Return the original list if the given item isn't in the list.
; Example: (upto 'x '(3 a x ^ 5)) ==> (3 a)
(define upto
(lambda (item lst)
(cond
((null? lst) '())
((equal? item (car lst)) '())
(else (cons (car lst) (upto item (cdr lst))))
)))
; Return a list consisting of the items of the given list
; after the first occurrence of the given item.
; Used to extract the exponent of a term.
; Return the empty list if the given item isn't in the list.
; Example: (after 'x '(3 a x ^ 5)) ==> (^ 5)
(define after
(lambda (item lst)
(cond
((null? lst) '())
((equal? item (car lst)) (cdr lst))
(else (after item (cdr lst)))
)))