Subversion Repositories programming

Rev

Details | Last modification | View Log | RSS feed

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