Subversion Repositories programming

Rev

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

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