CS 22

Clab 14: Multiple representations--Complex numbers


I'll say a few words about complex numbers. Then we'll work through some of the material on pp. 169-186 fairly rapidly. http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-17.html#%_sec_2.4
At home, work more thoroughly with the material. Try things out. Ask any questions you have at the beginning of next clab. Do arithmetic on complex numbers in several of the representations.

Here is some code to add and multiply complex numbers given in rectangular form. Also a couple of complex numbers and a definition of pi.

(define (make-from-real-imag x y) (cons x y)) (define (real-part z) (car z)) (define (imag-part z) (cdr z)) (define (add-complex z1 z2) (make-from-real-imag (+ (real-part z1) (real-part z2)) (+ (imag-part z1) (imag-part z2)))) (define (mul-complex2 z1 z2) (make-from-real-imag (- (* (real-part z1) (real-part z2)) (* (imag-part z1) (imag-part z2))) (+ (* (real-part z1) (imag-part z2)) (* (imag-part z1) (real-part z2))))) (define cpx45 (make-from-real-imag 4 4)) (define cpx30 (make-from-real-imag (sqrt 3) 1)) (define cpx60 (make-from-real-imag 2 (* 2 (sqrt 3)))) (define pi (* 2 (asin 1)))

now we'll add more from section 2.4.1

(define (sub-complex z1 z2) (make-from-real-imag (- (real-part z1) (real-part z2)) (- (imag-part z1) (imag-part z2)))) (define (mul-complex z1 z2) (make-from-mag-ang (* (magnitude z1) (magnitude z2)) (+ (angle z1) (angle z2)))) (define (div-complex z1 z2) (make-from-mag-ang (/ (magnitude z1) (magnitude z2)) (- (angle z1) (angle z2)))) add and subtract will work with rectangular form mul and div need polar form so Ben needs conversion functions (define (square x) (* x x)) (define (magnitude z) (sqrt (+ (square (real-part z)) (square (imag-part z))))) (define (angle z) (atan (imag-part z) (real-part z))) (define (make-from-mag-ang r a) (cons (* r (cos a)) (* r (sin a)))) Let's try Bens functions

Don't close Ben's window. But open a new window for Alyssa and put the following in her window.

;; the same implementation independent definitions of ;; add, sub, mult, div (define (add-complex z1 z2) (make-from-real-imag (+ (real-part z1) (real-part z2)) (+ (imag-part z1) (imag-part z2)))) (define (sub-complex z1 z2) (make-from-real-imag (- (real-part z1) (real-part z2)) (- (imag-part z1) (imag-part z2)))) (define (mul-complex z1 z2) (make-from-mag-ang (* (magnitude z1) (magnitude z2)) (+ (angle z1) (angle z2)))) (define (div-complex z1 z2) (make-from-mag-ang (/ (magnitude z1) (magnitude z2)) (- (angle z1) (angle z2)))) ;; add and subtract will work with rectangular form ;; mul and div need polar form so Alyssa also needs conversion ;; functions (define (square x) (* x x)) ;; these functions differ from Ben's functions of same name (define (real-part z) (* (magnitude z) (cos (angle z)))) (define (imag-part z) (* (magnitude z) (sin (angle z)))) (define (magnitude z) (car z)) (define (angle z) (cdr z)) (define (make-from-real-imag x y) (cons (sqrt (+ (square x) (square y))) (atan y x))) (define (make-from-mag-ang r a) (cons r a)) ;; try a couple of Alyssa's functions (define acpx30 (make-from-real-imag 1.7320508075688772 1)) (define acpx45 (make-from-real-imag 4 4)) (define acpx60 (make-from-real-imag 2 3.4641016151377544)) Let's try a couple of Alyssa's functions on numbers in polar form.

Before next clab, try the tagged system on pages 175-179. Use a third drscheme window. Put some numbers in in rectangular form and some in polar form and make sure you get the correct answers using the tagged functions. Also make sure you understand how the tags are being used. You might want to try:

(define tcpx45 (make-from-real-imag 4 4)) (define tcpx60 (make-from-mag-ang 4 1.0471975511965976)) and see if you can get real and imaginary parts, magnitude and angle, and that they multiply and add correctly.
Here is text code from those pages. ;;;SECTION 2.4.2 (define (attach-tag type-tag contents) (cons type-tag contents)) (define (type-tag datum) (if (pair? datum) (car datum) (error "Bad tagged datum -- TYPE-TAG" datum))) (define (contents datum) (if (pair? datum) (cdr datum) (error "Bad tagged datum -- CONTENTS" datum))) (define (rectangular? z) (eq? (type-tag z) 'rectangular)) (define (polar? z) (eq? (type-tag z) 'polar)) ;; Ben (rectangular) (define (real-part-rectangular z) (car z)) (define (imag-part-rectangular z) (cdr z)) (define (magnitude-rectangular z) (sqrt (+ (square (real-part-rectangular z)) (square (imag-part-rectangular z))))) (define (angle-rectangular z) (atan (imag-part-rectangular z) (real-part-rectangular z))) (define (make-from-real-imag-rectangular x y) (attach-tag 'rectangular (cons x y))) (define (make-from-mag-ang-rectangular r a) (attach-tag 'rectangular (cons (* r (cos a)) (* r (sin a))))) ;; Alyssa (polar) (define (real-part-polar z) (* (magnitude-polar z) (cos (angle-polar z)))) (define (imag-part-polar z) (* (magnitude-polar z) (sin (angle-polar z)))) (define (magnitude-polar z) (car z)) (define (angle-polar z) (cdr z)) (define (make-from-real-imag-polar x y) (attach-tag 'polar (cons (sqrt (+ (square x) (square y))) (atan y x)))) (define (make-from-mag-ang-polar r a) (attach-tag 'polar (cons r a))) ;; Generic selectors (define (real-part z) (cond ((rectangular? z) (real-part-rectangular (contents z))) ((polar? z) (real-part-polar (contents z))) (else (error "Unknown type -- REAL-PART" z)))) (define (imag-part z) (cond ((rectangular? z) (imag-part-rectangular (contents z))) ((polar? z) (imag-part-polar (contents z))) (else (error "Unknown type -- IMAG-PART" z)))) (define (magnitude z) (cond ((rectangular? z) (magnitude-rectangular (contents z))) ((polar? z) (magnitude-polar (contents z))) (else (error "Unknown type -- MAGNITUDE" z)))) (define (angle z) (cond ((rectangular? z) (angle-rectangular (contents z))) ((polar? z) (angle-polar (contents z))) (else (error "Unknown type -- ANGLE" z)))) ;; same as before (define (add-complex z1 z2) (make-from-real-imag (+ (real-part z1) (real-part z2)) (+ (imag-part z1) (imag-part z2)))) ;; Constructors for complex numbers (define (make-from-real-imag x y) (make-from-real-imag-rectangular x y)) (define (make-from-mag-ang r a) (make-from-mag-ang-polar r a))

Ben and Alyssa's tagged data handling of complex numbers allows for the two representations that they chose, but it does not generalize easily. Adding new representations requires changing code already written and being alert to name conflicts. A table-driven system can get around these problems.

We will build a table of operations (i.e. functions) whose rows are indexed by the operation name and whose columns are indexed by the representation.

For now assume that

(put r c p) will put the object p into a table at row r and column c and that (get r c) will return whatever object is in the table at row r and column c.
get will return #f if there is nothing in the table at row r, column c.

Let's install Ben's and Alyssa's tagged stuff with their original names in a table-driven system.

;;begin table implementation routines (define (assoc key records) (cond ((null? records) #f) ((equal? key (caar records)) (car records)) (else (assoc key (cdr records))))) (define (make-table) (let ((local-table (list '*table*))) (define (lookup key-1 key-2) (let ((subtable (assoc key-1 (cdr local-table)))) (if subtable (let ((record (assoc key-2 (cdr subtable)))) (if record (cdr record) #f)) #f))) (define (insert! key-1 key-2 value) (let ((subtable (assoc key-1 (cdr local-table)))) (if subtable (let ((record (assoc key-2 (cdr subtable)))) (if record (set-cdr! record value) (set-cdr! subtable (cons (cons key-2 value) (cdr subtable))))) (set-cdr! local-table (cons (list key-1 (cons key-2 value)) (cdr local-table))))) 'ok) (define peek (lambda () (display local-table))) (define (dispatch m) (cond ((eq? m 'lookup-proc) lookup) ((eq? m 'insert-proc!) insert!) ((eq? m 'peek) peek) (else (error "Unknown operation -- TABLE" m)))) dispatch)) (define operation-table (make-table)) (define get (operation-table 'lookup-proc)) (define put (operation-table 'insert-proc!)) (define peek (operation-table 'peek)) ;; end table implementation routines ;;;from SECTION 2.4.2 tag stuff (define (attach-tag type-tag contents) (cons type-tag contents)) (define (type-tag datum) (if (pair? datum) (car datum) (error "Bad tagged datum -- TYPE-TAG" datum))) (define (contents datum) (if (pair? datum) (cdr datum) (error "Bad tagged datum -- CONTENTS" datum))) ;; still need square (define (square x) (* x x)) ;;; this begins the table driven stuff (define (install-rectangular-package) ;; internal procedures (define (real-part z) (car z)) (define (imag-part z) (cdr z)) (define (make-from-real-imag x y) (cons x y)) (define (magnitude z) (sqrt (+ (square (real-part z)) (square (imag-part z))))) (define (angle z) (atan (imag-part z) (real-part z))) (define (make-from-mag-ang r a) (cons (* r (cos a)) (* r (sin a)))) ;; interface to the rest of the system (define (tag x) (attach-tag 'rectangular x)) (put 'real-part '(rectangular) real-part) (put 'imag-part '(rectangular) imag-part) (put 'magnitude '(rectangular) magnitude) (put 'angle '(rectangular) angle) (put 'make-from-real-imag 'rectangular (lambda (x y) (tag (make-from-real-imag x y)))) (put 'make-from-mag-ang 'rectangular (lambda (r a) (tag (make-from-mag-ang r a)))) 'done) (define (install-polar-package) ;; internal procedures (define (magnitude z) (car z)) (define (angle z) (cdr z)) (define (make-from-mag-ang r a) (cons r a)) (define (real-part z) (* (magnitude z) (cos (angle z)))) (define (imag-part z) (* (magnitude z) (sin (angle z)))) (define (make-from-real-imag x y) (cons (sqrt (+ (square x) (square y))) (atan y x))) ;; interface to the rest of the system (define (tag x) (attach-tag 'polar x)) (put 'real-part '(polar) real-part) (put 'imag-part '(polar) imag-part) (put 'magnitude '(polar) magnitude) (put 'angle '(polar) angle) (put 'make-from-real-imag 'polar (lambda (x y) (tag (make-from-real-imag x y)))) (put 'make-from-mag-ang 'polar (lambda (r a) (tag (make-from-mag-ang r a)))) 'done) (define (apply-generic op . args) (let ((type-tags (map type-tag args))) (let ((proc (get op type-tags))) (if proc (apply proc (map contents args)) (error "No method for these types -- APPLY-GENERIC" (list op type-tags)))))) ;; Generic selectors (define (real-part z) (apply-generic 'real-part z)) (define (imag-part z) (apply-generic 'imag-part z)) (define (magnitude z) (apply-generic 'magnitude z)) (define (angle z) (apply-generic 'angle z)) ;; Constructors for complex numbers (define (make-from-real-imag x y) ((get 'make-from-real-imag 'rectangular) x y)) (define (make-from-mag-ang r a) ((get 'make-from-mag-ang 'polar) r a)) ;; got to install em it you want em to work (install-rectangular-package) (install-polar-package) So we try it. >(define new30 (make-from-real-imag 1.7320508075688772 1)) > (define new45 (make-from-mag-ang 5.656854249492381 0.7853981633974483)) > new30 (rectangular 1.7320508075688772 . 1) > new45 (polar 5.656854249492381 . 0.7853981633974483) > (real-part new30) 1.7320508075688772 > (real-part new45) 4.000000000000001 This is looking good so let's do some arithmetic. > (define prod3045 (mul-complex new30 new45)) reference to undefined identifier: mul-complex OOPS. What is the problem? What do we need to do?
Fix this so I can do arithmetic. It should be easy and you should be able to get something like. > (define new30 (make-from-real-imag 1.7320508075688772 1)) > (define new45 (make-from-mag-ang 5.656854249492381 0.7853981633974483)) > (define prod3045 (mul-complex new30 new45)) > prod3045 (polar 11.31370849898476 . 1.3089969389957472) > Save your definitions in a file called tabcpx.scm and fix this at home.