Subversion Repositories programming

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
72 irasnyd 1
;Written By: Ira Snyder (parts from Dr. Soroka)
2
;Due Date:   02-28-2005
3
;Homework #: HW11
4
 
71 irasnyd 5
; POLY.LSP
6
;
7
; add code for (* i2 i3) &c
8
;
9
; on T 050118 at 1730
10
; It reads & prints polynomials.
11
;
12
; on T 050118 at 0830
13
; All new.
14
; Brought over the ARITH code & began altering it to handle polynomials.
15
;
16
 
72 irasnyd 17
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
18
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ASSUMPTIONS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
19
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
20
;;;                                                                          ;;;
21
;;; Since it was not specified, I decided to make POLY- work in same way     ;;;
22
;;; as the lisp function -. (POLY- P1 P2) would be written in infix as       ;;;
23
;;; P1 - P2.                                                                 ;;;
24
;;;                                                                          ;;;
25
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
71 irasnyd 26
 
27
;
28
; Loop -- read:
29
; a polynomial 
30
; or a reference
31
; or an expression involving references.
32
;
33
(defun POLY nil
34
  (setf $HISTORY nil)
35
  (let ((I 0)
36
        (POLY))
37
    (loop
38
      (format t "~%(i~s) " I)
39
      (setf INPUT (read))
40
      (cond
41
        ((member INPUT '(exit halt quit stop)) (return nil))
42
        ((eq INPUT 'history) (SHOW-HISTORY)) 
43
        ((and (REFERENCEP INPUT) (not (VALID-REFERENCE-P INPUT)))
44
                 (format t "Reference out of range: ~s" INPUT)
45
                 )
46
        ((REFERENCEP INPUT)    ; this reference is valid
47
          (let ((OUTPUT (GET-REFERENCE INPUT)))
48
            (format t "(o~s) " I)
49
            (format t "~s~%" OUTPUT)
50
            (setf $HISTORY (append $HISTORY (list OUTPUT)))
51
            (setf I (1+ I))
52
            )
53
          )
54
        ((atom INPUT) (format t "Illegal expression: ~s" INPUT))
55
        ((VALID-OP-REF-REF INPUT) 
56
          (let ((OUTPUT (EXECUTE-EXPRESSION INPUT)))
57
            (format t "(o~s)~%" I)
58
            (WRITE-POLY OUTPUT)
59
            (setf $HISTORY (append $HISTORY (list OUTPUT)))
60
            (setf I (1+ I))
61
            ) ;end let
62
          )
63
        ((not (VALID-IN-EXP INPUT)))
64
        (t (let ((INTERMS (IE2INTERMS INPUT)))
65
             (setf POLY (mapcar #'(lambda (INTERM) (VALID-INTERM nil INTERM))
66
                                INTERMS))
67
             )
68
           (format t "(o~s)~%" I) 
69
           (WRITE-POLY POLY)
70
           (setf $HISTORY (append $HISTORY (list POLY)))
71
           (setf I (1+ I))
72
           )
73
        ) ;end cond
74
    ) ;end loop
75
  ) ;end let
76
) ;end defun
77
 
78
; VALID-OP-REF-REF recognizes forms like (* i2 i3)
79
; where the references are valid.
80
; Appropriate error messages are printed if needed.
81
(defun VALID-OP-REF-REF (EXP)
82
  (cond
83
    ((not (= 3 (length EXP))) nil)
84
    ((not (member (car EXP) '(+ - *))) nil)
85
    ((not (VALID-REFERENCE-P (cadr EXP)))
86
      (format t "Reference out of range: ~s" (cadr EXP))
87
      nil)
88
    ((not (VALID-REFERENCE-P (caddr EXP)))
89
      (format t "Reference out of range: ~s" (caddr EXP))
90
      nil)
91
    (t t)
92
  )
93
)
94
 
95
;
96
; (VALID-REFERENCE-P S) returns T iff S is of the form i8 or o8 and the number
97
;                       specifies a valid $HISTORY entry.
98
;
99
(defun VALID-REFERENCE-P (S)
100
  (and (REFERENCEP S)
101
       (let ((N (parse-integer (subseq (symbol-name S) 1))))
102
         (and (>= N 0) (< N (length $HISTORY)))
103
       )
104
  )
105
)
106
 
107
;
108
; (REFERENCEP S) returns T iff S is of the form i5 or o16 etc.
109
;
110
(defun REFERENCEP (S)
111
  (and (symbolp S)
112
       (or (char= #\I (char (symbol-name S) 0))
113
           (char= #\O (char (symbol-name S) 0)))
114
       (> (length (symbol-name S)) 1)
115
       (DIGIT-STRING-P (subseq (symbol-name S) 1))
116
  )
117
)
118
 
119
;
120
; (VALID-IN-EXP EXP)
121
;
122
; A valid IN-EXP is an append of valid INTERMs.
123
; E.g. (+ 3 - x ^ 2) is an append of (+ 3) and (- x ^ 2).
124
;
125
(defun VALID-IN-EXP (EXP)
126
  (cond
127
    ((atom EXP) (format t "Sorry, but ~s is not legal here.~%" EXP)
128
                nil)
129
    (t (let ((INTERMS (IE2INTERMS EXP)))
130
         (every #'(lambda (INTERM) (VALID-INTERM t INTERM))
131
                INTERMS)
132
       ))
133
  )
134
)
135
 
136
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
137
;;; SEE BELOW FOR IMPLEMENTATION OF WRITE-POLY                               ;;;
138
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
139
 
140
;
141
; (IE2INTERMS EXP) returns a list of the INTERMS in EXP.
142
; For example, (3 - x ^ 2 + 7 x) --> ((3) (-  x ^ 2) (+ 7 x)).
143
; Note:  Some may not be legal!
144
;
145
(defun IE2INTERMS (EXP)
146
  (let ((RESULT nil)
147
        (REST EXP))
148
    (loop
149
      (if (null REST) (return (reverse RESULT)))
150
      (setf RESULT (cons (TAKE-INTERM REST) RESULT))
151
      (setf REST (DROP-INTERM REST))
152
    ) ;end-loop
153
  ) ;end-let
154
)
155
 
156
;
157
; (TAKE-INTERM IN-EXP) returns the first INTERM of IN-EXP
158
;
159
(defun TAKE-INTERM (EXP)
160
  (let ((INTERM (list (car EXP)))
161
        (REST (cdr EXP)))
162
    (loop
163
      (if (null REST) (return (reverse INTERM)))
164
      (if (member (car REST) '(+ -)) (return (reverse INTERM)))
165
      (setf INTERM (cons (car REST) INTERM))
166
      (setf REST (cdr REST))
167
    ) ;end loop
168
  ) ;end let
169
)
170
 
171
;
172
; (DROP-INTERM IN-EXP) returns ALL BUT the first INTERM of IN-EXP
173
;
174
(defun DROP-INTERM (EXP)
175
  (let ((INTERM (list (car EXP)))
176
        (REST (cdr EXP)))
177
    (loop
178
      (if (null REST) (return REST))
179
      (if (member (car REST) '(+ -)) (return REST))
180
      (setf INTERM (cons (car REST) INTERM))
181
      (setf REST (cdr REST))
182
    ) ;end loop
183
  ) ;end let
184
)
185
 
186
;
187
; (VALID-INTERM PFLAG EXP)
188
;
189
; Convert things like (- 2 x ^ 7) into (-2 7) if possible.
190
; If not possible, then return nil.
191
; If PFLAG is T, then error messages are printed.
192
;
193
(defun VALID-INTERM (PFLAG EXP) (VALID-INTERM0 PFLAG EXP EXP))
194
 
195
;
196
; Grab off the sign, if any.
197
;
198
(defun VALID-INTERM0 (PFLAG INTERM L)
199
  (cond
200
    ((atom L) (format PFLAG "Invalid INTERM: ~s" INTERM)
201
              nil)
202
    ((eq '- (car L)) (VALID-INTERM1 PFLAG INTERM -1 (cdr L)))
203
    ((eq '+ (car L)) (VALID-INTERM1 PFLAG INTERM 1 (cdr L)))
204
    (t               (VALID-INTERM1 PFLAG INTERM 1 L))
205
  )
206
)
207
 
208
;
209
; Grab off the coefficient, if any.
210
;
211
(defun VALID-INTERM1 (PFLAG INTERM SIGN L)
212
  (cond
213
    ((null L) (format PFLAG "Invalid INTERM: ~s" INTERM)
214
              nil)
215
    ((eq 'x (car L)) (VALID-INTERM2 PFLAG INTERM SIGN 1 L))
216
    ((numberp (car L)) (VALID-INTERM2 PFLAG INTERM SIGN (car L) (cdr L)))
217
    (t (format PFLAG "Invalid INTERM -- numeric coefficient expected: ")
218
       (format PFLAG "~s" INTERM)
219
       nil)
220
  )
221
)
222
 
223
;
224
; Handle constant terms here.
225
;
226
(defun VALID-INTERM2 (PFLAG INTERM SIGN COEF L)
227
  (cond
228
    ((null L) (list (* SIGN COEF) 0))
229
    ((eq 'x (car L)) (VALID-INTERM3 PFLAG INTERM SIGN COEF (cdr L)))
230
    (t (format PFLAG "Invalid INTERM -- X was expected: ")
231
       (format PFLAG "~s" INTERM)
232
       nil)
233
  )
234
)
235
 
236
;
237
; No exponent exits here:
238
;
239
(defun VALID-INTERM3 (PFLAG INTERM SIGN COEF L)
240
  (cond
241
    ((null L) (list (* SIGN COEF) 1))
242
    ((eq '^ (car L)) (VALID-INTERM4 PFLAG INTERM SIGN COEF (cdr L)))
243
    (t (format PFLAG "Invalid INTERM -- ^ was expected: ")
244
       (format PFLAG "~s" INTERM))
245
  )
246
)
247
 
248
;
249
; Grab the exponent.
250
;
251
(defun VALID-INTERM4 (PFLAG INTERM SIGN COEF L)
252
  (cond
253
    ((null L) (format PFLAG "Invalid INTERM -- exponent missing: ")
254
              (format PFLAG "~s" INTERM))
255
    ((cdr L) (format PFLAG "Invalid INTERM -- extra stuff at end: ")
256
             (format PFLAG "~s" INTERM))
257
    ((not (numberp (car L))) 
258
      (format PFLAG "Invalid INTERM -- exponent must be numeric: ")
259
      (format PFLAG "~s" INTERM))
260
    (t (list (* SIGN COEF) (car L)))
261
  )
262
)
263
 
264
;
265
; (EXECUTE-EXPRESSION EXP) processes things like (* I5 i6).
266
;
267
(defun EXECUTE-EXPRESSION (EXP)
268
  (let ((OP (car EXP))
269
        (ARG1 (GET-REFERENCE (cadr EXP)))
270
        (ARG2 (GET-REFERENCE (caddr EXP))))
271
    (cond
272
      ((eq OP '*) (POLY* ARG1 ARG2))
273
      ((eq OP '+) (POLY+ ARG1 ARG2))
274
      ((eq OP '-) (POLY- ARG1 ARG2))
275
      (t (format t "EXECUTE-EXPRESSION: Illegal operator: ~s" OP))
276
    ) ;end-cond
277
  ) ;end-let
278
)
279
 
280
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
281
;;; The below 3 functions (POLY*, POLY+, and POLY-) were implemented         ;;;
282
;;; on 02-20-2005 by Ira Snyder for HW11                                     ;;;
283
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
284
 
285
;;; This function takes two polynomials represented in PNF,
286
;;; and returns the result of multiplying them together.
287
;;; The two do loops take each sublist of P1 and P2, and call
288
;;; POLY*1 on the two lists.
289
(defun POLY* (P1 P2)
290
  (do ((P1 P1 (cdr P1)) 
291
       (RESULT nil))
292
      ((null P1) RESULT)
293
    (do ((P2 P2 (cdr P2)))
294
        ((null P2) RESULT)
295
      (setf RESULT (cons (POLY*1 (car P2) (car P1)) RESULT))
296
    )
297
  )
298
)
299
 
300
;;; This function takes two pairs of numbers, each representing
301
;;; a coefficient and power of a variable. It returns the multiplication
302
;;; of these two pairs, as a new pair.
303
(defun POLY*1 (PAIR1 PAIR2)
304
  (list (* (car PAIR1) (car PAIR2)) (+ (cadr PAIR1) (cadr PAIR2)))
305
)
306
 
307
;;; This function takes two lists, each in PNF, and returns a new
308
;;; list which is the addition of P1 and P2.
309
(defun POLY+ (P1 P2)
310
  (do ((P1 P1 (cdr P1))
311
       (RESULT P2))
312
      ((null P1) RESULT)
313
    (setf RESULT (INSERT (car P1) RESULT))
314
  )
315
)
316
 
317
;;; This function takes two lists, each in PNF, and returns a new
318
;;; list which is the subtraction of P2 from P1.
319
(defun POLY- (P1 P2)
320
  (do ((P2 P2 (cdr P2))
321
       (RESULT P1))
322
      ((null P2) RESULT)
323
    (setf RESULT (INSERT (list (* -1 (caar P2)) (cadar P2)) RESULT))
324
  )
325
)
326
 
327
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
328
;;; End of things implemented by Ira Snyder for HW11                         ;;;
329
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
330
 
331
;
332
; (GET-REFERENCE REF) looks up things like I8 in $HISTORY.
333
;                     Assume that REF is legal.
334
;
335
(defun GET-REFERENCE (REF)
336
  (let ((N (parse-integer (subseq (symbol-name REF) 1))))
337
    (nth N $HISTORY)
338
  )
339
)
340
 
341
;
342
; (DIGIT-STRING-P string) returns T iff all chars in STRING are digits.
343
;
344
(defun DIGIT-STRING-P (STR)
345
  (let ((I 0))
346
    (loop 
347
      (if (>= I (length STR)) (return t))
348
      (if (not (digit-char-p (char STR I))) (return nil))
349
      (setf I (1+ I))
350
    ) ;end loop
351
  ) ;end let
352
)
353
 
354
(defun SHOW-HISTORY nil
355
  (let ((I 0))
356
    (mapc #'(lambda (ITEM) (format t ">(i~s) ~s~%" I ITEM)
357
                           (setf I (1+ I)))
358
          $HISTORY)
359
  )
360
) 
361
 
362
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
363
;;; Below is code added by Ira Snyder on 02-20-2005                          ;;;
364
;;; This code implements WRITE-POLY, PNF and all supporting                  ;;;
365
;;; functionsfrom HW08                                                       ;;;
366
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
367
 
368
;;; Given a list in unsorted, unreduced Polynomial
369
;;; Normal Form, and returns a list in perfect PNF
370
(defun PNF (L)
371
  (do ((L L (cdr L))
372
       (RET nil))
373
      ((null L) RET)
374
    (setf RET (INSERT (car L) RET))
375
    (setf RET (DEL-ZERO-COEF RET))
376
  )
377
)
378
 
379
;;; Given a pair of numbers (in a list) and a list of pairs
380
;;; this inserts the pair into the list in it's correct place
381
;;; including combining coefficients
382
(defun INSERT (PAIR LIST)
383
  (let ((FPTR (caar LIST))) ;this is needed so we don't change 
384
                            ;the list outside this function
385
    (cond
386
      ((null LIST)                  (cons PAIR LIST))
387
      ((> (cadr PAIR) (cadar LIST)) (cons PAIR LIST))
388
      ((= (cadr PAIR) (cadar LIST)) (progn
389
                                      (setf FPTR (+ (car PAIR) FPTR))
390
                                      (cons (list FPTR (cadar LIST))
391
                                            (cdr LIST))))
392
      (t                            (cons (car LIST) (INSERT PAIR (cdr LIST))))
393
    )
394
  )
395
)
396
 
397
;;; Deletes all of the pairs that have zero coefficients in
398
;;; a PNF list
399
(defun DEL-ZERO-COEF (L)
400
  (cond
401
    ((null L) nil)
402
    ((= 0 (caar L)) (DEL-ZERO-COEF (cdr L)))
403
    (t              (cons (car L) (DEL-ZERO-COEF (cdr L))))
404
  )
405
)
406
 
407
;;; This takes a non-negative integer, and returns a string
408
;;; containing the number of spaces specified by the integer
409
(defun SPACES (N)
410
  (do ((N N (1- N))
411
       (STR (format nil "")))
412
      ((zerop N) STR)
413
    (setf STR (concatenate 'string STR " "))
414
  )
415
)
416
 
417
;;; This checks if nil was passed. If it was, print a blank line, then
418
;;; a "0" line. Else pass the list off to the WRITE-POLY1 function.
419
(defun WRITE-POLY (L)
420
  (cond
421
    ((null L) (format t "~%0~%"))
422
    (t        (WRITE-POLY1 L))
423
  )
424
)
425
 
426
;;; Given a list in Polynomial Normal Form, this will print
427
;;; the human readable form of the list on two lines.
428
;;; Example:
429
;;;   INPUT:  ((1 1) (2 3) (-10 0) (3 2) (2 1))
430
;;;   OUTPUT:      3      2      
431
;;;   OUTPUT: + 2 x  + 3 x  + 3 x - 10
432
(defun WRITE-POLY1 (L)
433
  (do ((L (PNF L) (cdr L))
434
       (EXP  (format nil ""))
435
       (COEF (format nil "")))
436
      ((null L) (format t "~A~%~A~%" EXP COEF))
437
    (setf COEF (concatenate 'string COEF (WRITE-NUM (caar L) (cadar L))))
438
    (MAKE-EQUAL EXP COEF)
439
    (setf EXP  (concatenate 'string EXP  (WRITE-EXP (caar L) (cadar L))))
440
    (MAKE-EQUAL EXP COEF)
441
  )
442
)
443
 
444
;;; Given a coefficient and an exponent, output the correct expression
445
;;; to represent it.
446
;;; Examples:
447
;;; INPUT:  3 4
448
;;; OUTPUT: + 3 x
449
;;;
450
;;; INPUT:  3 0
451
;;; OUTPUT: + 3
452
;;;
453
;;; INPUT:  -3 0
454
;;; OUTPUT: - 3
455
(defun WRITE-NUM (NUM EXP)
456
  (cond
457
    ; don't output an x if we have a zero exponent
458
    ((zerop EXP) (if (plusp NUM) (format nil " + ~A" NUM) 
459
                                 (format nil " - ~A" (abs NUM))))
460
    ((plusp NUM) (format nil " + ~A x" NUM))
461
    (t           (format nil " - ~A x" (abs NUM)))
462
  )
463
)
464
 
465
;;; Given a coefficient and an exponent, output the exponent.
466
;;; NOTE: I chose to have the syntax of WRITE-EXP match the syntax of WRITE-NUM
467
;;;       even though I do not use the parameter NUM in the code. This was for
468
;;;       uniformity reasons.
469
(defun WRITE-EXP (NUM EXP)
470
  (cond
471
    ((zerop EXP) nil)
472
    ((= EXP 1)   nil)
473
    (t           (format nil "~A" EXP))
474
  )
475
)
476
 
477
;;; When called with two strings as arguments, this macro expands to
478
;;; make them the same length, regardless of which is longer.
479
(defmacro MAKE-EQUAL (S1 S2)
480
  `(cond
481
     ((> (length ,S1) (length ,S2)) (let ((DIFF (- (length ,S1) (length ,S2))))
482
                                    (setf ,S2 (concatenate 'string ,S2 (SPACES DIFF)))))
483
     ((< (length ,S1) (length ,S2)) (let ((DIFF (- (length ,S2) (length ,S1))))
484
                                    (setf ,S1 (concatenate 'string ,S1 (SPACES DIFF)))))
485
     (t                             nil)
486
   )
487
)
488